June 17, 2026
Search gets a format models can actually cite
Search results were rebuilt into delimited, ranked, indexed records the model can parse and cite, while a months-long docstring cleanup finally closed out.
Two threads closed today, and they’re both about the same thing: making Chalie’s tools speak a language the model can actually trust.
The bigger one is search. Search results used to come back as minified JSON — technically parseable, practically hostile to a model trying to reason over ten results and decide which one to cite. I replaced that with a delimited, indexed record format: <result index="…" score="…" date="…"> blocks, boundary-defanged so nothing inside a result’s content can forge a fake delimiter and confuse the model about where one result ends and the next begins. A new renderer owns this end to end, with a clean empty-result sentinel and full, untruncated summaries instead of clipped fragments. Ranking got real too — results are now scored by actual embedding-based cosine similarity instead of heuristic ordering, sorted best-first, merged across sources, and capped at a global top five. If ranking fails for any reason, it fails open rather than blocking the response. On top of that, a hybrid enrichment step now runs concurrently for any result that comes back with a blank summary — fetching and summarizing the page content directly, SSRF-guarded, after the top-five cut so it never does wasted work. The old forced-provider and result-limit parameters are gone; search always auto-routes and always returns its best five. I also stripped out the rich-media and image-search machinery wholesale — card rendering, image candidate lookups, thumbnail extraction — because it had drifted out of step with how the model actually consumes results and was adding surface area for no real benefit.
The second thread is the two delegate tools that sit in front of the raw web tools — web_search and web_browse. They’d developed a subtle naming collision: web_browse calls its task parameter “goal,” web_search calls the same concept “query,” and a model fluent in one kept reaching for the other’s name. Rather than hand-roll a fix inside the tool, I routed it through the same synonym-healing layer every other tool parameter goes through — a goal→query mapping scoped strictly to web_browse, so the fourteen other tools that already own “query” as their canonical name are untouched. Each tool now also reads only its own parameter through a single shared accessor, closing off a cross-tool extraction helper that had no business existing. And the two tools’ descriptions now say plainly what they’re for: web_search looks things up, web_browse acts on a specific site with full browser control. Small fix, but it’s exactly the kind of ambiguity that quietly costs you tool-call accuracy at scale, and it’s now backed by tests proving the heal fires only where it should.
The other thing that wrapped today, after weeks of steady batches, was a full pass over the codebase’s docstrings — trimming restated signatures and boilerplate down to the parts that actually carry information: non-obvious behavior, side effects, real constraints. Every one of those edits was verified safe against the code itself before it landed, batch by batch, all the way through to the last file. It’s not a feature users will ever see directly, but a codebase that reads clearly is one I can move through faster on everything else — including days like today.
Search was the loudest deliverable, but the real throughline is consistency: results the model can parse without ambiguity, tool parameters that don’t silently collide, and a codebase that says what it means. That’s the boring infrastructure that makes the flashier stuff — memory, delegation, autonomous tool chains — actually reliable in practice. Next up: tightening how tools get discovered and scoped in the first place, so the surface a model sees stays as unambiguous as the results it gets back.
-
New delimited
<result>record format (index/score/date) replaces minified JSON, with boundary-defanging so content can’t forge a delimiter -
Real embedding-based relevance ranking replaces heuristic ordering — best-first, global top-five, fails open
-
Concurrent enrichment step fetches and summarizes blank-summary results post-ranking, SSRF-guarded
-
Rich-media and image-search paths removed wholesale — cards, candidate lookups, and image extraction all deleted
-
web_search/web_browseparameter collision fixed via the shared synonym healer, scoped narrowly, with clearer tool descriptions -
Codebase-wide docstring cleanup completed, verified safe file by file throughout