diff --git a/.lycheeignore b/.lycheeignore index 72b96df258..66396b3f9c 100644 --- a/.lycheeignore +++ b/.lycheeignore @@ -5,7 +5,7 @@ # Google Cloud Console (requires authentication, returns HTTP/2 errors) ^https://console\.(cloud\.google|developers\.google)\.com -# Placeholder URL with user-specific path +# URL contains bracket placeholder (e.g. /s/[project-id]) ^https://app\.phoenix\.arize\.com/s/\[ # Requires authentication diff --git a/docs/agents/index.md b/docs/agents/index.md index 41e9bf2e31..dff532e314 100644 --- a/docs/agents/index.md +++ b/docs/agents/index.md @@ -86,4 +86,5 @@ Now that you have an overview of the different agent types available in ADK, div * [**Workflow Agents:**](workflow-agents/index.md) Learn how to orchestrate tasks using `SequentialAgent`, `ParallelAgent`, and `LoopAgent` for structured and predictable processes. * [**Custom Agents:**](custom-agents.md) Discover the principles of extending `BaseAgent` to build agents with unique logic and integrations tailored to your specific needs. * [**Multi-Agents:**](multi-agents.md) Understand how to combine different agent types to create sophisticated, collaborative systems capable of tackling complex problems. +* [**Agent Routing:**](routing.md) Dynamically select between multiple agents at runtime using router functions for fallback, A/B testing, and auto-routing. * [**Models:**](/agents/models/) Learn about the different LLM integrations available and how to select the right model for your agents. diff --git a/docs/agents/models/index.md b/docs/agents/models/index.md index 0b5906280e..2858bffa6f 100644 --- a/docs/agents/models/index.md +++ b/docs/agents/models/index.md @@ -9,25 +9,30 @@ integrate various Large Language Models (LLMs) into your agents. This section details how to leverage Gemini and integrate other popular models effectively, including those hosted externally or running locally. -ADK primarily uses two mechanisms for model integration: +ADK provides several mechanisms for model integration: -1. **Direct String / Registry:** For models tightly integrated with Google Cloud, - such as Gemini models accessed via Google AI Studio or Agent Platform, or models - hosted on Agent Platform endpoints. You access these models by providing the model name or endpoint resource string and ADK's internal registry - resolves this string to the appropriate backend client. +1. **Direct String / Registry:** For models tightly integrated with Google + Cloud, such as Gemini models accessed via Google AI Studio or Agent Platform, + or models hosted on Agent Platform endpoints. You access these models by + providing the model name or endpoint resource string and ADK's internal + registry resolves this string to the appropriate backend client. * [Gemini models](/agents/models/google-gemini/) * [Claude models](/agents/models/anthropic/) * [Agent Platform hosted models](/agents/models/agent-platform/) -2. **Model connectors:** For broader compatibility, especially models - outside the Google ecosystem or those requiring specific client - configurations, such as models accessed via Apigee or LiteLLM. You instantiate a specific wrapper class, such as `ApigeeLlm` or - `LiteLlm`, and pass this object as the `model` parameter - to your `LlmAgent`. +2. **Model connectors:** For broader compatibility, especially models outside + the Google ecosystem or those requiring specific client configurations, such + as models accessed via Apigee or LiteLLM. You instantiate a specific wrapper + class, such as `ApigeeLlm` or `LiteLlm`, and pass this object as the `model` + parameter to your `LlmAgent`. * [Apigee models](/agents/models/apigee/) * [LiteLLM models](/agents/models/litellm/) * [Ollama model hosting](/agents/models/ollama/) * [vLLM model hosting](/agents/models/vllm/) * [LiteRT-LM model hosting](/agents/models/litert-lm/) + +3. **[Model routing](/agents/models/routing/):** For dynamically selecting + between multiple models at runtime using a router function, with automatic + failover on error. diff --git a/docs/agents/models/routing.md b/docs/agents/models/routing.md new file mode 100644 index 0000000000..4c51847bf6 --- /dev/null +++ b/docs/agents/models/routing.md @@ -0,0 +1,64 @@ +# Route between models + +
+ Supported in ADKTypeScript v1.0.0Experimental +
+ +!!! example "Experimental" + + Model routing is experimental and may change in future releases. We welcome + your + [feedback](https://github.com/google/adk-js/issues/new?template=feature_request.md)! + +An `LlmAgent` uses a single model by default. When you need to dynamically +select between different models for each request, you can define a routing +function that chooses which model to use. `RoutedLlm` provides this capability, +enabling model fallback on error, A/B testing between models, and auto-routing +by input complexity. If the selected model fails before producing any output, +the routing function is called again with error context so it can select a +different model. + +Pass a `RoutedLlm` as an `LlmAgent`'s `model` parameter. Use `RoutedLlm` when +only the model varies between routes. If you also need to switch instructions, +tools, or sub-agents, use [`RoutedAgent`](../routing.md) instead. + +## How routing works + +The `LlmRouter` function receives the map of available models and the current +`LlmRequest`, and returns the key of the model to use: + +=== "TypeScript" + + ```typescript + type LlmRouter = ( + models: Readonly>, + request: LlmRequest, + errorContext?: { failedKeys: ReadonlySet; lastError: unknown }, + ) => Promise | string | undefined; + ``` + +The `models` parameter accepts either a `Record` with explicit +keys, or an array of `BaseLlm` instances. If an array is provided, each model's +name is used as its key. + +Failover follows the same rules as +[`RoutedAgent`](../routing.md#how-routing-works): the router is re-called with +`errorContext` only if the selected model fails before yielding any response. +After yielding, errors propagate without retry. The router can return +`undefined` to stop retrying and propagate the last error. + +**Live connections:** `RoutedLlm.connect()` selects the model at connection +time. Once a live connection is established, the model cannot be switched +mid-stream. + +## Basic usage + +The following example creates a `RoutedLlm` that tries a primary model first and +falls back to a secondary model if the primary fails. The router checks +`errorContext.failedKeys` to avoid re-selecting the failed model: + +=== "TypeScript" + + ```typescript + --8<-- "examples/typescript/snippets/agents/models/routing/basic-usage.ts:full" + ``` diff --git a/docs/agents/routing.md b/docs/agents/routing.md new file mode 100644 index 0000000000..67f8e3273c --- /dev/null +++ b/docs/agents/routing.md @@ -0,0 +1,126 @@ +# Route between agents + +
+ Supported in ADKTypeScript v1.0.0Experimental +
+ +!!! example "Experimental" + + Agent routing is experimental and may change in future releases. We welcome + your + [feedback](https://github.com/google/adk-js/issues/new?template=feature_request.md)! + +When building agents for different tasks, you can define a routing function that +selects which one handles each invocation at runtime. `RoutedAgent` provides +this capability, enabling agent fallback on error, A/B testing, planning modes, +and auto-routing by input complexity. If the selected agent fails before +producing any output, the routing function is called again with error context so +it can select a fallback. + +`RoutedAgent` is different from [workflow agents](workflow-agents/index.md) like +`SequentialAgent` or `ParallelAgent`, which orchestrate multiple agents in a +fixed pattern, and from [LLM-driven +delegation](multi-agents.md#b-llm-driven-delegation-agent-transfer), where the +LLM decides which agent to hand off to. With `RoutedAgent`, you write an +explicit routing function that selects **one** agent per invocation. For +model-level routing, see [Model routing](models/routing.md). + +## How routing works + +Both `RoutedAgent` and [`RoutedLlm`](models/routing.md) are powered by a shared +routing utility that handles selection and failover. + +The router function receives the map of available agents and the current +context, and returns the key of the agent to run. It can be synchronous or +async: + +=== "TypeScript" + + ```typescript + type AgentRouter = ( + agents: Readonly>, + context: InvocationContext, + errorContext?: { failedKeys: ReadonlySet; lastError: unknown }, + ) => Promise | string | undefined; + ``` + +**The `agents` parameter** accepts either a `Record` with +explicit keys, or an array of agents. If an array is provided, each agent's +`name` property is used as its key. + +**Failover behavior:** + +- The router is first called without `errorContext` to make the initial + selection. +- If the selected agent throws an error **before yielding any events**, the + router is called again with `errorContext` containing `failedKeys` and + `lastError`. +- If the selected agent throws an error **after yielding events**, the error + propagates directly without retry, because partial results have already been + emitted. +- A key that has already been tried cannot be re-selected. If the router returns + a previously failed key, the error propagates. +- If the router returns `undefined`, routing stops and the last error is thrown. + +## Basic usage + +Create multiple agents, define a router function that returns a key, and wrap +them in a `RoutedAgent`. The following example routes between two agents based +on an external configuration value that can change between invocations: + +=== "TypeScript" + + ```typescript + --8<-- "examples/typescript/snippets/agents/routing/basic-usage.ts:full" + ``` + +Change `config.selectedAgent` to `'agent_b'` before the next invocation to +route to a different agent. + +## Fallback on error + +When an agent fails, the router is called again with `errorContext` so it can +select a fallback. Failover only applies if the agent fails before yielding any +events (see [How routing works](#how-routing-works)). The following example +checks `errorContext.failedKeys` to avoid re-selecting the failed agent: + +=== "TypeScript" + + ```typescript + --8<-- "examples/typescript/snippets/agents/routing/fallback.ts:config" + ``` + +## Planning mode + +A router can read any external state to select between agents with different +instructions, models, and tools. This lets you implement a planning mode where +the agent switches behavior dynamically. For example, a basic agent might have +read and write tools, while a planning agent is restricted to read-only access +and uses a more powerful model for analysis. + +The following example shows a different `RoutedAgent` configuration. See [basic +usage](#basic-usage) for the full runner setup. + +=== "TypeScript" + + ```typescript + --8<-- "examples/typescript/snippets/agents/routing/planning-mode.ts:config" + ``` + +Set `planningMode = true` before an invocation to route to the planning agent +with its restricted tool set and different instructions. + +## Auto-routing by complexity + +The router function can call a lightweight classifier model to categorize input +and route to different agents accordingly. Because the router can be async, you +can make LLM calls inside it before selecting an agent. + +The following example shows a different `RoutedAgent` configuration. See [basic +usage](#basic-usage) for the full runner setup. + +=== "TypeScript" + + ```typescript + --8<-- "examples/typescript/snippets/agents/routing/auto-routing.ts:config" + ``` diff --git a/examples/typescript/snippets/agents/models/routing/basic-usage.ts b/examples/typescript/snippets/agents/models/routing/basic-usage.ts new file mode 100644 index 0000000000..41da68e021 --- /dev/null +++ b/examples/typescript/snippets/agents/models/routing/basic-usage.ts @@ -0,0 +1,73 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// --8<-- [start:full] +import { + BaseLlm, + Gemini, + LlmRequest, + LlmAgent, + RoutedLlm, + InMemoryRunner, +} from '@google/adk'; + +const primaryModel = new Gemini({ model: 'gemini-flash-latest' }); +const fallbackModel = new Gemini({ model: 'gemini-pro-latest' }); + +const router = ( + models: Readonly>, + request: LlmRequest, + // errorContext is provided when a previously selected model fails + errorContext?: { failedKeys: ReadonlySet; lastError: unknown }, +) => { + if (!errorContext) { + return 'primary'; // Try primary first + } + if (errorContext.failedKeys.has('primary')) { + return 'fallback'; // Fall back if primary failed + } + return undefined; // No more options, propagate the error +}; + +const routedLlm = new RoutedLlm({ + models: { primary: primaryModel, fallback: fallbackModel }, + router, +}); + +// Use RoutedLlm as the model for an LlmAgent +const agent = new LlmAgent({ + name: 'my_agent', + model: routedLlm, + instruction: 'You are a helpful assistant.', +}); + +const runner = new InMemoryRunner({ agent, appName: 'my_app' }); + +const session = await runner.sessionService.createSession({ + appName: 'my_app', + userId: 'user_1', +}); + +const run = runner.runAsync({ + userId: 'user_1', + sessionId: session.id, + newMessage: { role: 'user', parts: [{ text: 'Hello!' }] }, +}); + +for await (const event of run) { + if (event.content?.parts?.[0]?.text) { + console.log(event.content.parts[0].text); + } +} +// --8<-- [end:full] diff --git a/examples/typescript/snippets/agents/models/routing/package.json b/examples/typescript/snippets/agents/models/routing/package.json new file mode 100644 index 0000000000..c60d54adf8 --- /dev/null +++ b/examples/typescript/snippets/agents/models/routing/package.json @@ -0,0 +1,22 @@ +{ + "name": "adk-docs-examples", + "version": "1.0.0", + "description": "TS code examples for the ADK Documentation", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc", + "clean": "rm -rf dist" + }, + "keywords": ["adk", "google", "agent", "typescript", "gemini"], + "author": "", + "license": "Apache-2.0", + "type": "commonjs", + "devDependencies": { + "@types/node": "^20.14.2", + "typescript": "^5.9.2" + }, + "dependencies": { + "@google/adk": "^1.0.0" + } +} diff --git a/examples/typescript/snippets/agents/models/routing/tsconfig.json b/examples/typescript/snippets/agents/models/routing/tsconfig.json new file mode 100644 index 0000000000..820f935898 --- /dev/null +++ b/examples/typescript/snippets/agents/models/routing/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + /* Build Options */ + "target": "es2020", + "module": "nodenext", + "moduleResolution": "nodenext", + "outDir": "./dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + + /* Strictness */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + /* Module Interop */ + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "exclude": ["node_modules", "dist"] +} diff --git a/examples/typescript/snippets/agents/routing/auto-routing.ts b/examples/typescript/snippets/agents/routing/auto-routing.ts new file mode 100644 index 0000000000..0bf08377ac --- /dev/null +++ b/examples/typescript/snippets/agents/routing/auto-routing.ts @@ -0,0 +1,98 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { InMemoryRunner } from '@google/adk'; + +// --8<-- [start:config] +import { + BaseAgent, + Gemini, + InvocationContext, + LlmAgent, + RoutedAgent, +} from '@google/adk'; + +const simpleAgent = new LlmAgent({ + name: 'simple', + model: 'gemini-flash-latest', + instruction: 'You are a simple assistant for basic questions.', +}); + +const complexAgent = new LlmAgent({ + name: 'complex', + model: 'gemini-pro-latest', + instruction: 'You are an expert assistant for complex analysis.', +}); + +// Lightweight model to classify input complexity +const classifierModel = new Gemini({ model: 'gemini-flash-latest' }); + +const router = async ( + agents: Readonly>, + context: InvocationContext, +) => { + // Extract the user's input text + const text = context.userContent?.parts?.[0]?.text || ''; + if (!text) return 'simple'; + + const prompt = + `Classify this request as 'simple' or 'complex'. ` + + `Reply with ONLY that word.\nRequest: "${text}"`; + + const generator = classifierModel.generateContentAsync({ + contents: [{ role: 'user', parts: [{ text: prompt }] }], + toolsDict: {}, + liveConnectConfig: {}, + }); + + let classification = ''; + for await (const resp of generator) { + if (resp.content?.parts?.[0]?.text) { + classification += resp.content.parts[0].text; + } + } + + return classification.toLowerCase().includes('complex') + ? 'complex' + : 'simple'; +}; + +const routedAgent = new RoutedAgent({ + name: 'my_routed_agent', + agents: { simple: simpleAgent, complex: complexAgent }, + router, +}); +// --8<-- [end:config] + +const runner = new InMemoryRunner({ + agent: routedAgent, + appName: 'my_app', +}); + +const session = await runner.sessionService.createSession({ + appName: 'my_app', + userId: 'user_1', +}); + +const run = runner.runAsync({ + userId: 'user_1', + sessionId: session.id, + newMessage: { role: 'user', parts: [{ text: 'What is 1+1?' }] }, +}); + +for await (const event of run) { + if (event.content?.parts?.[0]?.text) { + console.log(event.content.parts[0].text); + } +} diff --git a/examples/typescript/snippets/agents/routing/basic-usage.ts b/examples/typescript/snippets/agents/routing/basic-usage.ts new file mode 100644 index 0000000000..b4f4a4fb25 --- /dev/null +++ b/examples/typescript/snippets/agents/routing/basic-usage.ts @@ -0,0 +1,60 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// --8<-- [start:full] +import { LlmAgent, RoutedAgent, InMemoryRunner } from '@google/adk'; + +const agentA = new LlmAgent({ + name: 'agent_a', + model: 'gemini-flash-latest', + instruction: 'You are Agent A. Always identify yourself as Agent A.', +}); + +const agentB = new LlmAgent({ + name: 'agent_b', + model: 'gemini-flash-latest', + instruction: 'You are Agent B. Always identify yourself as Agent B.', +}); + +// External configuration that can change at runtime +const config = { selectedAgent: 'agent_a' }; + +const routedAgent = new RoutedAgent({ + name: 'my_routed_agent', + agents: { agent_a: agentA, agent_b: agentB }, + router: () => config.selectedAgent, +}); + +const runner = new InMemoryRunner({ + agent: routedAgent, + appName: 'my_app', +}); + +const session = await runner.sessionService.createSession({ + appName: 'my_app', + userId: 'user_1', +}); + +const run = runner.runAsync({ + userId: 'user_1', + sessionId: session.id, + newMessage: { role: 'user', parts: [{ text: 'Who are you?' }] }, +}); + +for await (const event of run) { + if (event.content?.parts?.[0]?.text) { + console.log(event.content.parts[0].text); + } +} +// --8<-- [end:full] diff --git a/examples/typescript/snippets/agents/routing/fallback.ts b/examples/typescript/snippets/agents/routing/fallback.ts new file mode 100644 index 0000000000..29aea62758 --- /dev/null +++ b/examples/typescript/snippets/agents/routing/fallback.ts @@ -0,0 +1,79 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { InMemoryRunner } from '@google/adk'; + +// --8<-- [start:config] +import { + BaseAgent, + InvocationContext, + LlmAgent, + RoutedAgent, +} from '@google/adk'; + +const primaryAgent = new LlmAgent({ + name: 'primary', + model: 'gemini-flash-latest', + instruction: 'You are the primary agent.', +}); + +const fallbackAgent = new LlmAgent({ + name: 'fallback', + model: 'gemini-pro-latest', + instruction: 'You are the fallback agent.', +}); + +const router = ( + agents: Readonly>, + context: InvocationContext, + // errorContext is provided when a previously selected agent fails + errorContext?: { failedKeys: ReadonlySet; lastError: unknown }, +) => { + if (!errorContext) { + return 'primary'; // Try primary first + } + if (errorContext.failedKeys.has('primary')) { + return 'fallback'; // Fall back if primary failed + } + return undefined; // No more options, propagate the error +}; + +const routedAgent = new RoutedAgent({ + name: 'my_routed_agent', + agents: { primary: primaryAgent, fallback: fallbackAgent }, + router, +}); +// --8<-- [end:config] + +const runner = new InMemoryRunner({ + agent: routedAgent, + appName: 'my_app', +}); + +const session = await runner.sessionService.createSession({ + appName: 'my_app', + userId: 'user_1', +}); + +const run = runner.runAsync({ + userId: 'user_1', + sessionId: session.id, + newMessage: { role: 'user', parts: [{ text: 'Who are you?' }] }, +}); + +for await (const event of run) { + if (event.content?.parts?.[0]?.text) { + console.log(event.content.parts[0].text); + } +} diff --git a/examples/typescript/snippets/agents/routing/package.json b/examples/typescript/snippets/agents/routing/package.json new file mode 100644 index 0000000000..64cf657306 --- /dev/null +++ b/examples/typescript/snippets/agents/routing/package.json @@ -0,0 +1,23 @@ +{ + "name": "adk-docs-examples", + "version": "1.0.0", + "description": "TS code examples for the ADK Documentation", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc", + "clean": "rm -rf dist" + }, + "keywords": ["adk", "google", "agent", "typescript", "gemini"], + "author": "", + "license": "Apache-2.0", + "type": "commonjs", + "devDependencies": { + "@types/node": "^20.14.2", + "typescript": "^5.9.2" + }, + "dependencies": { + "@google/adk": "^1.0.0", + "zod": "^3.24.0" + } +} diff --git a/examples/typescript/snippets/agents/routing/planning-mode.ts b/examples/typescript/snippets/agents/routing/planning-mode.ts new file mode 100644 index 0000000000..4c4e8ad14d --- /dev/null +++ b/examples/typescript/snippets/agents/routing/planning-mode.ts @@ -0,0 +1,83 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { InMemoryRunner } from '@google/adk'; + +// --8<-- [start:config] +import { + FunctionTool, + LlmAgent, + RoutedAgent, +} from '@google/adk'; +import { z } from 'zod'; + +const readFileTool = new FunctionTool({ + name: 'read_file', + description: 'Reads content from a file.', + parameters: z.object({ filePath: z.string() }), + execute: (args) => ({ content: `Contents of ${args.filePath}` }), +}); + +const writeFileTool = new FunctionTool({ + name: 'write_file', + description: 'Writes content to a file.', + parameters: z.object({ filePath: z.string(), content: z.string() }), + execute: (args) => ({ result: `Wrote to ${args.filePath}` }), +}); + +const basicAgent = new LlmAgent({ + name: 'basic', + model: 'gemini-flash-latest', + instruction: 'You are a basic assistant. Use tools to help the user.', + tools: [readFileTool, writeFileTool], +}); + +const planningAgent = new LlmAgent({ + name: 'planning', + model: 'gemini-flash-latest', + instruction: 'You are a planning expert. Analyze carefully. You can only read files.', + tools: [readFileTool], +}); + +// Toggle this to switch between basic and planning agents +let planningMode = false; + +const routedAgent = new RoutedAgent({ + name: 'my_routed_agent', + agents: { basic: basicAgent, planning: planningAgent }, + router: () => (planningMode ? 'planning' : 'basic'), +}); +// --8<-- [end:config] + +const runner = new InMemoryRunner({ + agent: routedAgent, + appName: 'my_app', +}); + +const session = await runner.sessionService.createSession({ + appName: 'my_app', + userId: 'user_1', +}); + +const run = runner.runAsync({ + userId: 'user_1', + sessionId: session.id, + newMessage: { role: 'user', parts: [{ text: 'Read the file report.txt' }] }, +}); + +for await (const event of run) { + if (event.content?.parts?.[0]?.text) { + console.log(event.content.parts[0].text); + } +} diff --git a/examples/typescript/snippets/agents/routing/tsconfig.json b/examples/typescript/snippets/agents/routing/tsconfig.json new file mode 100644 index 0000000000..820f935898 --- /dev/null +++ b/examples/typescript/snippets/agents/routing/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + /* Build Options */ + "target": "es2020", + "module": "nodenext", + "moduleResolution": "nodenext", + "outDir": "./dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + + /* Strictness */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + /* Module Interop */ + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "exclude": ["node_modules", "dist"] +} diff --git a/mkdocs.yml b/mkdocs.yml index bbfbc50893..85d69fc8f1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -298,6 +298,7 @@ nav: - Parallel agents: agents/workflow-agents/parallel-agents.md - Custom agents: agents/custom-agents.md - Multi-agent systems: agents/multi-agents.md + - Agent routing: agents/routing.md - Agent Config: agents/config.md - Models for Agents: - agents/models/index.md @@ -306,6 +307,7 @@ nav: - Claude: agents/models/anthropic.md - Agent Platform hosted: agents/models/agent-platform.md - Apigee AI Gateway: agents/models/apigee.md + - Model routing: agents/models/routing.md - Ollama: agents/models/ollama.md - vLLM: agents/models/vllm.md - LiteLLM: agents/models/litellm.md