Skip to content

ai: discover tools in deterministic order - #4902

Merged
asim merged 2 commits into
masterfrom
claude/stable-tool-order
Aug 30, 2026
Merged

ai: discover tools in deterministic order#4902
asim merged 2 commits into
masterfrom
claude/stable-tool-order

Conversation

@asim

@asim asim commented Aug 30, 2026

Copy link
Copy Markdown
Member

Why

Follow-up to #4901 (Anthropic prompt caching), and the answer to "what's the Gemini equivalent."

Investigating Gemini caching turned up a bug that undermines both: Tools.Discover inherits the registry's iteration order, and the memory registry ranges over a map — so the tool list is shuffled on every discovery. Provider prompt caching (Anthropic cache_control, Gemini implicit caching) keys on a byte-identical request prefix, and the tool catalogue is the bulk of that prefix. A shuffled catalogue means a cache write on every turn instead of a hit — paying the write premium repeatedly while never caching.

Change

Sort discovered tools by name in Tools.Discover (the free DiscoverTools delegates to it). Custom tools added via AgentTool keep their insertion order after the discovered set. Go's encoding/json already sorts map keys, so with the slice order fixed the serialized prefix is fully deterministic.

New test registers five services and asserts the order is sorted and survives repeated discovery across map-iteration shuffles.

On Gemini specifically

No provider code needed: implicit caching is on by default for Gemini 2.5+ models (go-micro's default is gemini-2.5-flash) with ~90% off cached prefix tokens — it just requires the stable prefix this PR provides. Explicit cachedContents caching is a stateful resource with TTL + storage billing; enabling it silently could raise costs for idle agents, so it's deliberately not added. If wanted later, it should be an explicit opt-in.

Verification

  • go test ./ai/ (new determinism test), ./agent/, ./cmd/micro/, mock conformance 6/6 — green; gofmt/vet clean.

🤖 Generated with Claude Code


Generated by Claude Code

Tools.Discover inherited the registry iteration order, and the memory
registry (and mDNS in practice) iterates a map — so the tool list was
shuffled on every discovery. That silently defeats provider prompt
caching: Anthropic cache_control and Gemini implicit caching both key
on a byte-identical request prefix, and the tool catalogue is the bulk
of that prefix. A shuffled catalogue is a cache write on every turn
instead of a hit.

Sort discovered tools by name. Custom tools added via AgentTool keep
their insertion order after the discovered set. A test registers five
services and asserts the order is sorted and survives repeated
discovery across map-iteration shuffles.
Copilot AI lite review requested due to automatic review settings August 30, 2026 08:01
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T08:02:35.704524Z 4398f9f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4398f9f401

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ai/tools.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request makes tool discovery deterministic by sorting the discovered tool list by name, preventing registry map-iteration randomness from shuffling tools between calls. This is important for provider-side prompt caching (e.g., Anthropic prefix caching and Gemini implicit caching), which depends on a byte-identical request prefix and is heavily influenced by the serialized tools catalogue.

Changes:

  • Sort Tools.Discover() results by tool name to ensure a stable ordering across runs.
  • Add a unit test that registers multiple services and asserts the discovered tool list is sorted and remains identical across repeated discovery calls.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ai/tools.go Sorts discovered tools by name to ensure deterministic tool ordering.
ai/tools_test.go Adds a regression test asserting tool discovery order is sorted and stable across repeated calls.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Review feedback: ListServices returns one entry per registered version
of a service, so Discover resolved each name once per version and
duplicated its tools — and GetService returns versions in map order, so
full[0] chose a different version (and therefore different endpoint
schemas and descriptions) on different discoveries, churning the
serialized catalogue even with the names sorted.

Dedupe service names, sort the resolved versions and take the highest
so the same version wins every time, and make the final sort stable
with OriginalName as tiebreak. The determinism test now registers two
versions of one service with different endpoints and asserts exactly
one tool set, from the highest version, on every round.
@asim
asim merged commit 7f9619d into master Aug 30, 2026
10 of 12 checks passed
asim added a commit that referenced this pull request Aug 30, 2026
…y fixes (#4903)

* docs(changelog): record the provider tool-loop, caching, and discovery fixes

Add [Unreleased] entries for the three merged provider fixes: the
cross-provider tool-execution loop (#4900), Anthropic prompt caching
with the WithoutCache opt-out (#4901), and deterministic tool discovery
(#4902) — so the next release rolls them into its section.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants