feat(runtime): provider-native Tool Search discovery policy + lowering contract (#1382 slice 1) - #1394
feat(runtime): provider-native Tool Search discovery policy + lowering contract (#1382 slice 1)#1394sunheyi6 wants to merge 6 commits into
Conversation
Astro-Han
left a comment
There was a problem hiding this comment.
Two P2 issues remain in addition to the inline P1:
- [P2]
resolveProviderToolSearchCapabilityacceptsmodelIdbut ignores it atpackages/runtime/src/tool-discovery.ts:142. Theopenaiadapter also serves Chat Completions models such asgpt-4o, while native tool search requires the Responses API on GPT-5.4 or later. Older Anthropic models have the same problem. Once this contract is wired, those models will select the native path instead of the requiredload_toolsfallback. Capability resolution needs to include the actual model and wire support, with unsupported-model tests. - [P2]
lowerToolsForProviderdiscardsnamespaceDescriptionatpackages/runtime/src/tool-discovery.ts:264. The OpenAI SDK expectsproviderOptions.openai.namespaceto contain bothnameanddescription, and groups tools using that pair. The lowering result carries only the namespace name, so the adapter cannot construct the promised namespace payload. Preserve the description and test the complete provider option shape.
The inline P1 prevents the native lowering contract from working. Please revise before merging or wiring this contract.
Address all three review issues from Astro-Han on PR apache#1394: [P1] Keep deferred tools in activeTools. AI SDK 7 treats activeTools as an allowlist: any tool omitted is stripped from the tools dict entirely, so the provider adapter never receives deferred schemas or their deferLoading flags. Fix: keep deferred entries in activeTools (unless neverAdvertise) and rely on the provider's deferLoading option to control initial visibility. Update the LoweredProviderToolPayload doc + the unit test that locked in the broken shape. [P2] resolveProviderToolSearchCapability now gates on modelId. Previously the function accepted modelId but ignored it, returning 'anthropic' / 'openai' for all models of that adapter kind. This would route models without native Tool Search (e.g. gpt-4o Chat Completions, older Claude 3.x) onto the native path, causing silent tool loss. Fix: add supportsAnthropicToolSearch (Opus 4.5+ / Sonnet 4.5+) and supportsOpenaiToolSearch (GPT-5.4+ Responses API) model-id checks. Unsupported models fall back to 'none' (the deterministic load_tools economy). Add tests for supported and unsupported models on both providers. [P2] Preserve namespaceDescription in LoweredToolEntry. The OpenAI SDK expects providerOptions.openai.namespace to carry both name and description for namespace grouping. The lowering result previously carried only the namespace name, so the adapter could not construct the full payload. Fix: add namespaceDescription to LoweredToolEntry and populate it during lowering. Add a test asserting the complete provider option shape. Tests: 17 pass (14 original updated + 3 new). biome lint/format clean. Refs apache#1382
Astro-Han
left a comment
There was a problem hiding this comment.
The earlier activeTools and namespace issues are fixed. I still found two P1 issues, left inline, plus two lower-priority gaps:
[P2] supportsAnthropicToolSearch only recognizes Opus and Sonnet. Anthropic's current compatibility table also includes claude-haiku-4-5 and claude-fable-5, and both models already exist in this repository's catalog. They currently resolve to none, so supported models never use this path. Please derive this from a declared capability table and cover the supported IDs instead of relying on the current family regex.
[P2] buildToolDiscoveryPolicy says the first surface claim wins, but each later surface overwrites an existing deferred entry. Putting the same bound tool in surfaces A and B produces B, unlike ToolAvailabilityRuntime, which skips an already claimed tool. Please either reject overlapping surface membership as a catalog invariant or preserve the first deferred claim, with a regression test.
The 17 tests pass, but they only verify the intermediate objects returned by this module. They do not exercise the existing availability plan, a real resolved provider/wire, or either SDK request serializer. Provider-boundary request tests can land with the wiring slice, but the contract-level P1s need to be fixed first.
Because the inline findings affect fallback correctness and capability selection, I am leaving comments rather than approving.
Anthropic compatibility reference:
https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool
|
Hi — this PR conflicts with current I tested a rebase onto current
These are real source conflicts, so they need your judgement rather than a mechanical rebase — please rebase onto current Thanks for the contribution — happy to help if any conflict is unclear. AI-assisted maintenance note, not a review. It does not count as the required human review under |
…ering contract (apache#1382 slice 1) First increment of apache#1382: establish a Maka-owned tool discovery policy on the catalog plus a provider-native lowering contract that the ModelAdapter (apache#1381 seam) lowers to Anthropic / OpenAI native Tool Search, with a deterministic `load_tools` fallback for unsupported models. Add packages/runtime/src/tool-discovery.ts as a pure, provider-package-free module owning: - `ToolDiscovery` policy (`direct` | `deferred` + namespace), extending the catalog model rather than duplicating it; - `buildToolDiscoveryPolicy`, deriving policy from product tools + deferred catalog surfaces + MCP tools grouped per server (MCP tools default deferred — the exact pain point apache#1382 targets: dozens/hundreds of MCP schemas sent every request even when the model needs one tool); - `resolveProviderToolSearchCapability` (anthropic / openai / none by adapter kind); - `lowerToolsForProvider`, the lowering contract: native modes mark deferred tools with `deferLoading` (OpenAI also carries `namespace`), exclude them from the initial `activeTools`, and add a `tool_search` descriptor kept active; `none` is an identity no-op so today's full-surface behavior and the existing `load_tools` economy are unchanged. This is the contract only, not the live `streamText` wiring. Per the RFC: - Tool Search changes visibility, not authorization; loaded tools still cross `ToolRuntime`. - One authoritative catalog; a search result only selects catalog entries. - Unsupported models keep the current deterministic behavior (no silent tool loss). - An unclassified tool defaults to `direct` (never silently hidden). Rebased onto current main: the apache#1381 seam commit was dropped (merged upstream, evolved); the runtime barrel `index.ts` was retired upstream (apache#2742), so the contract is exposed via a `./tool-discovery` subpath export in package.json.
Address all three review issues from Astro-Han on PR apache#1394: [P1] Keep deferred tools in activeTools. AI SDK 7 treats activeTools as an allowlist: any tool omitted is stripped from the tools dict entirely, so the provider adapter never receives deferred schemas or their deferLoading flags. Fix: keep deferred entries in activeTools (unless neverAdvertise) and rely on the provider's deferLoading option to control initial visibility. Update the LoweredProviderToolPayload doc + the unit test that locked in the broken shape. [P2] resolveProviderToolSearchCapability now gates on modelId. Previously the function accepted modelId but ignored it, returning 'anthropic' / 'openai' for all models of that adapter kind. This would route models without native Tool Search (e.g. gpt-4o Chat Completions, older Claude 3.x) onto the native path, causing silent tool loss. Fix: add supportsAnthropicToolSearch (Opus 4.5+ / Sonnet 4.5+) and supportsOpenaiToolSearch (GPT-5.4+ Responses API) model-id checks. Unsupported models fall back to 'none' (the deterministic load_tools economy). Add tests for supported and unsupported models on both providers. [P2] Preserve namespaceDescription in LoweredToolEntry. The OpenAI SDK expects providerOptions.openai.namespace to carry both name and description for namespace grouping. The lowering result previously carried only the namespace name, so the adapter could not construct the full payload. Fix: add namespaceDescription to LoweredToolEntry and populate it during lowering. Add a test asserting the complete provider option shape. Tests: 17 pass (14 original updated + 3 new). biome lint/format clean. Refs apache#1382
100a5cb to
5fe86c5
Compare
|
@Astro-Han I would like to confirm the intended scope before expanding this PR further. While reviewing the provider-native Tool Search contract, I found an important distinction:
To literally avoid transmitting all MCP tool definitions on every request, the likely follow-up is a provider-independent local discovery path:
This is a different optimization from provider-native Tool Search: it reduces request bytes as well as model-visible schema volume, while native deferral primarily reduces model-visible context. Would you prefer this local MCP discovery / request-payload reduction work to be implemented as a separate follow-up PR under #1382, keeping #1394 as the provider-native contract slice? Or should part of that behavior be included in this PR before it is reviewed? 中文@Astro-Han 想在继续扩大这个 PR 的范围之前确认一下方向。 这里有一个重要区别:
如果要真正避免每次传输全部 MCP 工具定义,后续可能需要实现与 Provider 无关的本地发现流程:
这个方案与 Provider 原生 Tool Search 是两种不同的优化:本地发现同时减少请求字节和模型可见 schema;原生延迟加载主要减少模型可见上下文。 请问这部分“本地 MCP 工具发现 / 减少请求体”的工作,是否应该在 #1382 下单独新建一个后续 PR,让 #1394 继续只负责 Provider 原生契约?还是希望在正式 review #1394 之前,把其中一部分实现也放进当前 PR? |
|
Closing this PR as superseded by the provider-independent design agreed in Discussion #3621 and implemented by merged PR #3765. The project now has one Maka-owned, turn-scoped Thank you for the review and design feedback. 中文关闭此 PR,因为 Discussion #3621 已经达成了新的 Provider 无关方案,并由已合并的 PR #3765 完成实现。 项目现在采用一个由 Maka 管理、仅在当前 turn 生效的 感谢大家的 review 和设计反馈。 |
What
First slice of #1382 (RFC: Provider-native Tool Search for large tool catalogs). Establishes a Maka-owned tool discovery policy on the catalog plus a provider-native lowering contract that the
ModelAdapterseam (#1381 / #1390) lowers to Anthropic / OpenAI native Tool Search, with a deterministicload_toolsfallback for unsupported models.This is the contract only, not the live
streamTextwiring — mirrors how #1381 was sliced (establish the seam first, wire behavior in follow-ups).Why
A session connected to several MCP servers sends dozens/hundreds of tool schemas on every provider request even when the model needs one tool. Both Anthropic and OpenAI now ship native deferred loading + Tool Search. #1382 says: reuse the protocol capability rather than build a generic search service first. This slice lands the Maka-owned policy + lowering contract that later slices consume.
Changes
packages/runtime/src/tool-discovery.ts(new, pure, provider-package-free):ToolDiscoverypolicy (direct|deferred+ namespace), extending the catalog model rather than duplicating it.buildToolDiscoveryPolicy— derives policy from product tools + deferred catalog surfaces + MCP tools grouped per server (MCP tools default deferred — the exact pain point).resolveProviderToolSearchCapability(anthropic/openai/noneby adapter kind).lowerToolsForProvider— the lowering contract: native modes mark deferred tools withdeferLoading(OpenAI also carriesnamespace), exclude them from the initialactiveTools, and add atool_searchdescriptor kept active;noneis an identity no-op so today's full-surface behavior and the existingload_toolseconomy are unchanged.packages/runtime/src/__tests__/tool-discovery.test.ts(new) — 14 tests.packages/runtime/package.json— expose the contract via the./tool-discoverysubpath export (the runtime barrelindex.tswas retired upstream in refactor: remove duplicate runtime architecture #2742).Safety / correctness (per the RFC)
ToolRuntime.direct(never silently hidden).Verification
biome lint/formatclean.Stacked
Rebased onto current
main(c78f850). The #1381 seam is already merged upstream and has evolved there, so this diff contains only this slice — thefeat(runtime): add provider-native Tool Search discovery policy + lowering contractcommit plus its review fixes. History is linear; no merge commits.Out of scope (follow-up slices)
lowerToolsForProviderinto the backend tool-assembly point; expandNativeSearchToolDescriptorinto@ai-sdk/anthropic.toolSearchBm25_20251119/@ai-sdk/openai.toolSearch.load_tools-drivenactiveNamesguard.tool-search call / output / tool_referenceitems for stateless continuation / process restart.Refs #1382