Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .speakeasy/gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ typescript:
acceptHeaderEnum: false
additionalDependencies:
dependencies:
'@standard-schema/spec': ^1.1.0
zod: ^3.25.0 || ^4.0.0
devDependencies:
'@types/node': ^22.13.12
'@valibot/to-json-schema': ^1.7.1
dotenv: ^16.4.7
valibot: ^1.4.2
vitest: ^3.2.4
peerDependencies: {}
additionalPackageJSON:
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Speakeasy's [persistent edits](https://www.speakeasy.com/docs/sdks/customize/cod
- Uses `ReusableReadableStream` to enable multiple parallel consumers

**Tool System** (`src/lib/tool.ts`, `src/lib/tool-types.ts`, `src/lib/tool-executor.ts`)
- `tool()` helper creates type-safe tools with Zod schemas
- `tool()` accepts Zod or Standard Schema v1 validators; provider schemas use Zod conversion, the Standard JSON Schema trait, or explicit `inputJsonSchema`
- Three tool types:
- **Regular tools** (`execute: function`) - auto-executed, return final result
- **Generator tools** (`execute: async generator`) - stream preliminary results
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ yarn add @openrouter/sdk
> [!IMPORTANT]
> `callModel` and its associated types have moved to the [`@openrouter/agent`](https://www.npmjs.com/package/@openrouter/agent) package. If you are using `callModel`, tool definitions, or related types from `@openrouter/sdk`, you should migrate to `@openrouter/agent`.
>
> The legacy SDK tool API accepts Zod schemas or any [Standard Schema v1](https://standardschema.dev/) validator for `inputSchema`, `outputSchema`, and `eventSchema`. Provider JSON Schema uses three tiers: Zod schemas use the built-in `z4.toJSONSchema` path; non-Zod schemas implementing [Standard JSON Schema v1](https://standardschema.dev/json-schema) use their `~standard.jsonSchema.input` converter; otherwise callers provide `inputJsonSchema`. An explicit `inputJsonSchema` overrides the Standard JSON Schema trait, and all paths remove `~`-prefixed metadata. The trait is available in Zod 4.2+, ArkType 2.1.28+, Zod Mini, VineJS, and Sury; Valibot adds it with `toStandardJsonSchema()` from `@valibot/to-json-schema`.
>
> To assist with the migration, run:
>
> ```bash
Expand Down
22 changes: 14 additions & 8 deletions examples/call-model-typed-tool-calling.example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* This example demonstrates how to use the tool() function for
* fully-typed tool definitions where execute params, return types, and event
* types are automatically inferred from Zod schemas.
* types are automatically inferred from Zod or any Standard Schema v1 validator.
*
* Tool types are auto-detected based on configuration:
* - Generator tool: When `eventSchema` is provided
Expand All @@ -17,7 +17,10 @@
import dotenv from "dotenv";
dotenv.config();

import { OpenRouter, tool } from "../src/index.js";
import { toStandardJsonSchema } from "@valibot/to-json-schema";
import * as v from "valibot";
import { OpenRouter } from "../src/index.js";
import { tool } from "../src/lib/tool.js";
import z from "zod";

const openRouter = new OpenRouter({
Expand All @@ -27,15 +30,18 @@ const openRouter = new OpenRouter({
// Create a typed regular tool using tool()
// The execute function params are automatically typed as z.infer<typeof inputSchema>
// The return type is enforced based on outputSchema
const weatherInputSchema = toStandardJsonSchema(
v.object({ location: v.string() }),
);

const weatherTool = tool({
name: "get_weather",
description: "Get the current weather for a location",
inputSchema: z.object({
location: z.string().describe("The city and country, e.g. San Francisco, CA"),
}),
outputSchema: z.object({
temperature: z.number(),
description: z.string(),
// This wrapper implements validation plus Standard JSON Schema conversion.
inputSchema: weatherInputSchema,
outputSchema: v.object({
temperature: v.number(),
description: v.string(),
}),
// params is automatically typed as { location: string }
execute: async (params) => {
Expand Down
4 changes: 3 additions & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"tsx": "^4.19.2"
},
"dependencies": {
"@openrouter/sdk": "file:.."
"@openrouter/sdk": "file:..",
"@valibot/to-json-schema": "^1.7.1",
"valibot": "^1.4.2"
}
}
31 changes: 31 additions & 0 deletions examples/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/tools-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* This file demonstrates the automatic tool execution feature.
* When you provide tools with `execute` functions, they are automatically:
* 1. Validated using Zod schemas
* 1. Validated using Zod or any Standard Schema v1 validator
* 2. Executed when the model calls them
* 3. Results sent back to the model
* 4. Process repeats until stopWhen condition is met (default: stepCountIs(5))
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,17 @@
"devDependencies": {
"@eslint/js": "^9.26.0",
"@types/node": "^22.13.12",
"@valibot/to-json-schema": "^1.7.1",
"dotenv": "^16.4.7",
"eslint": "^9.26.0",
"globals": "^15.14.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.26.0",
"valibot": "^1.4.2",
"vitest": "^3.2.4"
},
"dependencies": {
"@standard-schema/spec": "^1.1.0",
"zod": "^3.25.0 || ^4.0.0"
}
}
35 changes: 35 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading