Conversation
🦋 Changeset detectedLatest commit: efc8815 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds a new tool routing subsystem to VoltAgent: router tools, embedding-based router strategy, pool/expose controls, resolver mode, and per-call/global routing config. Enables provider-qualified embedding model strings via the model provider registry, updates Memory to accept string/config embedding specs, and includes examples and documentation. Changes
Sequence Diagram(s)sequenceDiagram
participant Agent
participant ToolRouter as ToolRouter (Embedding)
participant Embedding as EmbeddingAdapter
participant Candidates as ToolCandidates
participant Provider as ProviderTools
Agent->>ToolRouter: execute({ query })
activate ToolRouter
ToolRouter->>Embedding: embed(query)
Embedding->>Embedding: resolve model if provider string
Embedding-->>ToolRouter: queryEmbedding
ToolRouter->>Candidates: embedBatch(toolTexts)
Candidates->>Embedding: embedBatch(toolTexts)
Embedding-->>Candidates: toolEmbeddings (cacheable)
ToolRouter->>ToolRouter: score & select topK
ToolRouter-->>Agent: selections
deactivate ToolRouter
Agent->>Provider: resolve args & execute selected tool(s)
Provider-->>Agent: results
sequenceDiagram
participant VoltAgent
participant Registry as AgentRegistry
participant AgentA as Agent
participant AgentB as Subagent
VoltAgent->>Registry: setGlobalToolRouting(config)
Registry-->>VoltAgent: ack
VoltAgent->>AgentA: register(agent)
AgentA->>AgentA: __setDefaultToolRouting(global)
AgentA->>AgentA: applyToolRoutingConfig()
AgentA->>AgentB: addSubAgent(def)
AgentB->>AgentB: inherit toolRouting & init
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This comment has been minimized.
This comment has been minimized.
Deploying voltagent with
|
| Latest commit: |
efc8815
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c1edbff6.voltagent.pages.dev |
| Branch Preview URL: | https://feat-tool-routing.voltagent.pages.dev |
There was a problem hiding this comment.
3 issues found across 66 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/core/src/agent/agent.ts">
<violation number="1" location="packages/core/src/agent/agent.ts:4602">
P2: `toolRouting: false` should disable router tools for a call, but the current fallback returns all static tools (including routers). This means per-call routing disablement still exposes router tools to the model.</violation>
<violation number="2" location="packages/core/src/agent/agent.ts:5114">
P1: Provider tools can execute before approval is enforced. `runInternalGenerateText` triggers the tool call, but `ensureToolApproval` runs only after the tool has already executed, so tools requiring approval may still run and produce side effects. Approval needs to be enforced before invoking the provider tool.</violation>
<violation number="3" location="packages/core/src/agent/agent.ts:5159">
P2: Provider tools that require approval throw and abort the entire tool-router execution instead of returning a per-tool error result. This makes one denied provider tool fail the full router request.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/core/src/agent/agent.ts">
<violation number="1" location="packages/core/src/agent/agent.ts:5256">
P1: Tool approval can be bypassed: approved args are only injected as a prompt instruction, but the actual toolCall.input is never revalidated. A model that ignores the instruction can execute the tool with unapproved arguments. Re-run ensureToolApproval on toolCall.input (or verify it matches approvedArgs) before executing/hooks.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| [tool.name]: tool, | ||
| }; | ||
|
|
||
| const approvedArgsInstruction = approvedArgs |
There was a problem hiding this comment.
P1: Tool approval can be bypassed: approved args are only injected as a prompt instruction, but the actual toolCall.input is never revalidated. A model that ignores the instruction can execute the tool with unapproved arguments. Re-run ensureToolApproval on toolCall.input (or verify it matches approvedArgs) before executing/hooks.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/agent/agent.ts, line 5256:
<comment>Tool approval can be bypassed: approved args are only injected as a prompt instruction, but the actual toolCall.input is never revalidated. A model that ignores the instruction can execute the tool with unapproved arguments. Re-run ensureToolApproval on toolCall.input (or verify it matches approvedArgs) before executing/hooks.</comment>
<file context>
@@ -5159,25 +5216,58 @@ export class Agent {
[tool.name]: tool,
};
+ const approvedArgsInstruction = approvedArgs
+ ? `Use these tool arguments: ${safeStringify(approvedArgs)}`
+ : "";
</file context>
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
packages/voltagent-memory/CHANGELOG.md (1)
231-241: Don't modify historical changelog entries; document API changes in a new version entry.The embedding configuration in this example (version 0.1.1, released in PR
#641) is being updated to show the new string-based API (embedding: "openai/text-embedding-3-small"), but this API pattern is introduced in the current PR#980, not in v0.1.1.Changelogs should be append-only and historically accurate. Retroactively updating old version examples creates confusion:
- Users who installed v0.1.1 would have used
AiSdkEmbeddingAdapter(openai.embedding("text-embedding-3-small")), not the string format- Developers checking historical releases won't see the actual API that was available then
- Migration guidance is unclear - when exactly did this API change?
Instead, document this embedding model string support as a new feature or migration note in a new changelog entry for the current version (likely 1.0.4 or 2.1.0 depending on semantic versioning strategy). The new entry should:
- Explain the new string-based embedding model format
- Show both old and new patterns for migration
- Indicate whether the old
AiSdkEmbeddingAdapterpattern is still supported or deprecated📝 Recommended changelog structure
Add a new version entry at the top of the changelog:
# `@voltagent/voltagent-memory` +## 1.0.4 (or next version) + +### Patch Changes + +- [`#980`](https://github.com/VoltAgent/voltagent/pull/980) feat: support provider-qualified embedding model strings + + Memory now accepts embedding models as plain strings in addition to adapter instances: + + ```typescript + // New: provider-qualified model string (recommended) + const memory = new Memory({ + storage: new ManagedMemoryAdapter({ databaseName: "production-memory" }), + embedding: "openai/text-embedding-3-small", + }); + + // Still supported: adapter instance + const memory = new Memory({ + storage: new ManagedMemoryAdapter({ databaseName: "production-memory" }), + embedding: new AiSdkEmbeddingAdapter(openai.embedding("text-embedding-3-small")), + }); + ``` + ## 1.0.3And revert lines 231-241 to show the original v0.1.1 API (with AiSdkEmbeddingAdapter).
examples/with-lancedb/src/retriever/index.ts (1)
40-46: UseAiSdkEmbeddingAdapterfrom@voltagent/coreor resolve the string model identifier viaModelProviderRegistrybefore passing toembed().The
embedfunction from theaipackage expects anEmbeddingModelobject, not a string. Passing"openai/text-embedding-3-small"directly will cause a runtime error. The codebase'sAiSdkEmbeddingAdapterdemonstrates the correct pattern: string identifiers with provider prefixes (e.g.,openai/...) must be resolved viaModelProviderRegistry.getInstance().resolveEmbeddingModel()first, then passed toembed(). Either refactorgetEmbedding()to use the adapter, or resolve the model string before theembed()call.website/docs/getting-started/migration-guide.md (1)
331-331: Fix double slash in documentation link.There's a typo in the link path with a double slash:
../observability//developer-console.md📝 Proposed fix
-[Learn more](../observability//developer-console.md) +[Learn more](../observability/developer-console.md)packages/core/src/agent/agent.ts (1)
4801-4815: Remove the duplicatedtool.hooks.onEndcall on the error path.Line 4809 repeats the exact hook invocation from Line 4801, which can double side-effects/logging when a tool fails.
🩹 Proposed fix
- await tool.hooks?.onEnd?.({ - tool, - args, - output: undefined, - error: voltAgentError, - options: executionOptions, - }); - - await tool.hooks?.onEnd?.({ - tool, - args, - output: undefined, - error: voltAgentError, - options: executionOptions, - }); + await tool.hooks?.onEnd?.({ + tool, + args, + output: undefined, + error: voltAgentError, + options: executionOptions, + });
🤖 Fix all issues with AI agents
In `@packages/core/src/agent/agent.ts`:
- Around line 5763-5767: The onToolEnd handler currently always returns
undefined, discarding any output override from hooks; change it to await both
options.hooks?.onToolEnd and this.hooks.onToolEnd, capture their return values
(e.g., resOptions and resThis), and return the appropriate non-undefined result
so overrides propagate—prefer the later hook's return (this.hooks.onToolEnd) if
it returns a value, otherwise fall back to the options.hooks.onToolEnd result;
update the function around onToolEnd to return that captured value instead of
always returning undefined.
In `@packages/core/src/memory/adapters/embedding/ai-sdk.spec.ts`:
- Around line 198-213: Replace the ad-hoc resolveSpy.mockRestore() at the end of
the test with a proper per-test cleanup by adding an afterEach hook that calls
vi.restoreAllMocks(), so the spy on
ModelProviderRegistry.getInstance().resolveEmbeddingModel (resolveSpy) is always
restored even if the test fails; locate the test referencing
ModelProviderRegistry, resolveEmbeddingModel, resolveSpy and
AiSdkEmbeddingAdapter and add the afterEach(() => vi.restoreAllMocks()) hook (or
enable restoreMocks in Vitest config) to ensure no spy leakage between tests.
In `@packages/core/src/memory/adapters/embedding/ai-sdk.ts`:
- Around line 39-48: Trim and validate model strings early: in the constructor
(where this.model is set) call this.model = this.model.trim() and if the result
is an empty string throw an error to prevent resolveModel() from returning ""
which later gets passed to embed(...). For non-prefixed model names detected in
resolveModel() (the branch checking hasProviderPrefix), either validate the raw
name format against your acceptable model-name regex/list or route it through
the registry resolution logic (e.g., call the same registry lookup used for
provider-qualified names) before assigning this.modelName and returning; ensure
resolveModel(), constructor, this.model and this.modelName are updated
accordingly so empty/whitespace models are rejected and non-prefixed names are
validated or resolved.
In `@packages/core/src/tool/routing/embedding.ts`:
- Around line 49-53: The parameter normalization logic in embedding.ts is
inverted: change the conditional for tool.parameters so Zod schema objects are
converted with zodSchemaToJsonUI and non-object values are used directly;
specifically, in the block that builds `normalized` (referencing
`tool.parameters`, `zodSchemaToJsonUI`, and `safeStringify`) invert the ternary
so it calls `zodSchemaToJsonUI(tool.parameters)` when `typeof tool.parameters
=== "object"` and otherwise uses `tool.parameters`, then push the stringified
result as before.
In `@website/docs/tools/tool-routing.md`:
- Around line 238-243: Remove the duplicate embedding model bullet in the list
under the embedding router description by deleting the repeated
"openai/text-embedding-3-small" entry so the list contains unique items
("openai/text-embedding-3-small", "text-embedding-3-small"); update the
surrounding text if necessary to keep punctuation/formatting consistent.
In `@website/recipes/tool-routing.md`:
- Around line 124-133: The example references mcpToolkit but never defines or
imports it, causing confusion; update the toolRouting.pool example by either
adding a short MCP toolkit import/initialization (create an MCPToolkit instance
and assign it to mcpToolkit) or replace mcpToolkit with a concrete,
self-contained tool instance, and/or add a comment linking to the MCP docs;
specifically modify the snippet that defines toolRouting.pool and introduce
MCPToolkit (or a concrete alternative) so mcpToolkit is a valid symbol.
♻️ Duplicate comments (1)
packages/core/src/agent/agent.ts (1)
5277-5318: Approval can still be bypassed for provider tools.Line 5277 only injects
approvedArgsas prompt text; the actualtoolCall.inputis never validated against those approved args before the tool executes, so a model can call the tool with unapproved inputs. This was flagged earlier and still appears present.Suggested direction: re-validate
toolCall.inputagainstapprovedArgs(or re-runensureToolApprovalon the actual input) before acting on results, and hard-fail if they diverge.
🧹 Nitpick comments (8)
examples/with-auth/src/index.ts (1)
34-36: Consider adding a comment clarifying this is a placeholder secret.The hardcoded
"super-secret"JWT secret is fine for an example, but a brief inline comment would help users understand they must replace it in production.💡 Suggested improvement
provider: jwtAuth({ - secret: "super-secret", + secret: "super-secret", // TODO: Replace with a secure secret in production }),examples/with-tool-routing/README.md (1)
45-53: Consider expanding the README with usage details and code snippets.Compared to other example READMEs (e.g.,
with-working-memory), this README lacks:
- A "Highlights" section explaining what tool routing provides
- A code snippet demonstrating the tool routing configuration
- "Run Locally" instructions
Since tool routing is a new feature, users would benefit from a brief explanation and example code directly in the README.
docs/tool-routing-plan.md (1)
21-24: Clarify embedding strategy wording for model references.Since routing can now be enabled via model reference strings, consider updating the scope bullet so it doesn’t imply adapters are required.
✏️ Suggested wording tweak
- - Embedding strategy: optional selector using EmbeddingAdapter / AiSdkEmbeddingAdapter. + - Embedding strategy: optional selector using EmbeddingModelReference (model string) or EmbeddingAdapter.packages/core/src/memory/types.ts (1)
229-277: Align embedding docs and adapter type surface.MemoryConfig.embedding now accepts config objects (model + options), so the doc comment should reflect that. Also, EmbeddingAdapterInput now mixes EmbeddingAdapter with EmbeddingModelReference from the adapters module—worth aligning the EmbeddingAdapter signature across modules to avoid drift (notably
getDimensionsoptionality).✏️ Doc comment update
- * Optional embedding adapter or model reference for semantic operations + * Optional embedding adapter, model reference, or config (model + options) for semantic operationspackages/core/src/memory/adapters/embedding/ai-sdk.ts (2)
11-19: Type safety issue:modelfield typed asEmbeddingModelbut assigned a string.The
modelfield is declared asEmbeddingModel(line 11), but the constructor assignsnormalizedModelwhich can be a string (line 19). This creates a type inconsistency that TypeScript may not catch due to theany-like nature of some AI SDK types.Consider using a union type or separate fields:
♻️ Suggested type fix
export class AiSdkEmbeddingAdapter implements EmbeddingAdapter { - private model: EmbeddingModel; + private model: EmbeddingModel | string; private dimensions: number; private modelName: string; private options: EmbeddingOptions; private modelResolvePromise?: Promise<EmbeddingModel>;
51-63: Consider not clearingmodelResolvePromiseto enable caching.Currently,
modelResolvePromiseis cleared infinally(). While this works correctly (subsequent calls checktypeof this.model !== "string"first), keeping the resolved promise cached would be slightly more efficient and clearer in intent.♻️ Optional: Keep promise for caching
this.modelResolvePromise = ModelProviderRegistry.getInstance() .resolveEmbeddingModel(trimmed) .then((resolved) => { this.model = resolved; this.modelName = trimmed; return resolved; - }) - .finally(() => { - this.modelResolvePromise = undefined; }); return this.modelResolvePromise;packages/core/src/memory/index.ts (1)
47-68: Unreachable fallback case at line 67.The
resolveEmbeddingAdapterfunction handles all expected input types (undefined, EmbeddingAdapter, string, EmbeddingAdapterConfig), but line 67 appears unreachable. IfEmbeddingAdapterInputis a union of these types, this fallback should never execute. If it can execute, passing an unknown type toAiSdkEmbeddingAdaptermay cause unexpected behavior.Consider either removing the unreachable fallback or adding a type assertion to satisfy the exhaustiveness check:
♻️ Suggested improvement
if (isEmbeddingAdapterConfig(embedding)) { const { model, ...options } = embedding; return new AiSdkEmbeddingAdapter(model, options); } - return new AiSdkEmbeddingAdapter(embedding); + // Exhaustive check - this should be unreachable if EmbeddingAdapterInput is properly typed + const _exhaustive: never = embedding; + return _exhaustive;packages/core/src/tool/routing/embedding.ts (1)
100-109: Defensive fallback returns empty embedding.At line 103, if a cache entry is missing, an empty array is returned. This results in a 0 similarity score (line 165). While this is safe, it could silently hide bugs where the cache wasn't populated correctly. Consider logging a warning for this unexpected case.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/agent/agent.ts (1)
4801-4815: Avoid callingtool.hooks.onEndtwice on errors.This can duplicate side effects (metrics, cleanup, state changes) and is likely unintended.
🛠️ Proposed fix
await tool.hooks?.onEnd?.({ tool, args, output: undefined, error: voltAgentError, options: executionOptions, }); - - await tool.hooks?.onEnd?.({ - tool, - args, - output: undefined, - error: voltAgentError, - options: executionOptions, - });
🤖 Fix all issues with AI agents
In `@website/recipes/tool-routing.md`:
- Around line 95-97: The resolver currently returns metadata ({ query, tool:
tool.name }) instead of the tool's argument object expected by the tool's
parameter schema; update the resolver (function named resolver) to produce and
return an arguments object that matches the tool's expected params (e.g., for
get_weather return { location: <derived-from-query> } or call the tool's
argument-construction/validation helper if available) rather than only
tool.name, ensuring the returned shape matches get_weather's parameter schema.
🧹 Nitpick comments (6)
packages/core/src/memory/adapters/embedding/ai-sdk.spec.ts (1)
186-216: Consider adding test coverage for edge cases in model resolution.The test validates the happy path for provider-qualified strings, but the implementation has several branches that lack test coverage:
- Non-prefixed bare model names (e.g.,
"text-embedding-ada-002")- Invalid bare model names that should throw
- Empty/whitespace-only strings passed to the constructor
- Resolution failure scenarios from the registry
♻️ Suggested additional tests
it("should accept valid bare model names without registry resolution", async () => { const { embed } = await import("ai"); vi.mocked(embed).mockResolvedValue({ value: "test text", embedding: [0.1, 0.2], usage: { tokens: 10 }, } as EmbedResult<string>); const bareAdapter = new AiSdkEmbeddingAdapter("text-embedding-ada-002"); await bareAdapter.embed("test text"); expect(embed).toHaveBeenCalledWith({ model: "text-embedding-ada-002", value: "test text", }); }); it("should throw for invalid bare model names", async () => { const invalidAdapter = new AiSdkEmbeddingAdapter("invalid model name!"); await expect(invalidAdapter.embed("test")).rejects.toThrow('Invalid embedding model id'); }); it("should throw for empty model string", () => { expect(() => new AiSdkEmbeddingAdapter("")).toThrow("Embedding model is required."); expect(() => new AiSdkEmbeddingAdapter(" ")).toThrow("Embedding model is required."); });packages/core/src/memory/adapters/embedding/ai-sdk.ts (2)
41-76: Race condition: concurrent callers may trigger redundant registry lookups.When
modelResolvePromiseis cleared in.finally(), subsequent concurrent calls that arrive after resolution completes but beforethis.modelis checked will start a new registry lookup, even though the model was already resolved.The current flow:
- Call A starts resolution, sets
modelResolvePromise- Call B waits on
modelResolvePromise- Resolution completes,
this.modelis updated,.finally()clearsmodelResolvePromise- Call C arrives, sees
typeof this.model !== "string"→ returns immediately ✓This is actually safe because
this.modelis updated in.then()before.finally()clears the promise. However, if resolution fails,.finally()still clears the promise, allowing retries on subsequent calls—which may be intentional for transient failures.One minor robustness improvement: avoid the redundant
trim()call on line 49 since the constructor already trims.♻️ Minor cleanup
private async resolveModel(): Promise<EmbeddingModel> { if (typeof this.model !== "string") { return this.model; } if (this.modelResolvePromise) { return this.modelResolvePromise; } - const trimmed = this.model.trim(); - if (!trimmed) { - throw new Error("Embedding model is required."); - } + // Constructor guarantees non-empty trimmed string + const trimmed = this.model; const hasProviderPrefix = trimmed.includes("/") || trimmed.includes(":");
64-76: Error from registry resolution is not propagated with context.If
resolveEmbeddingModelthrows (e.g., provider not registered), the error bubbles up directly. Unlikeembed()andembedBatch()which wrap errors with context messages, resolution failures will surface raw registry errors.Consider wrapping the registry call for consistent error messaging:
♻️ Suggested improvement
this.modelResolvePromise = ModelProviderRegistry.getInstance() .resolveEmbeddingModel(trimmed) .then((resolved) => { this.model = resolved; this.modelName = trimmed; return resolved; }) + .catch((error) => { + throw new Error( + `Failed to resolve embedding model "${trimmed}": ${error instanceof Error ? error.message : String(error)}`, + ); + }) .finally(() => { this.modelResolvePromise = undefined; });website/recipes/tool-routing.md (3)
57-65: Incomplete code snippet may confuse readers.The
toolRouting:snippet is shown as a standalone object literal without the surroundingAgentorVoltAgentcontext. Consider wrapping it in a complete example or adding a comment indicating where this config belongs.📝 Suggested improvement
## Explicit Pools (Two Categories) ```typescript const weatherPool = [weatherTool]; const financePool = [convertCurrencyTool]; +const agent = new Agent({ + name: "Pool Agent", + model: openai("gpt-4o-mini"), -toolRouting: { - embedding: "openai/text-embedding-3-small", - pool: [...weatherPool, ...financePool], -} + toolRouting: { + embedding: "openai/text-embedding-3-small", + pool: [...weatherPool, ...financePool], + }, +});</details> --- `71-76`: **Same issue: standalone `toolRouting` config.** This snippet has the same problem—readers may not immediately understand where to place this configuration. --- `137-142`: **Standalone `toolRouting` block without surrounding context.** After properly importing and initializing `mcp`, the final `toolRouting:` block is still a fragment. Consider wrapping it in a complete `Agent` or `VoltAgent` instantiation for clarity. <details> <summary>📝 Suggested improvement</summary> ```diff const mcpTools = await mcp.getTools(); -toolRouting: { - pool: [ - openai.tools.webSearch(), - ...mcpTools, - ], -} +const agent = new Agent({ + name: "MCP Agent", + model: openai("gpt-4o-mini"), + toolRouting: { + embedding: "openai/text-embedding-3-small", + pool: [ + openai.tools.webSearch(), + ...mcpTools, + ], + }, +});
| resolver: async ({ query, tool }) => { | ||
| return { query, tool: tool.name }; | ||
| }, |
There was a problem hiding this comment.
Resolver returns metadata instead of tool arguments.
The resolver function returns { query, tool: tool.name } which appears to be metadata rather than arguments that match the tool's parameter schema. For example, if get_weather expects { location: string }, this resolver wouldn't provide valid arguments.
Consider updating to demonstrate proper argument resolution:
📝 Suggested improvement
resolver: async ({ query, tool }) => {
- return { query, tool: tool.name };
+ // Extract location from query for weather tool, etc.
+ if (tool.name === "get_weather") {
+ return { location: query };
+ }
+ return { query };
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| resolver: async ({ query, tool }) => { | |
| return { query, tool: tool.name }; | |
| }, | |
| resolver: async ({ query, tool }) => { | |
| // Extract location from query for weather tool, etc. | |
| if (tool.name === "get_weather") { | |
| return { location: query }; | |
| } | |
| return { query }; | |
| }, |
🤖 Prompt for AI Agents
In `@website/recipes/tool-routing.md` around lines 95 - 97, The resolver currently
returns metadata ({ query, tool: tool.name }) instead of the tool's argument
object expected by the tool's parameter schema; update the resolver (function
named resolver) to produce and return an arguments object that matches the
tool's expected params (e.g., for get_weather return { location:
<derived-from-query> } or call the tool's argument-construction/validation
helper if available) rather than only tool.name, ensuring the returned shape
matches get_weather's parameter schema.
PR Checklist
Please check if your PR fulfills the following requirements:
Bugs / Features
What is the current behavior?
What is the new behavior?
fixes (issue)
Notes for reviewers
Summary by cubic
Adds tool routing with router tools, pool/expose controls, and embedding-based selection so agents can route large tool pools without bloating prompts. Also adds provider-qualified embedding model strings (e.g., openai/text-embedding-3-small) and tool hooks with onToolEnd output overrides; fixes #969.
New Features
Migration
Written for commit efc8815. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.