-
Notifications
You must be signed in to change notification settings - Fork 15
feat: add async function support and nextTurnParams for dynamic parameter control. Also dynamic run stoppage #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
99941fc
feat: add nextTurnParams feature for dynamic conversation steering
mattapperson 4b78a19
feat: add async function support for CallModelInput parameters
mattapperson 7cdffd4
fix: correct type for nextTurnParams function parameters
mattapperson 25795a5
cleanup types
mattapperson 457f93b
fix
mattapperson c8ef55a
add stepWhen
mattapperson 6369ea3
cleanup
mattapperson af4f852
type cleanup and cruft removal
mattapperson f48d9f2
improve shape of turn context
mattapperson f7e2849
fixes and improvements
mattapperson bbab16a
fix: add stream termination and stopWhen condition support
mattapperson 701fe67
fix: use Claude Sonnet 4.5 with toolChoice required for reliable tool…
mattapperson 61ecacd
fix: differentiate manual vs auto-execution in tool tests
mattapperson 8f553df
fix: tools were being stripped from API requests
mattapperson 73de904
fix: increase timeout for tool execution test to 60s
mattapperson 9a11734
test: skip flaky tool execution test in CI
mattapperson c3308b7
fix getNewMessagesStream
mattapperson 4b288a9
need a longer timeout
mattapperson 4e96888
unskip tests that now work
mattapperson 8f0d240
add error expectation
mattapperson 21df4ea
cleanup
mattapperson a23183f
longer timeout
mattapperson 306b3b0
add env protection from log spam
mattapperson ad22de4
filename change
mattapperson 7b03504
AGENTS -> CLAUDE
subtleGradient 14b3340
cleanup clod
subtleGradient feb5273
cleanup
subtleGradient 7a42ef6
zeditor settings
subtleGradient f530180
TOOLS -> TTools
subtleGradient a635ca1
nits--
subtleGradient 5d00372
typecheck
subtleGradient 1941871
unbreak bad edit
subtleGradient c5d243c
Add test scripts and fix whitespace
subtleGradient 33a174c
use typeguard
subtleGradient 880135c
deflake test
subtleGradient File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "tab_size": 2, | ||
| "project_name": "@openrouter/sdk", | ||
| "formatter": { | ||
| "language_server": { | ||
| "name": "eslint" | ||
| } | ||
| }, | ||
| "language_servers": ["!biome", "..."] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| CLAUDE.md |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Overview | ||
|
|
||
| This is the OpenRouter TypeScript SDK - a type-safe toolkit for building AI applications with access to 300+ language models. The SDK is **generated using Speakeasy** from an OpenAPI specification, with custom hand-written features for tool orchestration, async parameter resolution, and streaming. | ||
|
|
||
| **IMPORTANT**: Most code in this repository is auto-generated by Speakeasy. Do not manually edit generated files - changes will be overwritten. See the "Code Generation" section below for how to make changes. | ||
|
|
||
| ## Common Commands | ||
|
|
||
| ### Building | ||
| ```bash | ||
| pnpm run build | ||
| ``` | ||
| Compiles TypeScript to `esm/` directory using `tsc`. | ||
|
|
||
| ### Linting | ||
| ```bash | ||
| pnpm run lint | ||
| ``` | ||
| **Note**: This project uses **ESLint** (not Biome). Configuration is in `eslint.config.mjs`. | ||
|
|
||
| ### Testing | ||
| ```bash | ||
| # Run all tests | ||
| npx vitest | ||
|
|
||
| # Run specific test file | ||
| npx vitest tests/e2e/call-model.test.ts | ||
|
|
||
| # Run tests in watch mode | ||
| npx vitest --watch | ||
| ``` | ||
|
|
||
| Tests require an OpenRouter API key: | ||
| 1. Copy `.env.example` to `.env` | ||
| 2. Add your API key: `OPENROUTER_API_KEY=your_key_here` | ||
|
|
||
| Test organization: | ||
| - `tests/e2e/` - End-to-end integration tests | ||
| - `tests/unit/` - Unit tests | ||
| - `tests/funcs/` - Function-specific tests | ||
|
|
||
| ### Publishing | ||
| ```bash | ||
| pnpm run prepublishOnly | ||
| ``` | ||
| This runs the build automatically before publishing. | ||
|
|
||
| ## Code Generation with Speakeasy | ||
|
|
||
| The SDK is generated from `.speakeasy/in.openapi.yaml` using [Speakeasy](https://www.speakeasy.com/docs). | ||
|
|
||
| ### Generated vs Hand-Written Code | ||
|
|
||
| **Generated Files** (DO NOT EDIT - will be overwritten): | ||
| - `src/models/` - Type definitions from OpenAPI schemas | ||
| - `src/funcs/*Send.ts`, `src/funcs/*Get.ts`, etc. - Most API operation functions | ||
| - `src/sdk/` - SDK service classes | ||
| - `src/hooks/registration.ts` - Hook registration | ||
|
|
||
| **Hand-Written Files** (safe to edit): | ||
| - `src/lib/` - All library utilities and helpers | ||
| - `src/funcs/call-model.ts` - High-level model calling abstraction | ||
| - `src/index.ts` - Main exports | ||
| - `src/hooks/hooks.ts` and `src/hooks/types.ts` - Custom hooks | ||
|
|
||
| ### Regenerating the SDK | ||
|
|
||
| To regenerate after updating the OpenAPI spec: | ||
| ```bash | ||
| speakeasy run | ||
| ``` | ||
|
|
||
| This reads configuration from `.speakeasy/gen.yaml` and workflow from `.speakeasy/workflow.yaml`. | ||
|
|
||
| ### Making Changes to Generated Code | ||
|
|
||
| 1. **For type/schema changes**: Update `.speakeasy/in.openapi.yaml` and regenerate | ||
| 2. **For overlays**: Edit files in `.speakeasy/overlays/` to apply transformations | ||
| 3. **For generation config**: Edit `.speakeasy/gen.yaml` | ||
| 4. **Always commit both** the OpenAPI spec changes AND the regenerated code | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Core Abstractions | ||
|
|
||
| **callModel** (`src/funcs/call-model.ts`) | ||
| - High-level function for making model requests with tools | ||
| - Returns a `ModelResult` wrapper with multiple consumption patterns | ||
| - Supports async parameter resolution and automatic tool execution | ||
| - Example consumption: `.getText()`, `.getTextStream()`, `.getToolStream()`, etc. | ||
|
|
||
| **ModelResult** (`src/lib/model-result.ts`) | ||
| - Wraps streaming responses with multiple consumption patterns | ||
| - Handles automatic tool execution and turn orchestration | ||
| - 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 | ||
| - Three tool types: | ||
| - **Regular tools** (`execute: function`) - auto-executed, return final result | ||
| - **Generator tools** (`execute: async generator`) - stream preliminary results | ||
| - **Manual tools** (`execute: false`) - return tool calls without execution | ||
| - Tool orchestrator (`src/lib/tool-orchestrator.ts`) manages multi-turn conversations | ||
|
|
||
| **Async Parameter Resolution** (`src/lib/async-params.ts`) | ||
| - Any parameter in `CallModelInput` can be a function: `(ctx: TurnContext) => value` | ||
| - Functions resolved before each turn, allowing dynamic parameter adjustment | ||
| - Supports both sync and async functions | ||
| - Example: `model: (ctx) => ctx.numberOfTurns > 3 ? 'gpt-4' : 'gpt-3.5-turbo'` | ||
|
|
||
| **Next Turn Params** (`src/lib/next-turn-params.ts`) | ||
| - Tools can define `nextTurnParams` to modify request parameters after execution | ||
| - Functions receive tool input and can return parameter updates | ||
| - Applied after tool execution, before next API request | ||
| - Example: Increase temperature after seeing tool results | ||
|
|
||
| **Stop Conditions** (`src/lib/stop-conditions.ts`) | ||
| - Control when tool execution loops terminate | ||
| - Built-in helpers: `stepCountIs()`, `hasToolCall()`, `maxTokensUsed()`, `maxCost()`, `finishReasonIs()` | ||
| - Custom conditions receive full step history | ||
| - Default: `stepCountIs(5)` if not specified | ||
|
|
||
| ## Message Format Compatibility | ||
|
|
||
| The SDK supports multiple message formats: | ||
|
|
||
| - **OpenRouter format** (native) | ||
| - **Claude format** via `fromClaudeMessages()` / `toClaudeMessage()` (`src/lib/anthropic-compat.ts`) | ||
| - **OpenAI Chat format** via `fromChatMessages()` / `toChatMessage()` (`src/lib/chat-compat.ts`) | ||
|
|
||
| These converters handle content types, tool calls, and format-specific features. | ||
|
|
||
| ## Streaming Architecture | ||
|
|
||
| **ReusableReadableStream** (`src/lib/reusable-stream.ts`) | ||
|
|
||
| - Caches stream events to enable multiple independent consumers | ||
| - Critical for allowing parallel consumption patterns (text + tools + reasoning) | ||
| - Handles both SSE and standard ReadableStream | ||
|
|
||
| **Stream Transformers** (`src/lib/stream-transformers.ts`) | ||
|
|
||
| - Extract specific data from response streams | ||
| - `extractTextDeltas()`, `extractReasoningDeltas()`, `extractToolDeltas()` | ||
| - Build higher-level streams for different consumption patterns | ||
| - Handle both streaming and non-streaming responses uniformly | ||
|
|
||
| ## Development Workflow | ||
|
|
||
| ### When Adding New Features | ||
|
|
||
| 1. **If it's an API change**: Update `.speakeasy/in.openapi.yaml` in the monorepo (see `/Users/mattapperson/Development/CLAUDE.md` for monorepo workflow) | ||
| 2. **If it's SDK functionality**: Add to `src/lib/` or extend existing hand-written files | ||
| 3. **Add tests** to appropriate directory (`tests/e2e/`, `tests/unit/`) | ||
| 4. **Update examples** if user-facing (in `examples/`) | ||
|
|
||
| ### When Fixing Bugs | ||
|
|
||
| 1. **In generated code**: Fix the OpenAPI spec or Speakeasy generation config, then regenerate | ||
| 2. **In hand-written code**: Fix directly in `src/lib/` or other hand-written files | ||
| 3. **Add regression test** to prevent reoccurrence | ||
|
|
||
| ### Running Examples | ||
|
|
||
| ```bash | ||
| cd examples | ||
| # Set your API key in .env first | ||
| node --loader ts-node/esm call-model.example.ts | ||
| ``` | ||
|
|
||
| Examples demonstrate: | ||
| - `call-model.example.ts` - Basic usage | ||
| - `call-model-typed-tool-calling.example.ts` - Type-safe tools | ||
| - `anthropic-multimodal-tools.example.ts` - Multimodal inputs with tools | ||
| - `anthropic-reasoning.example.ts` - Extended thinking/reasoning | ||
| - `chat-reasoning.example.ts` - Reasoning with chat format | ||
| - `tools-example.ts` - Comprehensive tool usage | ||
|
|
||
| ## TypeScript Configuration | ||
|
|
||
| - **Target**: ES2020, module: Node16 | ||
| - **Strict mode**: Enabled with strictest settings from tsconfig/bases | ||
| - **Output**: `esm/` directory with declaration files | ||
| - **Module format**: ESM only (no CommonJS) | ||
|
|
||
| Key compiler options: | ||
| - `exactOptionalPropertyTypes: true` - Strict optional handling | ||
| - `noUncheckedIndexedAccess: true` - Array access safety | ||
| - `isolatedModules: true` - Required for module transforms | ||
|
|
||
| ## Testing Strategy | ||
|
|
||
| Tests use Vitest with: | ||
| - 30s timeout for API calls | ||
| - Environment variables from `.env` | ||
| - Type checking enabled for test files | ||
|
|
||
| E2E tests (`tests/e2e/`) make real API calls and test: | ||
| - Basic chat completions | ||
| - Tool execution flows | ||
| - Streaming responses | ||
| - Multi-turn conversations | ||
| - Different message formats | ||
|
|
||
| ## Package Structure | ||
|
|
||
| This is an ES Module (ESM) package with multiple exports: | ||
| - `@openrouter/sdk` - Main SDK | ||
| - `@openrouter/sdk/types` - Type definitions | ||
| - `@openrouter/sdk/models` - Model types | ||
| - `@openrouter/sdk/models/operations` - Operation types | ||
| - `@openrouter/sdk/models/errors` - Error types | ||
|
|
||
| The package uses conditional exports in `package.json` to map source files to build outputs. | ||
mattapperson marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.