|
1 | 1 | # @openrouter/agent |
2 | 2 |
|
| 3 | +## 0.10.0 |
| 4 | + |
| 5 | +### Minor Changes |
| 6 | + |
| 7 | +- [#102](https://github.com/OpenRouterTeam/typescript-agent/pull/102) [`787cbf8`](https://github.com/OpenRouterTeam/typescript-agent/commit/787cbf8b22bf2b8071e81e2dbf84ecd871a5e824) Thanks [@LukasParke](https://github.com/LukasParke)! - Add the full MCP integration under the canonical `@openrouter/agent/mcp` subpath. `@modelcontextprotocol/client` is an optional peer, so base agent installations and imports do not install or load MCP support. The existing `@openrouter/mcp` package remains as a compatibility facade and now re-exports the canonical agent subpaths. |
| 8 | + |
| 9 | + ```ts |
| 10 | + import { callModel, OpenRouter } from "@openrouter/agent"; |
| 11 | + import { createMCPTools } from "@openrouter/agent/mcp"; |
| 12 | + |
| 13 | + const mcp = await createMCPTools({ url: "https://mcp.example.com/mcp" }); |
| 14 | + const result = callModel(new OpenRouter(), { |
| 15 | + model: "openai/gpt-4o-mini", |
| 16 | + input: "Use the remote tools.", |
| 17 | + tools: mcp.tools, |
| 18 | + }); |
| 19 | + ``` |
| 20 | + |
| 21 | + Install `@modelcontextprotocol/client` alongside `@openrouter/agent` when using `/mcp`. The SDK is loaded lazily, so importing the base agent or the MCP entry point does not require the peer; the first MCP connection attempt without it throws an actionable `MCPMissingPeerDependencyError`. |
| 22 | + |
| 23 | + Existing `@openrouter/mcp` imports continue to work as tooling-visible deprecated migration facades, but new code should prefer `@openrouter/agent/mcp`. The facade would only be removed in a future breaking release after migration notice. |
| 24 | + |
| 25 | + The `@openrouter/mcp` facade continues to install `@modelcontextprotocol/client` transitively for backward compatibility; only direct `@openrouter/agent/mcp` users need to add the optional peer explicitly. |
| 26 | + |
| 27 | +- [#31](https://github.com/OpenRouterTeam/typescript-agent/pull/31) [`8d2ed61`](https://github.com/OpenRouterTeam/typescript-agent/commit/8d2ed61964aa063936763c7b80f6b5bf389fa144) Thanks [@mattapperson](https://github.com/mattapperson)! - Add `@openrouter/agent/tool-set` (port of ai-tool-set v1.0.0, MIT © Chris Cook): declarative activate / deactivate / activateWhen / deactivateWhen for tools with state- and context-aware predicates. Integrates with a new `activeTools?: readonly string[]` option on `callModel` that filters which tools are sent to the model for a given call. |
| 28 | + |
| 29 | + ```ts |
| 30 | + import { callModel, OpenRouter, serverTool, tool } from "@openrouter/agent"; |
| 31 | + import { createToolSet } from "@openrouter/agent/tool-set"; |
| 32 | + import { z } from "zod/v4"; |
| 33 | + |
| 34 | + type AppContext = { accountId: string }; |
| 35 | + |
| 36 | + // Curried form preserves the literal name for correlated tool event types. |
| 37 | + const listOrders = tool<AppContext>()({ |
| 38 | + name: "list_orders", |
| 39 | + inputSchema: z.object({}), |
| 40 | + execute: async (_params, ctx) => ({ |
| 41 | + accountId: ctx?.shared.accountId, |
| 42 | + orders: [], |
| 43 | + }), |
| 44 | + }); |
| 45 | + // override the default `server:${type}` id |
| 46 | + const search = serverTool( |
| 47 | + { type: "web_search_2025_08_26" }, |
| 48 | + { id: "public_search" } |
| 49 | + ); |
| 50 | + |
| 51 | + const toolSet = createToolSet({ |
| 52 | + tools: [listOrders, search] as const, |
| 53 | + }).deactivate("list_orders"); |
| 54 | + |
| 55 | + const client = new OpenRouter({ apiKey: process.env["OPENROUTER_API_KEY"] }); |
| 56 | + const resolved = toolSet.resolve(); |
| 57 | + |
| 58 | + // resolved.callModel is `{ tools, activeTools }` — spread it straight in |
| 59 | + const result = callModel(client, { |
| 60 | + model: "openai/gpt-4o-mini", |
| 61 | + input: "Search for OpenRouter pricing.", |
| 62 | + ...resolved.callModel, |
| 63 | + }); |
| 64 | + ``` |
| 65 | + |
| 66 | +- [#114](https://github.com/OpenRouterTeam/typescript-agent/pull/114) [`66d7232`](https://github.com/OpenRouterTeam/typescript-agent/commit/66d7232d53d9881c5842c77f8bc342314724bf3b) Thanks [@mattapperson](https://github.com/mattapperson)! - Add `toolChoice` to `nextTurnParams`, so a tool can change which tools the model may call on the following turn without touching the `tools` array. |
| 67 | + |
| 68 | + This is what a tool-search tool needs: declare every tool up front, keep the not-yet-needed ones out of reach behind an `allowed_tools` choice, and widen that choice as the model discovers what it wants. Because `tools` is byte-identical across turns, the provider's prompt-cache prefix survives — which is the whole reason to withhold tools rather than send them all. |
| 69 | + |
| 70 | + ```ts |
| 71 | + import { callModel, OpenRouter, tool } from "@openrouter/agent"; |
| 72 | + import { z } from "zod/v4"; |
| 73 | + |
| 74 | + const allowed = (names: string[]) => ({ |
| 75 | + type: "allowed_tools" as const, |
| 76 | + mode: "auto" as const, |
| 77 | + tools: names.map((name) => ({ type: "function", name })), |
| 78 | + }); |
| 79 | + |
| 80 | + const toolSearch = tool({ |
| 81 | + name: "tool_search", |
| 82 | + inputSchema: z.object({ pattern: z.string() }), |
| 83 | + execute: ({ pattern }) => findMatchingToolNames(pattern), |
| 84 | + nextTurnParams: { |
| 85 | + // Append, never rebuild: dropping a name revokes a tool the model may |
| 86 | + // already have used, and reordering churns the request for nothing. |
| 87 | + toolChoice: ({ pattern }, context) => |
| 88 | + allowed([ |
| 89 | + ...namesIn(context.toolChoice), |
| 90 | + ...findMatchingToolNames(pattern), |
| 91 | + ]), |
| 92 | + }, |
| 93 | + }); |
| 94 | + |
| 95 | + const client = new OpenRouter({ apiKey: process.env["OPENROUTER_API_KEY"] }); |
| 96 | + |
| 97 | + const result = callModel(client, { |
| 98 | + model: "openai/gpt-4o-mini", |
| 99 | + input: "What is the weather in Tokyo?", |
| 100 | + tools: [toolSearch, getWeather, sendEmail, listRepos], |
| 101 | + // Only the search tool is reachable until it finds something. |
| 102 | + toolChoice: allowed(["tool_search"]), |
| 103 | + }); |
| 104 | + ``` |
| 105 | + |
3 | 106 | ## 0.9.0 |
4 | 107 |
|
5 | 108 | ### Minor Changes |
|
0 commit comments