Skip to content

Commit b2d02b1

Browse files
author
OpenRouter Team
committed
Commits included in this export:
- b1edfb513a2f1f1056f7a0cf9d39d9c45272acc0 - b867adcde6b64f3f2a11c4626254b39098e4b0b4 - 21912c097b4066d109766c6b4492826595cd57c5 - bc1ed85adc976a4634ca8a41b82e4fc2c39a864f - 8d10b121356a215a589092326b8f604293147de1 - 7828708558cfa789b51d6d3ee35fc0e893dea32d - d145c89c941937a312ed1357590d2bfda9a3603d - 12f05b5dee397ead47cfcd545a7a2e3c7ff57524 - dd28f75a19a015809797c7abf3f8758f7c37262e - b8b107ca04e2e4dc39dd8c97c285dff665de6f05 - c96e569781e07ab44172d9c69940ec17bafd81f4 - c9d5a90e3c2b5077a2bdd49773f1a46d1a5a79c7 - cdf5dfb908ef3afe57e29b9c4e1bedcdd31c7c49 - 58b08f87116ceab9076de2fdc0a4c74c919b44c4 - 2592bdc8b4b7c695a3d689390aedc9a42914acc8 - 95dc994c2fcb701f3a8d8ffe410aa2e91ea8120b - a552a86da33c602a8f0eb8e40724d9154b63cac9 - 7b49f98f8599508b9aca6921a48d446ca04d41ce - 2841134445f6a925c9072b6eccb1be9adcf3797c - 5d59d49f32086b2f4d38961e4d11744bdbda72c1 - edeedb0ad02de9951408298c66a6a6ccbd683f7f - 037329dc548fbdefbfcc1d84d85c67d227afce0d - 67ac9ff744a5c802380876ebf56b939625a44e13 - 74c003f4ecf72520cb9097d38495f1f9839379a5 - 5140ef0b1fdbb58e8aa1d20ca08bdd948f4dadaf - a3d789c36cdaf821e400a6fe9eefbe1a82bc5819 - 2a87802bcec26e7e3cea535c680f4b71dbb10b15 - 16e9a45c7816adf1e33efce1e384eb9879dc2b28 - 7358fd8e8c7476dc6b75b300084e225ece79bceb - 8199c8abea6e6acefa8c37a1336a56c7fcdd3a07 - d17e8505a8d46baf3192a92a530986bbce7014b2 - 7ab5200031221f71aaff2503c9af1c706ccb7634 - 0f4cd4840b46f21e843d0d40bdaf587ba0e5b2cd - b19e35320304f4313b4fa27c5dc8d348e4a5a5c2 - 9994ceca26eab71d3b22a5de2f7fd530f21a071d - ee2da3156a55471cf3d3c66d4c00944eebdd898d - 0a4e2198ab076e9b8530bdf1cf481367b1fed971 - a5804a88b7417d2c18a741de8683fa3f59f29028 - bf787ed35487961a465347bde6d952f5b985ae53 - 6ece2ee3b6782c672d487f857d4b9a5255e97d27 - 57ff7bba84d38a88e31eeef75fa3d3de34f55af3 - afa7f5af2d4c9cbdf18bbafdb7ce70b882c02d10 - aae3911dcc666a818f9b58f3ca47a25de252c6da - 449925fbabb1b1c3eac565f0ee99176402e5762c - 491e5ac99a7a4b3f76e2a5e2dff3b833e3a1fbfb - e9f17b7f0df89e2159f37631fd0a890c0510401a - a28de4933b3212eb4c31601d07b0e9120f33aaa1 - 5657366b127cb27f2ae49dedf4cd776bb4c0bb5c - 18216342b2bd775c35b0b6619a24801224445de2 - 6590c4d866f9ff23fff051574e609c09ab8ddb12 - f0f552336ce1215d2ec768c0bdca5028a968680c - 70b651e298470af96f40625c6094cd4aae008483 - b395cc4176ff5decc52636ec18b6db8fe89d4ed1 - d0b664a88597f79c5b0d5f19a2179b6d8fabddbc - d3862269e3fa6e044cf7f3a307f5d8f07bff863f - 6c895dcb22935a2a164767c7d09840123b6fae8e - 86f3da290f484de3b6620c65c408d2a8437c0e67 - 21a4f580479b3b0fa2b4381802dbaf90eb005d2b - fb941b1ca6ce407fd344d1ba1efe0d443f0dddd0 - 20c2d10632637680294895ac242bca1805b52b7a - 20425ada8aa09714f5d46e151d4df55e950a34a1 - 716848405ea7296b735f8ed026d4da07b49a651f - 638eec62dcc7c000010a40962e61ec35e7e5d3a0 - 8ef06dcfce6842466412935d935a57ff57b10d76 - 72c52708b8f989005ca8837e5491462798a51e46 - ebaac50f2143ae5a6f3025e997aa1ad70d110a1f - ace3723b9883c46d2d7c33c21146a59d403093ef - 79cf17a40fed709c93b3f7e35d7065e76a355996 - 66fa5870420336037921914fd69e3a01e14223e4 - 95d711fd9ac03bd2831208b12c3841640464c093 - 779c34de0724d6b72150b39cd6193dd84625ddb8 - d91887e755fbb466326ed27b74a1dcd66f64639d - 762342705a61b57d39ddb50ff87dc3b41dfa8d32 - dc3fc7fea5df69c6a2ba7ab963607360d51ce714 - 8cd291839de1af3fa693b440f8ce73b888c83e92 - 5305e998238be4d4ae5874d218210802af8284d1 - c486224f2e25446c46dacdc8ef66def68751c7cb - 09977e4101e87d71dafd517143dcdec8ec348f5f - 04e44747bf25957653ed532a55c5c3457237db12 - 94074033e15542b78c82f8a4fe721be656aeaaed - b4a29e2f94d21ce28c17a0d1e34aad571cae31b6 - 3eb32d1a1d6f455ef4d4156dfa05b3d9b4330e3b - 62fc31a6f377fa3f9bf7cdd6a1b0a555ce7dfa97 - 10d043cc7a561a9e3226a25e43dc2a74ed167419 - 64c92062b38b2b481988d6aa154119e0f0c6d0a6 - 28e2a6583906a3e4620377eb632b7e080e8c562a - c5a629827086bf03db209ec2a6802f7a00aaa4d9 - 355ee32c288616d6748bf96eba4b200d30aeb3c4 - c1c61684e7c5a0de3389512b98bf48341702a811 - ca09b1fec0e853e83da1cc99e3ee7372da416cde - 3cc7f4a640cb3e409e922ffab55a9cc391f343c3 - 5cd07f0390a68cf207d0a5b7dbf0b5bc4fbc1896 - 9da85b69dac143f7cc120400e3cb810925b03c30 - f7c5993b6c51050037b226d62eae05a5b40cc789 - 367137f954370421ea18c7fb70f3dbc04502d937 - 9a2887f9eaea5aa23da00df8fe3e5bd2eeedb6d0 - b98f37c4cace1aa619eae3cca1196df64270cf8d - e50857cac2fb98556fe495c67030c89cd1db9037 - 6306c60742bcacd4e64175be6f654b48d52a110f - bfd9c158a2f31b11fd6b74dad48456c6ce5f162a (And 23 more changes) GitOrigin-RevId: b1edfb513a2f1f1056f7a0cf9d39d9c45272acc0
1 parent cb302be commit b2d02b1

15 files changed

Lines changed: 1212 additions & 75 deletions

.speakeasy/gen.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
lockVersion: 2.0.0
22
id: 8b6cd71c-ea04-44da-af45-e43968b5928d
33
management:
4-
docChecksum: ad7e31da06ce6399342bfab65b33bd39
4+
docChecksum: 73e9a83b95df662091c1325b5ce88d01
55
docVersion: 1.0.0
66
speakeasyVersion: 1.680.0
77
generationVersion: 2.788.4
@@ -11,9 +11,9 @@ management:
1111
installationURL: https://github.com/OpenRouterTeam/typescript-sdk
1212
published: true
1313
persistentEdits:
14-
generation_id: c0170acd-b4b0-4bfe-9c01-d03b417ce575
15-
pristine_commit_hash: 18739563fe8d4aa756fe9a335822327a1788b932
16-
pristine_tree_hash: 08bd942e9790b82b3751e5e9560b1b41b57f369f
14+
generation_id: edcf52a2-c8e9-43cb-a80f-d296b4d9ed06
15+
pristine_commit_hash: 885c59d790b52fef4b5963d7f55fdbeb82112bba
16+
pristine_tree_hash: 16d72f71a1da4981a63079fba699c3bb6da7f2e6
1717
features:
1818
typescript:
1919
acceptHeaders: 2.81.2
@@ -2336,8 +2336,8 @@ trackedFiles:
23362336
pristine_git_object: ccd5e5d812cb4d21a1013c89f04daad9d2f72190
23372337
src/index.ts:
23382338
id: c5fb850250c7
2339-
last_write_checksum: sha1:7ed2a5fa061eff70d4a20f33fc3269c60a5b1821
2340-
pristine_git_object: 35c2fb4c999bde2ca2b78b36088b052235d4bdff
2339+
last_write_checksum: sha1:8232ceb975ab0ad9abc06fe63c7ce79b18bb47d0
2340+
pristine_git_object: bb0c15148be25feb935e2d50c35c072b516cbcb5
23412341
src/lib/base64.ts:
23422342
id: "598522066688"
23432343
last_write_checksum: sha1:26b234d589cc15afab76ac7aaba1dd1bd4b4a84c

.speakeasy/in.openapi.yaml

100644100755
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9467,7 +9467,7 @@ paths:
94679467
x-speakeasy-name-override: create
94689468
x-speakeasy-stream-request-field: stream
94699469
tags:
9470-
- anthropic.messages
9470+
- Anthropic Messages
94719471
summary: Create a message
94729472
description: >-
94739473
Creates a message using the Anthropic Messages API format. Supports text, images, PDFs, tools, and extended
@@ -13581,6 +13581,8 @@ tags:
1358113581
description: API key management endpoints
1358213582
- name: Analytics
1358313583
description: Analytics and usage endpoints
13584+
- name: Anthropic Messages
13585+
description: Anthropic Messages endpoints
1358413586
- name: Chat
1358513587
description: Chat completion endpoints
1358613588
- name: Credits
@@ -13599,8 +13601,6 @@ tags:
1359913601
description: OAuth authentication endpoints
1360013602
- name: Providers
1360113603
description: Provider information endpoints
13602-
- name: anthropic.messages
13603-
description: anthropic.messages endpoints
1360413604
- name: beta.responses
1360513605
description: beta.responses endpoints
1360613606
x-fern-base-path: /

.speakeasy/out.openapi.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9491,7 +9491,7 @@ paths:
94919491
x-speakeasy-name-override: create
94929492
x-speakeasy-stream-request-field: stream
94939493
tags:
9494-
- anthropic.messages
9494+
- Anthropic Messages
94959495
summary: Create a message
94969496
description: >-
94979497
Creates a message using the Anthropic Messages API format. Supports text, images, PDFs, tools, and extended thinking.
@@ -13581,6 +13581,8 @@ tags:
1358113581
description: API key management endpoints
1358213582
- name: Analytics
1358313583
description: Analytics and usage endpoints
13584+
- name: Anthropic Messages
13585+
description: Anthropic Messages endpoints
1358413586
- name: Chat
1358513587
description: Chat completion endpoints
1358613588
- name: Credits
@@ -13599,8 +13601,6 @@ tags:
1359913601
description: OAuth authentication endpoints
1360013602
- name: Providers
1360113603
description: Provider information endpoints
13602-
- name: anthropic.messages
13603-
description: anthropic.messages endpoints
1360413604
- name: beta.responses
1360513605
description: beta.responses endpoints
1360613606
x-fern-base-path: /

.speakeasy/workflow.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ speakeasyVersion: 1.680.0
22
sources:
33
OpenRouter API:
44
sourceNamespace: open-router-chat-completions-api
5-
sourceRevisionDigest: sha256:918ea9897844be80c8981f374291b9731af294730415cfa27a98da846b02416a
6-
sourceBlobDigest: sha256:f10085a818483a67ece3ac3b9e8112cc26cffdab3ec7e583f1be2ca78fdc1c78
5+
sourceRevisionDigest: sha256:d0f1998ad92ab7b3f66f9d40fbde6c4b922137e768efb4adb91907d12c3bb235
6+
sourceBlobDigest: sha256:f5e39b02fd76a6dbd02df72a4d5b281038b40ecac762921a6157221e98485574
77
tags:
88
- latest
99
- 1.0.0
1010
targets:
1111
openrouter:
1212
source: OpenRouter API
1313
sourceNamespace: open-router-chat-completions-api
14-
sourceRevisionDigest: sha256:918ea9897844be80c8981f374291b9731af294730415cfa27a98da846b02416a
15-
sourceBlobDigest: sha256:f10085a818483a67ece3ac3b9e8112cc26cffdab3ec7e583f1be2ca78fdc1c78
14+
sourceRevisionDigest: sha256:d0f1998ad92ab7b3f66f9d40fbde6c4b922137e768efb4adb91907d12c3bb235
15+
sourceBlobDigest: sha256:f5e39b02fd76a6dbd02df72a4d5b281038b40ecac762921a6157221e98485574
1616
workflow:
1717
workflowVersion: 1.0.0
1818
speakeasyVersion: 1.680.0

package.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,16 @@
6464
"type": "git",
6565
"url": "https://github.com/OpenRouterTeam/typescript-sdk.git"
6666
},
67-
"scripts": {
68-
"lint": "eslint --cache --max-warnings=0 src",
69-
"build": "tsc",
70-
"typecheck": "tsc --noEmit",
71-
"prepublishOnly": "npm run build",
72-
"postinstall": "node scripts/check-types.js || true",
73-
"test": "vitest --run --project unit",
74-
"test:e2e": "vitest --run --project e2e",
75-
"test:watch": "vitest --watch --project unit"
76-
},
67+
"scripts": {
68+
"lint": "eslint --cache --max-warnings=0 src",
69+
"build": "tsc",
70+
"typecheck": "tsc --noEmit",
71+
"prepublishOnly": "npm run build",
72+
"postinstall": "node scripts/check-types.js || true",
73+
"test": "vitest --run --project unit",
74+
"test:e2e": "vitest --run --project e2e",
75+
"test:watch": "vitest --watch --project unit"
76+
},
7777
"peerDependencies": {},
7878
"devDependencies": {
7979
"@eslint/js": "^9.19.0",
@@ -89,4 +89,4 @@
8989
"zod": "^3.25.0 || ^4.0.0"
9090
},
9191
"packageManager": "pnpm@10.22.0"
92-
}
92+
}

src/lib/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* @generated-id: 320761608fb3
44
*/
55

6+
import type { Hook } from "../hooks/types.js";
67
import { HTTPClient } from "./http.js";
78
import { Logger } from "./logger.js";
89
import { RetryConfig } from "./retries.js";
@@ -51,6 +52,11 @@ export type SDKOptions = {
5152
retryConfig?: RetryConfig;
5253
timeoutMs?: number;
5354
debugLogger?: Logger;
55+
/**
56+
* Hooks for request/response lifecycle events.
57+
* Can be a single hook object or an array of hooks.
58+
*/
59+
hooks?: Hook | Hook[];
5460
};
5561

5662
export function serverURLFromOptions(options: SDKOptions): URL | null {

src/lib/model-result.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import { hasExecuteFunction } from './tool-types.js';
5454
import { isStopConditionMet, stepCountIs } from './stop-conditions.js';
5555
import {
5656
isOutputMessage,
57-
isFunctionCallOutputItem,
57+
isFunctionCallItem,
5858
isReasoningOutputItem,
5959
isWebSearchCallOutputItem,
6060
isFileSearchCallOutputItem,
@@ -1184,8 +1184,16 @@ export class ModelResult<TTools extends readonly Tool[]> {
11841184
// Execute tools if needed
11851185
await this.executeToolsIfNeeded();
11861186

1187-
// Yield function call outputs for each executed tool
1187+
// Yield function calls and outputs for each tool round
11881188
for (const round of this.allToolExecutionRounds) {
1189+
// Round 0's function_calls already yielded via buildItemsStream
1190+
if (round.round > 0) {
1191+
for (const item of round.response.output) {
1192+
if (isFunctionCallItem(item)) {
1193+
yield item;
1194+
}
1195+
}
1196+
}
11891197
for (const toolResult of round.toolResults) {
11901198
yield toolResult;
11911199
}
@@ -1196,7 +1204,7 @@ export class ModelResult<TTools extends readonly Tool[]> {
11961204
for (const item of this.finalResponse.output) {
11971205
if (
11981206
isOutputMessage(item) ||
1199-
isFunctionCallOutputItem(item) ||
1207+
isFunctionCallItem(item) ||
12001208
isReasoningOutputItem(item) ||
12011209
isWebSearchCallOutputItem(item) ||
12021210
isFileSearchCallOutputItem(item) ||

src/lib/sdks.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { SDKHooks } from "../hooks/hooks.js";
7-
import { HookContext } from "../hooks/types.js";
7+
import type { Hook, HookContext } from "../hooks/types.js";
88
import {
99
ConnectionError,
1010
InvalidRequestError,
@@ -87,17 +87,19 @@ export class ClientSDK {
8787
public readonly _options: SDKOptions & { hooks?: SDKHooks };
8888

8989
constructor(options: SDKOptions = {}) {
90-
const opt = options as unknown;
91-
if (
92-
typeof opt === "object"
93-
&& opt != null
94-
&& "hooks" in opt
95-
&& opt.hooks instanceof SDKHooks
96-
) {
97-
this.#hooks = opt.hooks;
90+
// Reuse existing SDKHooks if passed (for sub-SDKs)
91+
if (options.hooks instanceof SDKHooks) {
92+
this.#hooks = options.hooks;
9893
} else {
9994
this.#hooks = new SDKHooks();
95+
if (options.hooks) {
96+
const hooksArray = Array.isArray(options.hooks) ? options.hooks : [options.hooks];
97+
for (const hook of hooksArray) {
98+
this.#registerHook(hook);
99+
}
100+
}
100101
}
102+
101103
const defaultHttpClient = new HTTPClient();
102104
options.httpClient = options.httpClient || defaultHttpClient;
103105
options = this.#hooks.sdkInit(options);
@@ -117,6 +119,24 @@ export class ClientSDK {
117119
}
118120
}
119121

122+
#registerHook(hook: Hook): void {
123+
if ("sdkInit" in hook) {
124+
this.#hooks.registerSDKInitHook(hook);
125+
}
126+
if ("beforeCreateRequest" in hook) {
127+
this.#hooks.registerBeforeCreateRequestHook(hook);
128+
}
129+
if ("beforeRequest" in hook) {
130+
this.#hooks.registerBeforeRequestHook(hook);
131+
}
132+
if ("afterSuccess" in hook) {
133+
this.#hooks.registerAfterSuccessHook(hook);
134+
}
135+
if ("afterError" in hook) {
136+
this.#hooks.registerAfterErrorHook(hook);
137+
}
138+
}
139+
120140
public _createRequest(
121141
context: HookContext,
122142
conf: RequestConfig,

src/lib/stream-transformers.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
isResponseIncompleteEvent,
1313
isFunctionCallArgumentsDoneEvent,
1414
isOutputMessage,
15-
isFunctionCallOutputItem,
15+
isFunctionCallItem,
1616
isReasoningOutputItem,
1717
isWebSearchCallOutputItem,
1818
isFileSearchCallOutputItem,
@@ -234,7 +234,7 @@ function handleOutputItemAdded(
234234
};
235235
}
236236

237-
if (isFunctionCallOutputItem(item)) {
237+
if (isFunctionCallItem(item)) {
238238
// Use item.id if available (matches itemId in delta events), fall back to callId
239239
const itemKey = item.id ?? item.callId;
240240
itemsInProgress.set(itemKey, {
@@ -391,7 +391,7 @@ function handleOutputItemDone(
391391
return item;
392392
}
393393

394-
if (isFunctionCallOutputItem(item)) {
394+
if (isFunctionCallItem(item)) {
395395
// Use item.id if available (matches itemId in delta events), fall back to callId
396396
itemsInProgress.delete(item.id ?? item.callId);
397397
return item;
@@ -616,7 +616,7 @@ export function extractToolCallsFromResponse(
616616
const toolCalls: ParsedToolCall<Tool>[] = [];
617617

618618
for (const item of response.output) {
619-
if (isFunctionCallOutputItem(item)) {
619+
if (isFunctionCallItem(item)) {
620620
try {
621621
const parsedArguments = JSON.parse(item.arguments);
622622

@@ -670,7 +670,7 @@ export async function* buildToolCallStream(
670670

671671
switch (event.type) {
672672
case 'response.output_item.added': {
673-
if (isOutputItemAddedEvent(event) && event.item && isFunctionCallOutputItem(event.item)) {
673+
if (isOutputItemAddedEvent(event) && event.item && isFunctionCallItem(event.item)) {
674674
toolCallsInProgress.set(event.item.callId, {
675675
id: event.item.callId,
676676
name: event.item.name,
@@ -725,7 +725,7 @@ export async function* buildToolCallStream(
725725
}
726726

727727
case 'response.output_item.done': {
728-
if (isOutputItemDoneEvent(event) && event.item && isFunctionCallOutputItem(event.item)) {
728+
if (isOutputItemDoneEvent(event) && event.item && isFunctionCallItem(event.item)) {
729729
// Yield final tool call if we haven't already
730730
if (toolCallsInProgress.has(event.item.callId)) {
731731
try {
@@ -943,7 +943,7 @@ export function convertToClaudeMessage(
943943
}
944944

945945
case 'function_call': {
946-
if (isFunctionCallOutputItem(item)) {
946+
if (isFunctionCallItem(item)) {
947947
let parsedInput: Record<string, unknown>;
948948

949949
try {

src/lib/stream-type-guards.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function isOutputMessage(
7474
);
7575
}
7676

77-
export function isFunctionCallOutputItem(
77+
export function isFunctionCallItem(
7878
item: unknown
7979
): item is models.ResponsesOutputItemFunctionCall {
8080
return (

0 commit comments

Comments
 (0)