@openrouter/sdk 0.3.7 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.zed/settings.json +10 -0
- package/_speakeasy/.github/action-inputs-config.json +53 -0
- package/_speakeasy/.github/action-security-config.json +88 -0
- package/esm/funcs/call-model.d.ts +94 -9
- package/esm/funcs/call-model.js +102 -120
- package/esm/index.d.ts +20 -8
- package/esm/index.js +20 -7
- package/esm/lib/anthropic-compat.d.ts +6 -2
- package/esm/lib/anthropic-compat.js +117 -98
- package/esm/lib/async-params.d.ts +53 -0
- package/esm/lib/async-params.js +76 -0
- package/esm/lib/chat-compat.js +4 -0
- package/esm/lib/claude-constants.d.ts +22 -0
- package/esm/lib/claude-constants.js +20 -0
- package/esm/lib/claude-type-guards.d.ts +10 -0
- package/esm/lib/claude-type-guards.js +70 -0
- package/esm/lib/config.d.ts +4 -2
- package/esm/lib/config.js +2 -2
- package/esm/lib/model-result.d.ts +18 -25
- package/esm/lib/model-result.js +137 -176
- package/esm/lib/next-turn-params.d.ts +30 -0
- package/esm/lib/next-turn-params.js +129 -0
- package/esm/lib/reusable-stream.js +10 -10
- package/esm/lib/stop-conditions.d.ts +80 -0
- package/esm/lib/stop-conditions.js +104 -0
- package/esm/lib/stream-transformers.d.ts +3 -3
- package/esm/lib/stream-transformers.js +311 -260
- package/esm/lib/stream-type-guards.d.ts +29 -0
- package/esm/lib/stream-type-guards.js +109 -0
- package/esm/lib/tool-executor.d.ts +9 -7
- package/esm/lib/tool-executor.js +7 -1
- package/esm/lib/tool-orchestrator.d.ts +7 -7
- package/esm/lib/tool-orchestrator.js +38 -10
- package/esm/lib/tool-types.d.ts +163 -29
- package/esm/lib/tool-types.js +6 -0
- package/esm/lib/tool.d.ts +99 -0
- package/esm/lib/tool.js +71 -0
- package/esm/lib/turn-context.d.ts +50 -0
- package/esm/lib/turn-context.js +59 -0
- package/esm/sdk/sdk.d.ts +3 -9
- package/jsr.json +1 -1
- package/package.json +6 -3
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { convertToClaudeMessage } from
|
|
1
|
+
import { OpenResponsesEasyInputMessageRoleAssistant, OpenResponsesEasyInputMessageRoleUser, } from '../models/openresponseseasyinputmessage.js';
|
|
2
|
+
import { OpenResponsesFunctionCallOutputType } from '../models/openresponsesfunctioncalloutput.js';
|
|
3
|
+
import { OpenResponsesInputMessageItemRoleUser, OpenResponsesInputMessageItemRoleDeveloper } from '../models/openresponsesinputmessageitem.js';
|
|
4
|
+
import { convertToClaudeMessage } from './stream-transformers.js';
|
|
5
5
|
/**
|
|
6
6
|
* Maps Claude role strings to OpenResponses role types
|
|
7
7
|
*/
|
|
8
8
|
function mapClaudeRole(role) {
|
|
9
|
-
if (role ===
|
|
9
|
+
if (role === 'user') {
|
|
10
10
|
return OpenResponsesEasyInputMessageRoleUser.User;
|
|
11
11
|
}
|
|
12
12
|
return OpenResponsesEasyInputMessageRoleAssistant.Assistant;
|
|
@@ -36,6 +36,10 @@ function createFunctionCallOutput(callId, output) {
|
|
|
36
36
|
* This function transforms ClaudeMessageParam[] (Anthropic SDK format) to
|
|
37
37
|
* OpenResponsesInput format that can be passed directly to callModel().
|
|
38
38
|
*
|
|
39
|
+
* Note: Some Claude features are lost in conversion as OpenRouter doesn't support them:
|
|
40
|
+
* - cache_control on content blocks
|
|
41
|
+
* - is_error flag on tool_result blocks
|
|
42
|
+
*
|
|
39
43
|
* @example
|
|
40
44
|
* ```typescript
|
|
41
45
|
* import { fromClaudeMessages } from '@openrouter/sdk';
|
|
@@ -55,124 +59,139 @@ export function fromClaudeMessages(messages) {
|
|
|
55
59
|
const result = [];
|
|
56
60
|
for (const msg of messages) {
|
|
57
61
|
const { role, content } = msg;
|
|
58
|
-
if (typeof content ===
|
|
62
|
+
if (typeof content === 'string') {
|
|
59
63
|
result.push(createEasyInputMessage(role, content));
|
|
60
64
|
continue;
|
|
61
65
|
}
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
// Separate content blocks into categories for clearer processing
|
|
67
|
+
const textBlocks = [];
|
|
68
|
+
const imageBlocks = [];
|
|
69
|
+
const toolUseBlocks = [];
|
|
70
|
+
const toolResultBlocks = [];
|
|
64
71
|
for (const block of content) {
|
|
65
72
|
switch (block.type) {
|
|
66
|
-
case 'text':
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
case 'text':
|
|
74
|
+
textBlocks.push(block);
|
|
75
|
+
break;
|
|
76
|
+
case 'image':
|
|
77
|
+
imageBlocks.push(block);
|
|
78
|
+
break;
|
|
79
|
+
case 'tool_use':
|
|
80
|
+
toolUseBlocks.push(block);
|
|
73
81
|
break;
|
|
82
|
+
case 'tool_result':
|
|
83
|
+
toolResultBlocks.push(block);
|
|
84
|
+
break;
|
|
85
|
+
default: {
|
|
86
|
+
// Exhaustiveness check - TypeScript will error if we don't handle all block types
|
|
87
|
+
const exhaustiveCheck = block;
|
|
88
|
+
throw new Error(`Unhandled content block type: ${JSON.stringify(exhaustiveCheck)}`);
|
|
74
89
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Process tool use blocks first (they go directly to result)
|
|
93
|
+
for (const toolUseBlock of toolUseBlocks) {
|
|
94
|
+
result.push({
|
|
95
|
+
type: 'function_call',
|
|
96
|
+
callId: toolUseBlock.id,
|
|
97
|
+
name: toolUseBlock.name,
|
|
98
|
+
arguments: JSON.stringify(toolUseBlock.input),
|
|
99
|
+
id: toolUseBlock.id,
|
|
100
|
+
status: 'completed',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Process tool result blocks
|
|
104
|
+
for (const toolResultBlock of toolResultBlocks) {
|
|
105
|
+
let toolOutput = '';
|
|
106
|
+
if (typeof toolResultBlock.content === 'string') {
|
|
107
|
+
toolOutput = toolResultBlock.content;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Extract text and handle images separately
|
|
111
|
+
const textParts = [];
|
|
112
|
+
const imageParts = [];
|
|
113
|
+
for (const part of toolResultBlock.content) {
|
|
114
|
+
if (part.type === 'text') {
|
|
115
|
+
textParts.push(part.text);
|
|
85
116
|
}
|
|
86
|
-
else if (
|
|
87
|
-
|
|
88
|
-
const dataUri = `data:${imageBlock.source.media_type};base64,${imageBlock.source.data}`;
|
|
89
|
-
contentItems.push({
|
|
90
|
-
type: 'input_image',
|
|
91
|
-
detail: 'auto',
|
|
92
|
-
imageUrl: dataUri,
|
|
93
|
-
});
|
|
117
|
+
else if (part.type === 'image') {
|
|
118
|
+
imageParts.push(part);
|
|
94
119
|
}
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
case 'tool_use': {
|
|
98
|
-
const toolUseBlock = block;
|
|
99
|
-
// Map to OpenResponsesFunctionToolCall
|
|
100
|
-
result.push({
|
|
101
|
-
type: 'function_call',
|
|
102
|
-
callId: toolUseBlock.id,
|
|
103
|
-
name: toolUseBlock.name,
|
|
104
|
-
arguments: JSON.stringify(toolUseBlock.input),
|
|
105
|
-
id: toolUseBlock.id,
|
|
106
|
-
status: 'completed', // Tool use in conversation history is already completed
|
|
107
|
-
});
|
|
108
|
-
break;
|
|
109
120
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
toolOutput = textParts.join('');
|
|
122
|
+
// Map images to image_generation_call items
|
|
123
|
+
imageParts.forEach((imagePart, i) => {
|
|
124
|
+
let imageUrl;
|
|
125
|
+
if (imagePart.source.type === 'url') {
|
|
126
|
+
imageUrl = imagePart.source.url;
|
|
115
127
|
}
|
|
116
|
-
else {
|
|
117
|
-
|
|
118
|
-
const textParts = [];
|
|
119
|
-
const imageParts = [];
|
|
120
|
-
for (const part of toolResultBlock.content) {
|
|
121
|
-
if (part.type === 'text') {
|
|
122
|
-
textParts.push(part.text);
|
|
123
|
-
}
|
|
124
|
-
else if (part.type === 'image') {
|
|
125
|
-
imageParts.push(part);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
toolOutput = textParts.join('');
|
|
129
|
-
// Map images to image_generation_call items
|
|
130
|
-
for (const imagePart of imageParts) {
|
|
131
|
-
const imageUrl = imagePart.source.type === 'url'
|
|
132
|
-
? imagePart.source.url
|
|
133
|
-
: `data:${imagePart.source.media_type};base64,${imagePart.source.data}`;
|
|
134
|
-
result.push({
|
|
135
|
-
type: 'image_generation_call',
|
|
136
|
-
id: `${toolResultBlock.tool_use_id}-image-${imageParts.indexOf(imagePart)}`,
|
|
137
|
-
result: imageUrl,
|
|
138
|
-
status: 'completed',
|
|
139
|
-
});
|
|
140
|
-
}
|
|
128
|
+
else if (imagePart.source.type === 'base64') {
|
|
129
|
+
imageUrl = `data:${imagePart.source.media_type};base64,${imagePart.source.data}`;
|
|
141
130
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
else {
|
|
132
|
+
const exhaustiveCheck = imagePart.source;
|
|
133
|
+
throw new Error(`Unhandled image source type: ${exhaustiveCheck}`);
|
|
145
134
|
}
|
|
146
|
-
|
|
135
|
+
result.push({
|
|
136
|
+
type: 'image_generation_call',
|
|
137
|
+
id: `${toolResultBlock.tool_use_id}-image-${i}`,
|
|
138
|
+
result: imageUrl,
|
|
139
|
+
status: 'completed',
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Add the function call output for the text portion (if any)
|
|
144
|
+
if (toolOutput.length > 0) {
|
|
145
|
+
result.push(createFunctionCallOutput(toolResultBlock.tool_use_id, toolOutput));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Process text and image blocks (these become message content)
|
|
149
|
+
if (textBlocks.length > 0 || imageBlocks.length > 0) {
|
|
150
|
+
const contentItems = [];
|
|
151
|
+
// Add text blocks
|
|
152
|
+
for (const textBlock of textBlocks) {
|
|
153
|
+
contentItems.push({
|
|
154
|
+
type: 'input_text',
|
|
155
|
+
text: textBlock.text,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// Add image blocks
|
|
159
|
+
for (const imageBlock of imageBlocks) {
|
|
160
|
+
let imageUrl;
|
|
161
|
+
if (imageBlock.source.type === 'url') {
|
|
162
|
+
imageUrl = imageBlock.source.url;
|
|
147
163
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
throw new Error(`Unhandled content block type: ${_exhaustiveCheck.type}`);
|
|
164
|
+
else if (imageBlock.source.type === 'base64') {
|
|
165
|
+
imageUrl = `data:${imageBlock.source.media_type};base64,${imageBlock.source.data}`;
|
|
151
166
|
}
|
|
167
|
+
else {
|
|
168
|
+
const exhaustiveCheck = imageBlock.source;
|
|
169
|
+
throw new Error(`Unhandled image source type: ${exhaustiveCheck}`);
|
|
170
|
+
}
|
|
171
|
+
contentItems.push({
|
|
172
|
+
type: 'input_image',
|
|
173
|
+
detail: 'auto',
|
|
174
|
+
imageUrl,
|
|
175
|
+
});
|
|
152
176
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (hasStructuredContent) {
|
|
157
|
-
// Use OpenResponsesInputMessageItem for messages with images
|
|
158
|
-
const messageRole = role === 'user'
|
|
159
|
-
? OpenResponsesInputMessageItemRoleUser.User
|
|
160
|
-
: role === 'assistant'
|
|
161
|
-
? OpenResponsesInputMessageItemRoleSystem.System // Assistant messages treated as system in this context
|
|
162
|
-
: OpenResponsesInputMessageItemRoleSystem.System;
|
|
177
|
+
// Determine output format based on content
|
|
178
|
+
if (imageBlocks.length > 0) {
|
|
179
|
+
// Use structured format for messages with images
|
|
163
180
|
result.push({
|
|
164
181
|
type: 'message',
|
|
165
|
-
role:
|
|
182
|
+
role: role === 'user'
|
|
183
|
+
? OpenResponsesInputMessageItemRoleUser.User
|
|
184
|
+
: OpenResponsesInputMessageItemRoleDeveloper.Developer,
|
|
166
185
|
content: contentItems,
|
|
167
186
|
});
|
|
168
187
|
}
|
|
169
188
|
else {
|
|
170
|
-
// Use simple format for text-only messages
|
|
189
|
+
// Use simple string format for text-only messages
|
|
171
190
|
const textContent = contentItems
|
|
172
191
|
.filter((item) => item.type === 'input_text')
|
|
173
|
-
.map(item => item.text)
|
|
192
|
+
.map((item) => item.text)
|
|
174
193
|
.join('');
|
|
175
|
-
if (textContent) {
|
|
194
|
+
if (textContent.length > 0) {
|
|
176
195
|
result.push(createEasyInputMessage(role, textContent));
|
|
177
196
|
}
|
|
178
197
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type * as models from '../models/index.js';
|
|
2
|
+
import type { StopWhen, Tool, TurnContext } from './tool-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A field can be either a value of type T or a function that computes T
|
|
5
|
+
*/
|
|
6
|
+
export type FieldOrAsyncFunction<T> = T | ((context: TurnContext) => T | Promise<T>);
|
|
7
|
+
/**
|
|
8
|
+
* Input type for callModel function
|
|
9
|
+
* Each field can independently be a static value or a function that computes the value
|
|
10
|
+
* Generic over TTools to enable proper type inference for stopWhen conditions
|
|
11
|
+
*/
|
|
12
|
+
export type CallModelInput<TTools extends readonly Tool[] = readonly Tool[]> = {
|
|
13
|
+
[K in keyof Omit<models.OpenResponsesRequest, 'stream' | 'tools'>]?: FieldOrAsyncFunction<models.OpenResponsesRequest[K]>;
|
|
14
|
+
} & {
|
|
15
|
+
tools?: TTools;
|
|
16
|
+
stopWhen?: StopWhen<TTools>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Resolved CallModelInput (all functions evaluated to values)
|
|
20
|
+
* This is the type after all async functions have been resolved to their values
|
|
21
|
+
*/
|
|
22
|
+
export type ResolvedCallModelInput = Omit<models.OpenResponsesRequest, 'stream' | 'tools'> & {
|
|
23
|
+
tools?: never;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Resolve all async functions in CallModelInput to their values
|
|
27
|
+
*
|
|
28
|
+
* @param input - Input with possible functions
|
|
29
|
+
* @param context - Turn context for function execution
|
|
30
|
+
* @returns Resolved input with all values (no functions)
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const resolved = await resolveAsyncFunctions(
|
|
35
|
+
* {
|
|
36
|
+
* model: 'gpt-4',
|
|
37
|
+
* temperature: (ctx) => ctx.numberOfTurns * 0.1,
|
|
38
|
+
* input: 'Hello',
|
|
39
|
+
* },
|
|
40
|
+
* { numberOfTurns: 2, messageHistory: [] }
|
|
41
|
+
* );
|
|
42
|
+
* // resolved.temperature === 0.2
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveAsyncFunctions(input: CallModelInput, context: TurnContext): Promise<ResolvedCallModelInput>;
|
|
46
|
+
/**
|
|
47
|
+
* Check if input has any async functions that need resolution
|
|
48
|
+
*
|
|
49
|
+
* @param input - Input to check
|
|
50
|
+
* @returns True if any field is a function
|
|
51
|
+
*/
|
|
52
|
+
export declare function hasAsyncFunctions(input: unknown): boolean;
|
|
53
|
+
//# sourceMappingURL=async-params.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if a value is a parameter function
|
|
3
|
+
* Parameter functions take TurnContext and return a value or promise
|
|
4
|
+
*/
|
|
5
|
+
function isParameterFunction(value) {
|
|
6
|
+
return typeof value === 'function';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Build a resolved request object from entries
|
|
10
|
+
* This validates the structure matches the expected ResolvedCallModelInput shape
|
|
11
|
+
*/
|
|
12
|
+
function buildResolvedRequest(entries) {
|
|
13
|
+
const obj = Object.fromEntries(entries);
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve all async functions in CallModelInput to their values
|
|
18
|
+
*
|
|
19
|
+
* @param input - Input with possible functions
|
|
20
|
+
* @param context - Turn context for function execution
|
|
21
|
+
* @returns Resolved input with all values (no functions)
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const resolved = await resolveAsyncFunctions(
|
|
26
|
+
* {
|
|
27
|
+
* model: 'gpt-4',
|
|
28
|
+
* temperature: (ctx) => ctx.numberOfTurns * 0.1,
|
|
29
|
+
* input: 'Hello',
|
|
30
|
+
* },
|
|
31
|
+
* { numberOfTurns: 2, messageHistory: [] }
|
|
32
|
+
* );
|
|
33
|
+
* // resolved.temperature === 0.2
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export async function resolveAsyncFunctions(input, context) {
|
|
37
|
+
// Build array of resolved entries
|
|
38
|
+
const resolvedEntries = [];
|
|
39
|
+
// Iterate over all keys in the input
|
|
40
|
+
for (const [key, value] of Object.entries(input)) {
|
|
41
|
+
// Skip stopWhen - it's handled separately in ModelResult
|
|
42
|
+
// Note: tools are already in API format at this point (converted in callModel()), so we include them
|
|
43
|
+
if (key === 'stopWhen') {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (isParameterFunction(value)) {
|
|
47
|
+
try {
|
|
48
|
+
// Execute the function with context and store the result
|
|
49
|
+
const result = await Promise.resolve(value(context));
|
|
50
|
+
resolvedEntries.push([key, result]);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
// Wrap errors with context about which field failed
|
|
54
|
+
throw new Error(`Failed to resolve async function for field "${key}": ${error instanceof Error ? error.message : String(error)}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Not a function, use as-is
|
|
59
|
+
resolvedEntries.push([key, value]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return buildResolvedRequest(resolvedEntries);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if input has any async functions that need resolution
|
|
66
|
+
*
|
|
67
|
+
* @param input - Input to check
|
|
68
|
+
* @returns True if any field is a function
|
|
69
|
+
*/
|
|
70
|
+
export function hasAsyncFunctions(input) {
|
|
71
|
+
if (!input || typeof input !== 'object') {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return Object.values(input).some((value) => typeof value === 'function');
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=async-params.js.map
|
package/esm/lib/chat-compat.js
CHANGED
|
@@ -26,6 +26,10 @@ function mapChatRole(role) {
|
|
|
26
26
|
return OpenResponsesEasyInputMessageRoleAssistant.Assistant;
|
|
27
27
|
case "developer":
|
|
28
28
|
return OpenResponsesEasyInputMessageRoleDeveloper.Developer;
|
|
29
|
+
default: {
|
|
30
|
+
const exhaustiveCheck = role;
|
|
31
|
+
throw new Error(`Unhandled role type: ${exhaustiveCheck}`);
|
|
32
|
+
}
|
|
29
33
|
}
|
|
30
34
|
}
|
|
31
35
|
/**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude-specific content block types
|
|
3
|
+
* Used for detecting Claude message format
|
|
4
|
+
*/
|
|
5
|
+
export declare const ClaudeContentBlockType: {
|
|
6
|
+
readonly Text: "text";
|
|
7
|
+
readonly Image: "image";
|
|
8
|
+
readonly ToolUse: "tool_use";
|
|
9
|
+
readonly ToolResult: "tool_result";
|
|
10
|
+
};
|
|
11
|
+
export type ClaudeContentBlockType = (typeof ClaudeContentBlockType)[keyof typeof ClaudeContentBlockType];
|
|
12
|
+
/**
|
|
13
|
+
* Message roles that are NOT supported in Claude format
|
|
14
|
+
* Used for distinguishing Claude vs OpenAI format
|
|
15
|
+
*/
|
|
16
|
+
export declare const NonClaudeMessageRole: {
|
|
17
|
+
readonly System: "system";
|
|
18
|
+
readonly Developer: "developer";
|
|
19
|
+
readonly Tool: "tool";
|
|
20
|
+
};
|
|
21
|
+
export type NonClaudeMessageRole = (typeof NonClaudeMessageRole)[keyof typeof NonClaudeMessageRole];
|
|
22
|
+
//# sourceMappingURL=claude-constants.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude-specific content block types
|
|
3
|
+
* Used for detecting Claude message format
|
|
4
|
+
*/
|
|
5
|
+
export const ClaudeContentBlockType = {
|
|
6
|
+
Text: "text",
|
|
7
|
+
Image: "image",
|
|
8
|
+
ToolUse: "tool_use",
|
|
9
|
+
ToolResult: "tool_result",
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Message roles that are NOT supported in Claude format
|
|
13
|
+
* Used for distinguishing Claude vs OpenAI format
|
|
14
|
+
*/
|
|
15
|
+
export const NonClaudeMessageRole = {
|
|
16
|
+
System: "system",
|
|
17
|
+
Developer: "developer",
|
|
18
|
+
Tool: "tool",
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=claude-constants.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as models from "../models/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Check if input is in Claude message format
|
|
4
|
+
* Uses structural analysis to detect Claude-specific patterns
|
|
5
|
+
*
|
|
6
|
+
* @param input - Input to check
|
|
7
|
+
* @returns True if input appears to be Claude format
|
|
8
|
+
*/
|
|
9
|
+
export declare function isClaudeStyleMessages(input: unknown): input is models.ClaudeMessageParam[];
|
|
10
|
+
//# sourceMappingURL=claude-type-guards.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ClaudeContentBlockType, NonClaudeMessageRole, } from "./claude-constants.js";
|
|
2
|
+
function isRecord(value) {
|
|
3
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function isNonClaudeRole(role) {
|
|
6
|
+
return (role === NonClaudeMessageRole.System ||
|
|
7
|
+
role === NonClaudeMessageRole.Developer ||
|
|
8
|
+
role === NonClaudeMessageRole.Tool);
|
|
9
|
+
}
|
|
10
|
+
function isClaudeToolResultBlock(block) {
|
|
11
|
+
if (!isRecord(block))
|
|
12
|
+
return false;
|
|
13
|
+
return block["type"] === ClaudeContentBlockType.ToolResult;
|
|
14
|
+
}
|
|
15
|
+
function isClaudeImageBlockWithSource(block) {
|
|
16
|
+
if (!isRecord(block))
|
|
17
|
+
return false;
|
|
18
|
+
return (block["type"] === ClaudeContentBlockType.Image &&
|
|
19
|
+
"source" in block &&
|
|
20
|
+
isRecord(block["source"]));
|
|
21
|
+
}
|
|
22
|
+
function isClaudeToolUseBlockWithId(block) {
|
|
23
|
+
if (!isRecord(block))
|
|
24
|
+
return false;
|
|
25
|
+
return (block["type"] === ClaudeContentBlockType.ToolUse &&
|
|
26
|
+
"id" in block &&
|
|
27
|
+
typeof block["id"] === "string");
|
|
28
|
+
}
|
|
29
|
+
function hasClaudeSpecificBlocks(content) {
|
|
30
|
+
for (const block of content) {
|
|
31
|
+
if (isClaudeToolResultBlock(block))
|
|
32
|
+
return true;
|
|
33
|
+
if (isClaudeImageBlockWithSource(block))
|
|
34
|
+
return true;
|
|
35
|
+
if (isClaudeToolUseBlockWithId(block))
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if input is in Claude message format
|
|
42
|
+
* Uses structural analysis to detect Claude-specific patterns
|
|
43
|
+
*
|
|
44
|
+
* @param input - Input to check
|
|
45
|
+
* @returns True if input appears to be Claude format
|
|
46
|
+
*/
|
|
47
|
+
export function isClaudeStyleMessages(input) {
|
|
48
|
+
if (!Array.isArray(input) || input.length === 0) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
for (const msg of input) {
|
|
52
|
+
if (!isRecord(msg))
|
|
53
|
+
continue;
|
|
54
|
+
if (!("role" in msg))
|
|
55
|
+
continue;
|
|
56
|
+
if ("type" in msg)
|
|
57
|
+
continue; // Claude messages don't have top-level "type"
|
|
58
|
+
// If we find a non-Claude role, it's not Claude format
|
|
59
|
+
if (isNonClaudeRole(msg["role"])) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
// If we find Claude-specific content blocks, it's Claude format
|
|
63
|
+
const content = msg["content"];
|
|
64
|
+
if (Array.isArray(content) && hasClaudeSpecificBlocks(content)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=claude-type-guards.js.map
|
package/esm/lib/config.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SDKHooks } from "../hooks/hooks.js";
|
|
1
2
|
import { HTTPClient } from "./http.js";
|
|
2
3
|
import { Logger } from "./logger.js";
|
|
3
4
|
import { RetryConfig } from "./retries.js";
|
|
@@ -40,13 +41,14 @@ export type SDKOptions = {
|
|
|
40
41
|
retryConfig?: RetryConfig;
|
|
41
42
|
timeoutMs?: number;
|
|
42
43
|
debugLogger?: Logger;
|
|
44
|
+
hooks?: SDKHooks;
|
|
43
45
|
};
|
|
44
46
|
export declare function serverURLFromOptions(options: SDKOptions): URL | null;
|
|
45
47
|
export declare const SDK_METADATA: {
|
|
46
48
|
readonly language: "typescript";
|
|
47
49
|
readonly openapiDocVersion: "1.0.0";
|
|
48
|
-
readonly sdkVersion: "0.3.
|
|
50
|
+
readonly sdkVersion: "0.3.11";
|
|
49
51
|
readonly genVersion: "2.788.4";
|
|
50
|
-
readonly userAgent: "speakeasy-sdk/typescript 0.3.
|
|
52
|
+
readonly userAgent: "speakeasy-sdk/typescript 0.3.11 2.788.4 1.0.0 @openrouter/sdk";
|
|
51
53
|
};
|
|
52
54
|
//# sourceMappingURL=config.d.ts.map
|
package/esm/lib/config.js
CHANGED
|
@@ -26,8 +26,8 @@ export function serverURLFromOptions(options) {
|
|
|
26
26
|
export const SDK_METADATA = {
|
|
27
27
|
language: "typescript",
|
|
28
28
|
openapiDocVersion: "1.0.0",
|
|
29
|
-
sdkVersion: "0.3.
|
|
29
|
+
sdkVersion: "0.3.11",
|
|
30
30
|
genVersion: "2.788.4",
|
|
31
|
-
userAgent: "speakeasy-sdk/typescript 0.3.
|
|
31
|
+
userAgent: "speakeasy-sdk/typescript 0.3.11 2.788.4 1.0.0 @openrouter/sdk",
|
|
32
32
|
};
|
|
33
33
|
//# sourceMappingURL=config.js.map
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import type { OpenRouterCore } from
|
|
2
|
-
import type * as models from
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { OpenRouterCore } from '../core.js';
|
|
2
|
+
import type * as models from '../models/index.js';
|
|
3
|
+
import type { CallModelInput } from './async-params.js';
|
|
4
|
+
import type { RequestOptions } from './sdks.js';
|
|
5
|
+
import type { ResponseStreamEvent, InferToolEventsUnion, ParsedToolCall, StopWhen, Tool, ToolStreamEvent } from './tool-types.js';
|
|
6
|
+
export interface GetResponseOptions<TTools extends readonly Tool[]> {
|
|
7
|
+
request: CallModelInput<TTools>;
|
|
7
8
|
client: OpenRouterCore;
|
|
8
9
|
options?: RequestOptions;
|
|
9
|
-
tools?:
|
|
10
|
-
|
|
10
|
+
tools?: TTools;
|
|
11
|
+
stopWhen?: StopWhen<TTools>;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* A wrapper around a streaming response that provides multiple consumption patterns.
|
|
@@ -25,8 +26,10 @@ export interface GetResponseOptions {
|
|
|
25
26
|
*
|
|
26
27
|
* All consumption patterns can be used concurrently thanks to the underlying
|
|
27
28
|
* ReusableReadableStream implementation.
|
|
29
|
+
*
|
|
30
|
+
* @template TTools - The tools array type to enable typed tool calls and results
|
|
28
31
|
*/
|
|
29
|
-
export declare class ModelResult {
|
|
32
|
+
export declare class ModelResult<TTools extends readonly Tool[]> {
|
|
30
33
|
private reusableStream;
|
|
31
34
|
private streamPromise;
|
|
32
35
|
private textPromise;
|
|
@@ -36,7 +39,8 @@ export declare class ModelResult {
|
|
|
36
39
|
private finalResponse;
|
|
37
40
|
private preliminaryResults;
|
|
38
41
|
private allToolExecutionRounds;
|
|
39
|
-
|
|
42
|
+
private resolvedRequest;
|
|
43
|
+
constructor(options: GetResponseOptions<TTools>);
|
|
40
44
|
/**
|
|
41
45
|
* Type guard to check if a value is a non-streaming response
|
|
42
46
|
*/
|
|
@@ -71,7 +75,7 @@ export declare class ModelResult {
|
|
|
71
75
|
* Multiple consumers can iterate over this stream concurrently.
|
|
72
76
|
* Includes preliminary tool result events after tool execution.
|
|
73
77
|
*/
|
|
74
|
-
getFullResponsesStream(): AsyncIterableIterator<
|
|
78
|
+
getFullResponsesStream(): AsyncIterableIterator<ResponseStreamEvent<InferToolEventsUnion<TTools>>>;
|
|
75
79
|
/**
|
|
76
80
|
* Stream only text deltas as they arrive.
|
|
77
81
|
* This filters the full event stream to only yield text content.
|
|
@@ -95,30 +99,19 @@ export declare class ModelResult {
|
|
|
95
99
|
* - Tool call argument deltas as { type: "delta", content: string }
|
|
96
100
|
* - Preliminary results as { type: "preliminary_result", toolCallId, result }
|
|
97
101
|
*/
|
|
98
|
-
getToolStream(): AsyncIterableIterator<ToolStreamEvent
|
|
99
|
-
/**
|
|
100
|
-
* Stream events in chat format (compatibility layer).
|
|
101
|
-
* Note: This transforms responses API events into a chat-like format.
|
|
102
|
-
* Includes preliminary tool result events after tool execution.
|
|
103
|
-
*
|
|
104
|
-
* @remarks
|
|
105
|
-
* This is a compatibility method that attempts to transform the responses API
|
|
106
|
-
* stream into a format similar to the chat API. Due to differences in the APIs,
|
|
107
|
-
* this may not be a perfect mapping.
|
|
108
|
-
*/
|
|
109
|
-
getFullChatStream(): AsyncIterableIterator<ChatStreamEvent>;
|
|
102
|
+
getToolStream(): AsyncIterableIterator<ToolStreamEvent<InferToolEventsUnion<TTools>>>;
|
|
110
103
|
/**
|
|
111
104
|
* Get all tool calls from the completed response (before auto-execution).
|
|
112
105
|
* Note: If tools have execute functions, they will be automatically executed
|
|
113
106
|
* and this will return the tool calls from the initial response.
|
|
114
107
|
* Returns structured tool calls with parsed arguments.
|
|
115
108
|
*/
|
|
116
|
-
getToolCalls(): Promise<ParsedToolCall[]>;
|
|
109
|
+
getToolCalls(): Promise<ParsedToolCall<TTools[number]>[]>;
|
|
117
110
|
/**
|
|
118
111
|
* Stream structured tool call objects as they're completed.
|
|
119
112
|
* Each iteration yields a complete tool call with parsed arguments.
|
|
120
113
|
*/
|
|
121
|
-
getToolCallsStream(): AsyncIterableIterator<ParsedToolCall
|
|
114
|
+
getToolCallsStream(): AsyncIterableIterator<ParsedToolCall<TTools[number]>>;
|
|
122
115
|
/**
|
|
123
116
|
* Cancel the underlying stream and all consumers
|
|
124
117
|
*/
|