@opencode/ai 0.0.0-dev-20138 → 0.0.0-dev-20141
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/dist/image-client.d.ts +54 -21
- package/dist/image-client.js +14 -39
- package/dist/image.d.ts +13 -25
- package/dist/image.js +2 -13
- package/dist/media-client.d.ts +30 -0
- package/dist/media-client.js +51 -0
- package/dist/media-model.d.ts +9 -8
- package/dist/media-model.js +10 -10
- package/dist/promise.d.ts +26 -10
- package/dist/promise.js +15 -20
- package/dist/protocols/anthropic-messages.js +3 -6
- package/dist/protocols/bedrock-converse.js +5 -6
- package/dist/protocols/cartesia-speech.d.ts +16 -0
- package/dist/protocols/deepgram-speech.d.ts +16 -0
- package/dist/protocols/elevenlabs-speech.d.ts +16 -0
- package/dist/protocols/gemini.js +6 -6
- package/dist/protocols/google-speech.d.ts +16 -0
- package/dist/protocols/meta-responses.js +1 -2
- package/dist/protocols/mistral-chat.js +3 -6
- package/dist/protocols/open-responses.d.ts +1 -3
- package/dist/protocols/open-responses.js +3 -4
- package/dist/protocols/openai-chat.js +3 -4
- package/dist/protocols/openai-responses.js +7 -10
- package/dist/protocols/openai-speech.d.ts +16 -0
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-schema.js +10 -3
- package/dist/route/client.d.ts +2 -1
- package/dist/route/client.js +3 -1
- package/dist/route/media.d.ts +4 -14
- package/dist/route/media.js +1 -36
- package/dist/route/protocol.d.ts +3 -1
- package/dist/speech-client.d.ts +57 -14
- package/dist/speech-client.js +15 -20
- package/dist/speech.d.ts +176 -19
- package/dist/speech.js +11 -6
- package/dist/transcription-client.d.ts +73 -21
- package/dist/transcription-client.js +7 -39
- package/dist/transcription.d.ts +13 -25
- package/dist/transcription.js +2 -8
- package/dist/video-client.d.ts +50 -21
- package/dist/video-client.js +14 -35
- package/dist/video.d.ts +14 -22
- package/dist/video.js +13 -14
- package/package.json +3 -3
|
@@ -14,7 +14,6 @@ import { classifyProviderFailure } from "../provider-error.js";
|
|
|
14
14
|
import { effortUpdate, resolveEffortUpdates } from "../effort-updates.js";
|
|
15
15
|
import * as Cache from "./utils/cache.js";
|
|
16
16
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
17
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
18
17
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
19
18
|
const ADAPTER = "anthropic-messages";
|
|
20
19
|
export const DEFAULT_BASE_URL = "https://api.anthropic.com/v1";
|
|
@@ -408,10 +407,10 @@ const redactedDataFromMetadata = (metadata, key) => {
|
|
|
408
407
|
return undefined;
|
|
409
408
|
return typeof provider.redactedData === "string" ? provider.redactedData : undefined;
|
|
410
409
|
};
|
|
411
|
-
const lowerTool = (breakpoints, tool
|
|
410
|
+
const lowerTool = (breakpoints, tool) => ({
|
|
412
411
|
name: tool.name,
|
|
413
412
|
description: tool.description,
|
|
414
|
-
input_schema: inputSchema,
|
|
413
|
+
input_schema: tool.inputSchema,
|
|
415
414
|
cache_control: cacheControl(breakpoints, tool.cache),
|
|
416
415
|
});
|
|
417
416
|
const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("Anthropic Messages", toolChoice, {
|
|
@@ -910,9 +909,7 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
|
|
|
910
909
|
// over-mark we keep their tool hints and shed the message-tail ones first.
|
|
911
910
|
const breakpoints = Cache.newBreakpoints(ANTHROPIC_BREAKPOINT_CAP);
|
|
912
911
|
const flattened = ProviderShared.flattenToolRequest(updates.request);
|
|
913
|
-
const tools = flattened.tools.length === 0
|
|
914
|
-
? undefined
|
|
915
|
-
: flattened.tools.map((tool) => lowerTool(breakpoints, tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, request.model)));
|
|
912
|
+
const tools = flattened.tools.length === 0 ? undefined : flattened.tools.map((tool) => lowerTool(breakpoints, tool));
|
|
916
913
|
// Anthropic rejects tool_choice when tools are absent; "none" is only meaningful with tools present.
|
|
917
914
|
const toolChoice = tools === undefined || !request.toolChoice ? undefined : yield* lowerToolChoice(request.toolChoice);
|
|
918
915
|
const systemParts = request.system.filter((part) => part.text.length > 0);
|
|
@@ -11,7 +11,6 @@ import { BedrockCache } from "./utils/bedrock-cache.js";
|
|
|
11
11
|
import { BedrockMedia } from "./utils/bedrock-media.js";
|
|
12
12
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
13
13
|
import { MistralToolID } from "./utils/mistral-tool-id.js";
|
|
14
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
15
14
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
16
15
|
import { concatBytes } from "../utils/bytes.js";
|
|
17
16
|
const ADAPTER = "bedrock-converse";
|
|
@@ -156,17 +155,17 @@ const BedrockEvent = Schema.Struct({
|
|
|
156
155
|
// =============================================================================
|
|
157
156
|
// Request Lowering
|
|
158
157
|
// =============================================================================
|
|
159
|
-
const lowerToolSpec = (tool
|
|
158
|
+
const lowerToolSpec = (tool) => ({
|
|
160
159
|
toolSpec: {
|
|
161
160
|
name: tool.name,
|
|
162
161
|
...(tool.description.trim().length > 0 ? { description: tool.description } : {}),
|
|
163
|
-
inputSchema: { json: inputSchema },
|
|
162
|
+
inputSchema: { json: tool.inputSchema },
|
|
164
163
|
},
|
|
165
164
|
});
|
|
166
|
-
const lowerTools = (
|
|
165
|
+
const lowerTools = (breakpoints, tools) => {
|
|
167
166
|
const result = [];
|
|
168
167
|
for (const tool of tools) {
|
|
169
|
-
result.push(lowerToolSpec(tool
|
|
168
|
+
result.push(lowerToolSpec(tool));
|
|
170
169
|
const cachePoint = BedrockCache.block(breakpoints, tool.cache);
|
|
171
170
|
if (cachePoint)
|
|
172
171
|
result.push(cachePoint);
|
|
@@ -371,7 +370,7 @@ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request)
|
|
|
371
370
|
if (flattened.tools.length === 0)
|
|
372
371
|
return undefined;
|
|
373
372
|
return {
|
|
374
|
-
tools: lowerTools(
|
|
373
|
+
tools: lowerTools(breakpoints, flattened.tools),
|
|
375
374
|
// Converse has no native "none". Keep definitions stable for prompt
|
|
376
375
|
// caching and omit only the unsupported choice.
|
|
377
376
|
toolChoice,
|
|
@@ -23,6 +23,14 @@ interface State extends SpeechStream.Audio {
|
|
|
23
23
|
readonly done: boolean;
|
|
24
24
|
}
|
|
25
25
|
export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly type: "generation-queued";
|
|
28
|
+
readonly position?: number | undefined;
|
|
29
|
+
} | {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly type: "generation-progress";
|
|
32
|
+
readonly progress?: number | undefined;
|
|
33
|
+
} | {
|
|
26
34
|
readonly type: "audio-delta";
|
|
27
35
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
28
36
|
} | {
|
|
@@ -74,6 +82,14 @@ export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
|
74
82
|
export declare const model: (input: MediaRoute.ModelInput) => SpeechModel<CartesiaSpeechOptions>;
|
|
75
83
|
export declare const CartesiaSpeech: {
|
|
76
84
|
readonly protocol: MediaProtocol.Streamed<Request, {
|
|
85
|
+
readonly id: string;
|
|
86
|
+
readonly type: "generation-queued";
|
|
87
|
+
readonly position?: number | undefined;
|
|
88
|
+
} | {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly type: "generation-progress";
|
|
91
|
+
readonly progress?: number | undefined;
|
|
92
|
+
} | {
|
|
77
93
|
readonly type: "audio-delta";
|
|
78
94
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
79
95
|
} | {
|
|
@@ -16,6 +16,14 @@ export type DeepgramSpeechOptions = {
|
|
|
16
16
|
} & Record<string, unknown>;
|
|
17
17
|
export type Request = SpeechRequestFor<DeepgramSpeechOptions>;
|
|
18
18
|
export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly type: "generation-queued";
|
|
21
|
+
readonly position?: number | undefined;
|
|
22
|
+
} | {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly type: "generation-progress";
|
|
25
|
+
readonly progress?: number | undefined;
|
|
26
|
+
} | {
|
|
19
27
|
readonly type: "audio-delta";
|
|
20
28
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
21
29
|
} | {
|
|
@@ -67,6 +75,14 @@ export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
|
67
75
|
export declare const model: (input: MediaRoute.ModelInput) => SpeechModel<DeepgramSpeechOptions>;
|
|
68
76
|
export declare const DeepgramSpeech: {
|
|
69
77
|
readonly protocol: MediaProtocol.Streamed<Request, {
|
|
78
|
+
readonly id: string;
|
|
79
|
+
readonly type: "generation-queued";
|
|
80
|
+
readonly position?: number | undefined;
|
|
81
|
+
} | {
|
|
82
|
+
readonly id: string;
|
|
83
|
+
readonly type: "generation-progress";
|
|
84
|
+
readonly progress?: number | undefined;
|
|
85
|
+
} | {
|
|
70
86
|
readonly type: "audio-delta";
|
|
71
87
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
72
88
|
} | {
|
|
@@ -19,6 +19,14 @@ export type ElevenLabsSpeechOptions = {
|
|
|
19
19
|
} & Record<string, unknown>;
|
|
20
20
|
export type Request = SpeechRequestFor<ElevenLabsSpeechOptions>;
|
|
21
21
|
export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly type: "generation-queued";
|
|
24
|
+
readonly position?: number | undefined;
|
|
25
|
+
} | {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly type: "generation-progress";
|
|
28
|
+
readonly progress?: number | undefined;
|
|
29
|
+
} | {
|
|
22
30
|
readonly type: "audio-delta";
|
|
23
31
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
24
32
|
} | {
|
|
@@ -70,6 +78,14 @@ export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
|
70
78
|
export declare const model: (input: MediaRoute.ModelInput) => SpeechModel<ElevenLabsSpeechOptions>;
|
|
71
79
|
export declare const ElevenLabsSpeech: {
|
|
72
80
|
readonly protocol: MediaProtocol.Streamed<Request, {
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly type: "generation-queued";
|
|
83
|
+
readonly position?: number | undefined;
|
|
84
|
+
} | {
|
|
85
|
+
readonly id: string;
|
|
86
|
+
readonly type: "generation-progress";
|
|
87
|
+
readonly progress?: number | undefined;
|
|
88
|
+
} | {
|
|
73
89
|
readonly type: "audio-delta";
|
|
74
90
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
75
91
|
} | {
|
package/dist/protocols/gemini.js
CHANGED
|
@@ -11,7 +11,6 @@ import { Media } from "../media.js";
|
|
|
11
11
|
import { JsonObject, knownString, lenient, optionalArray, optionalNull, ProviderShared } from "./shared.js";
|
|
12
12
|
import { GeminiGenerateContent } from "./utils/gemini-generate-content.js";
|
|
13
13
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
14
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
15
14
|
const ADAPTER = "gemini";
|
|
16
15
|
// Google documents this sentinel for replaying Gemini 3 function calls after their original signature was lost.
|
|
17
16
|
const SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
|
|
@@ -190,12 +189,11 @@ const GeminiEvent = Schema.Struct({
|
|
|
190
189
|
// =============================================================================
|
|
191
190
|
// Request Lowering
|
|
192
191
|
// =============================================================================
|
|
193
|
-
// Tool schemas go in `parametersJsonSchema`, which accepts standard JSON Schema.
|
|
194
|
-
|
|
195
|
-
const lowerTool = (tool, model) => ({
|
|
192
|
+
// Tool schemas go in `parametersJsonSchema`, which accepts standard JSON Schema.
|
|
193
|
+
const lowerTool = (tool) => ({
|
|
196
194
|
name: tool.name,
|
|
197
195
|
description: tool.description,
|
|
198
|
-
parametersJsonSchema:
|
|
196
|
+
parametersJsonSchema: tool.inputSchema,
|
|
199
197
|
});
|
|
200
198
|
const lowerToolConfig = (toolChoice) => ProviderShared.matchToolChoice("Gemini", toolChoice, {
|
|
201
199
|
auto: () => ({ functionCallingConfig: { mode: "AUTO" } }),
|
|
@@ -388,7 +386,7 @@ const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request) {
|
|
|
388
386
|
tools: hasTools
|
|
389
387
|
? [
|
|
390
388
|
{
|
|
391
|
-
functionDeclarations: flattened.tools.map(
|
|
389
|
+
functionDeclarations: flattened.tools.map(lowerTool),
|
|
392
390
|
},
|
|
393
391
|
]
|
|
394
392
|
: undefined,
|
|
@@ -654,6 +652,8 @@ export const protocol = Protocol.make({
|
|
|
654
652
|
schema: GeminiBody,
|
|
655
653
|
from: fromRequest,
|
|
656
654
|
},
|
|
655
|
+
// Gemini's schema rules are this API's default, including for tuned endpoints whose IDs do not name Gemini.
|
|
656
|
+
sanitizer: "gemini",
|
|
657
657
|
stream: {
|
|
658
658
|
event: Protocol.jsonEvent(GeminiEvent),
|
|
659
659
|
initial: (request) => ({
|
|
@@ -26,6 +26,14 @@ interface State extends SpeechStream.Audio, GeminiGenerateContent.Metadata {
|
|
|
26
26
|
readonly mimeType?: string;
|
|
27
27
|
}
|
|
28
28
|
export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly type: "generation-queued";
|
|
31
|
+
readonly position?: number | undefined;
|
|
32
|
+
} | {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly type: "generation-progress";
|
|
35
|
+
readonly progress?: number | undefined;
|
|
36
|
+
} | {
|
|
29
37
|
readonly type: "audio-delta";
|
|
30
38
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
31
39
|
} | {
|
|
@@ -77,6 +85,14 @@ export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
|
77
85
|
export declare const model: (input: MediaRoute.ModelInput) => SpeechModel<GoogleSpeechOptions>;
|
|
78
86
|
export declare const GoogleSpeech: {
|
|
79
87
|
readonly protocol: MediaProtocol.Streamed<Request, {
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly type: "generation-queued";
|
|
90
|
+
readonly position?: number | undefined;
|
|
91
|
+
} | {
|
|
92
|
+
readonly id: string;
|
|
93
|
+
readonly type: "generation-progress";
|
|
94
|
+
readonly progress?: number | undefined;
|
|
95
|
+
} | {
|
|
80
96
|
readonly type: "audio-delta";
|
|
81
97
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
82
98
|
} | {
|
|
@@ -5,7 +5,6 @@ import { LLMEvent, LLMRequest, Message, ToolResultPart } from "../schema/index.j
|
|
|
5
5
|
import { OpenResponses } from "./open-responses.js";
|
|
6
6
|
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
|
|
7
7
|
import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js";
|
|
8
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
9
8
|
import { detectMediaType } from "../utils/media-type.js";
|
|
10
9
|
const ADAPTER = "meta-responses";
|
|
11
10
|
const NAME = "Meta Responses";
|
|
@@ -82,7 +81,7 @@ const fromRequest = Effect.fn("MetaResponses.fromRequest")(function* (request) {
|
|
|
82
81
|
? undefined
|
|
83
82
|
: yield* Effect.forEach(projected.tools, (tool) => Effect.gen(function* () {
|
|
84
83
|
if (tool.native === undefined)
|
|
85
|
-
return yield* OpenResponses.lowerTool(NAME, tool
|
|
84
|
+
return yield* OpenResponses.lowerTool(NAME, tool);
|
|
86
85
|
return yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(NativeTool))(tool.native.meta);
|
|
87
86
|
})),
|
|
88
87
|
tool_choice: OpenResponses.allowedToolChoice(request) ??
|
|
@@ -10,7 +10,6 @@ import { classifyProviderFailure } from "../provider-error.js";
|
|
|
10
10
|
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
|
|
11
11
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
12
12
|
import { MistralToolID } from "./utils/mistral-tool-id.js";
|
|
13
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
14
13
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
15
14
|
const ADAPTER = "mistral-chat";
|
|
16
15
|
const DONE = "[DONE]";
|
|
@@ -273,9 +272,9 @@ const lowerMessages = Effect.fn("MistralChat.lowerMessages")(function* (request)
|
|
|
273
272
|
}
|
|
274
273
|
return messages;
|
|
275
274
|
});
|
|
276
|
-
const lowerTool = (tool
|
|
275
|
+
const lowerTool = (tool) => ({
|
|
277
276
|
type: "function",
|
|
278
|
-
function: { name: tool.name, description: tool.description, parameters: inputSchema, strict: false },
|
|
277
|
+
function: { name: tool.name, description: tool.description, parameters: tool.inputSchema, strict: false },
|
|
279
278
|
});
|
|
280
279
|
export const fromRequest = Effect.fn("MistralChat.fromRequest")(function* (request) {
|
|
281
280
|
const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(MistralOptions))(request.providerOptions ?? {});
|
|
@@ -296,9 +295,7 @@ export const fromRequest = Effect.fn("MistralChat.fromRequest")(function* (reque
|
|
|
296
295
|
return {
|
|
297
296
|
model: request.model.id,
|
|
298
297
|
messages: yield* lowerMessages(flattened.request),
|
|
299
|
-
tools: flattened.tools.length > 0
|
|
300
|
-
? flattened.tools.map((tool) => lowerTool(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, request.model)))
|
|
301
|
-
: undefined,
|
|
298
|
+
tools: flattened.tools.length > 0 ? flattened.tools.map(lowerTool) : undefined,
|
|
302
299
|
tool_choice: toolChoice,
|
|
303
300
|
stream: true,
|
|
304
301
|
max_tokens: request.generation?.maxTokens,
|
|
@@ -716,9 +716,7 @@ interface ReasoningStreamItem {
|
|
|
716
716
|
readonly summaryParts: Readonly<Record<number, ReasoningSummaryStatus>>;
|
|
717
717
|
readonly deltaIndexes: ReadonlySet<number>;
|
|
718
718
|
}
|
|
719
|
-
export declare const lowerTool: (protocolName: string, tool: ToolDefinition
|
|
720
|
-
readonly [x: string]: unknown;
|
|
721
|
-
}) => Effect.Effect<{
|
|
719
|
+
export declare const lowerTool: (protocolName: string, tool: ToolDefinition) => Effect.Effect<{
|
|
722
720
|
type: "function";
|
|
723
721
|
name: string;
|
|
724
722
|
description: string;
|
|
@@ -7,7 +7,6 @@ import { classifyProviderFailure } from "../provider-error.js";
|
|
|
7
7
|
import { effortUpdate } from "../effort-updates.js";
|
|
8
8
|
import { OpenResponsesOptions } from "./utils/open-responses-options.js";
|
|
9
9
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
10
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
11
10
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
12
11
|
const ADAPTER = "open-responses";
|
|
13
12
|
const NAME = "Open Responses";
|
|
@@ -281,14 +280,14 @@ const BASE_ADAPTER = { id: ADAPTER, name: NAME };
|
|
|
281
280
|
// =============================================================================
|
|
282
281
|
// Request Lowering
|
|
283
282
|
// =============================================================================
|
|
284
|
-
export const lowerTool = Effect.fn("OpenResponses.lowerTool")(function* (protocolName, tool
|
|
283
|
+
export const lowerTool = Effect.fn("OpenResponses.lowerTool")(function* (protocolName, tool) {
|
|
285
284
|
if (tool.native !== undefined)
|
|
286
285
|
return yield* ProviderShared.invalidRequest(`${protocolName} does not support provider-native tool ${tool.name}`);
|
|
287
286
|
return {
|
|
288
287
|
type: "function",
|
|
289
288
|
name: tool.name,
|
|
290
289
|
description: tool.description,
|
|
291
|
-
parameters: inputSchema,
|
|
290
|
+
parameters: tool.inputSchema,
|
|
292
291
|
// The common tool definition does not currently express Responses strict-schema policy.
|
|
293
292
|
strict: false,
|
|
294
293
|
};
|
|
@@ -610,7 +609,7 @@ export const fromRequestWithAdapter = Effect.fn("OpenResponses.fromRequestWithAd
|
|
|
610
609
|
? undefined
|
|
611
610
|
: yield* Effect.forEach(projected.tools, (tool) => tool.native !== undefined && adapter.nativeTool
|
|
612
611
|
? adapter.nativeTool(tool.native)
|
|
613
|
-
: lowerTool(adapter.name, tool
|
|
612
|
+
: lowerTool(adapter.name, tool)),
|
|
614
613
|
tool_choice: allowedToolChoice(request) ??
|
|
615
614
|
(request.toolChoice ? yield* lowerToolChoice(adapter.name, request.toolChoice) : undefined),
|
|
616
615
|
};
|
|
@@ -11,7 +11,6 @@ import { classifyProviderFailure } from "../provider-error.js";
|
|
|
11
11
|
import { isRecord, JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
|
|
12
12
|
import { OpenAIOptions } from "./utils/openai-options.js";
|
|
13
13
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
14
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
15
14
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
16
15
|
const ADAPTER = "openai-chat";
|
|
17
16
|
const RESERVED_REASONING_FIELDS = new Set(["role", "content", "refusal", "tool_calls"]);
|
|
@@ -209,12 +208,12 @@ export const OpenAIChatEvent = Schema.StructWithRest(Schema.Struct({
|
|
|
209
208
|
}), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
210
209
|
const DONE = "[DONE]";
|
|
211
210
|
const OpenAIChatStreamEvent = Schema.Union([Schema.Literal(DONE), Protocol.jsonEvent(OpenAIChatEvent)]);
|
|
212
|
-
const lowerTool = (tool,
|
|
211
|
+
const lowerTool = (tool, options, supportsStrictMode) => ({
|
|
213
212
|
type: "function",
|
|
214
213
|
function: {
|
|
215
214
|
name: tool.name,
|
|
216
215
|
description: tool.description,
|
|
217
|
-
parameters: inputSchema,
|
|
216
|
+
parameters: tool.inputSchema,
|
|
218
217
|
...(supportsStrictMode ? { strict: false } : {}),
|
|
219
218
|
},
|
|
220
219
|
cache_control: options.cacheControl?.(tool.cache),
|
|
@@ -649,7 +648,7 @@ export const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (reques
|
|
|
649
648
|
? hasHistory
|
|
650
649
|
? []
|
|
651
650
|
: undefined
|
|
652
|
-
: flattened.tools.map((tool) => lowerTool(tool,
|
|
651
|
+
: flattened.tools.map((tool) => lowerTool(tool, options, supportsStrictMode)),
|
|
653
652
|
tool_choice: hasActiveTools && request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined,
|
|
654
653
|
stream: true,
|
|
655
654
|
...(supportsUsageInStreaming ? { stream_options: { include_usage: true } } : {}),
|
|
@@ -5,13 +5,12 @@ import { Auth } from "../route/auth.js";
|
|
|
5
5
|
import { Endpoint } from "../route/endpoint.js";
|
|
6
6
|
import { Protocol } from "../route/protocol.js";
|
|
7
7
|
import { HttpTransport } from "../route/transport/index.js";
|
|
8
|
-
import { LLMRequest, mergeJsonRecords
|
|
8
|
+
import { LLMRequest, mergeJsonRecords } from "../schema/index.js";
|
|
9
9
|
import { resolveEffortUpdates } from "../effort-updates.js";
|
|
10
10
|
import { OpenResponses } from "./open-responses.js";
|
|
11
11
|
import { OpenResponsesOptions } from "./utils/open-responses-options.js";
|
|
12
12
|
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
|
|
13
13
|
import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js";
|
|
14
|
-
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
15
14
|
import { OpenResponsesChannel } from "./open-responses-channel.js";
|
|
16
15
|
import { ResponsesCompaction } from "./utils/responses-compaction.js";
|
|
17
16
|
import { ResponsesCheckpoint } from "./utils/responses-checkpoint.js";
|
|
@@ -132,27 +131,27 @@ const nativeImageTool = (tool) => {
|
|
|
132
131
|
const native = nativeImageToolInput(tool);
|
|
133
132
|
return Schema.is(OpenAIResponsesImageGenerationTool)(native) ? native : undefined;
|
|
134
133
|
};
|
|
135
|
-
const lowerTool = Effect.fn("OpenAIResponses.lowerTool")(function* (tool
|
|
134
|
+
const lowerTool = Effect.fn("OpenAIResponses.lowerTool")(function* (tool) {
|
|
136
135
|
const native = nativeImageToolInput(tool);
|
|
137
136
|
if (native !== undefined) {
|
|
138
137
|
if (Schema.is(OpenAIResponsesImageGenerationTool)(native))
|
|
139
138
|
return native;
|
|
140
139
|
return yield* ProviderShared.invalidRequest("OpenAI Responses image generation tool options are invalid");
|
|
141
140
|
}
|
|
142
|
-
return yield* OpenResponses.lowerTool(NAME, tool
|
|
141
|
+
return yield* OpenResponses.lowerTool(NAME, tool);
|
|
143
142
|
});
|
|
144
143
|
// Native namespaces hold only function tools, so deeper levels flatten into
|
|
145
144
|
// the leaf names the same way non-native protocols flatten the whole tree.
|
|
146
|
-
const lowerToolEntry = Effect.fn("OpenAIResponses.lowerToolEntry")(function* (tool
|
|
145
|
+
const lowerToolEntry = Effect.fn("OpenAIResponses.lowerToolEntry")(function* (tool) {
|
|
147
146
|
if (tool.type === "tool")
|
|
148
|
-
return yield* lowerTool(tool
|
|
147
|
+
return yield* lowerTool(tool);
|
|
149
148
|
// OpenAI requires a namespace description; fall back to a generic one so a
|
|
150
149
|
// missing description never blocks the request.
|
|
151
150
|
return {
|
|
152
151
|
type: "namespace",
|
|
153
152
|
name: tool.name,
|
|
154
153
|
description: tool.description ?? `Tools in the ${tool.name} namespace.`,
|
|
155
|
-
tools: yield* Effect.forEach(ProviderShared.flattenTools(tool.tools), (leaf) => OpenResponses.lowerTool(NAME, leaf
|
|
154
|
+
tools: yield* Effect.forEach(ProviderShared.flattenTools(tool.tools), (leaf) => OpenResponses.lowerTool(NAME, leaf)),
|
|
156
155
|
};
|
|
157
156
|
});
|
|
158
157
|
const lowerToolChoice = (toolChoice, tools) => ProviderShared.matchToolChoice(NAME, toolChoice, {
|
|
@@ -172,9 +171,7 @@ const fromRequest = Effect.fn("OpenAIResponses.fromRequest")(function* (request)
|
|
|
172
171
|
...(yield* OpenResponses.lowerConversation(updates.request, adapter)),
|
|
173
172
|
...OpenResponses.lowerGeneration(request, { ...options, reasoningEffort: updates.effort }),
|
|
174
173
|
context_management: management?.map((edit) => ({ type: edit.type, compact_threshold: edit.compactThreshold })),
|
|
175
|
-
tools: request.tools.length === 0
|
|
176
|
-
? undefined
|
|
177
|
-
: yield* Effect.forEach(request.tools, (tool) => lowerToolEntry(tool, request.model)),
|
|
174
|
+
tools: request.tools.length === 0 ? undefined : yield* Effect.forEach(request.tools, lowerToolEntry),
|
|
178
175
|
tool_choice: request.tools.length === 0
|
|
179
176
|
? undefined
|
|
180
177
|
: (OpenResponses.allowedToolChoice(request) ??
|
|
@@ -16,6 +16,14 @@ interface State extends SpeechStream.Audio {
|
|
|
16
16
|
readonly usage?: MediaUsage;
|
|
17
17
|
}
|
|
18
18
|
export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly type: "generation-queued";
|
|
21
|
+
readonly position?: number | undefined;
|
|
22
|
+
} | {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly type: "generation-progress";
|
|
25
|
+
readonly progress?: number | undefined;
|
|
26
|
+
} | {
|
|
19
27
|
readonly type: "audio-delta";
|
|
20
28
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
21
29
|
} | {
|
|
@@ -67,6 +75,14 @@ export declare const protocol: MediaProtocol.Streamed<Request, {
|
|
|
67
75
|
export declare const model: (input: MediaRoute.ModelInput) => SpeechModel<OpenAISpeechOptions>;
|
|
68
76
|
export declare const OpenAISpeech: {
|
|
69
77
|
readonly protocol: MediaProtocol.Streamed<Request, {
|
|
78
|
+
readonly id: string;
|
|
79
|
+
readonly type: "generation-queued";
|
|
80
|
+
readonly position?: number | undefined;
|
|
81
|
+
} | {
|
|
82
|
+
readonly id: string;
|
|
83
|
+
readonly type: "generation-progress";
|
|
84
|
+
readonly progress?: number | undefined;
|
|
85
|
+
} | {
|
|
70
86
|
readonly type: "audio-delta";
|
|
71
87
|
readonly chunk: Uint8Array<ArrayBufferLike>;
|
|
72
88
|
} | {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JsonSchema, type LanguageModel, type LLMRequest } from "../../schema/index.js";
|
|
2
2
|
export declare const ToolSchemaProjection: {
|
|
3
3
|
readonly gemini: (schema: JsonSchema) => JsonSchema;
|
|
4
|
-
readonly modelCompatibility: (schema: JsonSchema, model: LanguageModel, protocolDefault?: LanguageModelSanitizerCompatibility) => JsonSchema;
|
|
5
4
|
readonly moonshot: (schema: JsonSchema) => JsonSchema;
|
|
6
5
|
readonly openAI: (schema: JsonSchema) => JsonSchema;
|
|
7
6
|
readonly responses: (schema: JsonSchema) => JsonSchema;
|
|
7
|
+
readonly tools: (entries: LLMRequest["tools"], model: LanguageModel) => LLMRequest["tools"];
|
|
8
8
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ToolDefinition } from "../../schema/index.js";
|
|
1
2
|
import { isRecord } from "../../utils/record.js";
|
|
2
3
|
import { GeminiJsonSchema } from "./gemini-json-schema.js";
|
|
3
4
|
const tupleItemsSchema = (items) => {
|
|
@@ -69,9 +70,11 @@ const objectRoot = (schema) => {
|
|
|
69
70
|
// Otherwise the protocol's own default applies (the Gemini API always uses Gemini's rules), then the
|
|
70
71
|
// model name selects the family's rules so models reached through gateways and OpenAI-compatible
|
|
71
72
|
// endpoints get the same handling.
|
|
72
|
-
const modelCompatibility = (schema, model
|
|
73
|
+
const modelCompatibility = (schema, model) => {
|
|
73
74
|
const root = objectRoot(schema);
|
|
74
|
-
switch (model.compatibility?.sanitizer ??
|
|
75
|
+
switch (model.compatibility?.sanitizer ??
|
|
76
|
+
model.route.sanitizer ??
|
|
77
|
+
MODEL_NAMES.find(([name]) => name.test(model.id))?.[1]) {
|
|
75
78
|
case "gemini":
|
|
76
79
|
return gemini(root);
|
|
77
80
|
case "moonshot":
|
|
@@ -81,10 +84,14 @@ const modelCompatibility = (schema, model, protocolDefault) => {
|
|
|
81
84
|
return root;
|
|
82
85
|
}
|
|
83
86
|
};
|
|
87
|
+
// Applied once to every request before any protocol builds its body, including tools in namespaces.
|
|
88
|
+
const tools = (entries, model) => entries.map((tool) => tool.type === "tool"
|
|
89
|
+
? new ToolDefinition({ ...tool, inputSchema: modelCompatibility(tool.inputSchema, model) })
|
|
90
|
+
: { ...tool, tools: tools(tool.tools, model) });
|
|
84
91
|
export const ToolSchemaProjection = {
|
|
85
92
|
gemini,
|
|
86
|
-
modelCompatibility,
|
|
87
93
|
moonshot,
|
|
88
94
|
openAI,
|
|
89
95
|
responses,
|
|
96
|
+
tools,
|
|
90
97
|
};
|
package/dist/route/client.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Framing } from "./framing.js";
|
|
|
6
6
|
import { HttpTransport } from "./transport/index.js";
|
|
7
7
|
import type { HttpMiddleware, Transport, TransportRuntime, WebSocketChannelExecutor } from "./transport/index.js";
|
|
8
8
|
import type { Protocol } from "./protocol.js";
|
|
9
|
-
import type { ProtocolID, ProviderOptions } from "../schema/index.js";
|
|
9
|
+
import type { LanguageModelSanitizerCompatibility, ProtocolID, ProviderOptions } from "../schema/index.js";
|
|
10
10
|
import { AIError, CompactionResponse, CompactionCheckpointResponse, GenerationOptions, HttpOptions, LLMRequest, LLMResponse, LanguageModel, LLMEvent, ProviderID } from "../schema/index.js";
|
|
11
11
|
export interface RouteBody<Body> {
|
|
12
12
|
/** Schema for the validated provider-native body sent as the JSON request. */
|
|
@@ -31,6 +31,7 @@ export interface Route<Body, Prepared = unknown, Compact extends CompactionOpera
|
|
|
31
31
|
readonly defaults: RouteDefaults;
|
|
32
32
|
readonly body: RouteBody<Body>;
|
|
33
33
|
readonly supportsEffortUpdates?: (request: LLMRequest) => boolean;
|
|
34
|
+
readonly sanitizer?: LanguageModelSanitizerCompatibility;
|
|
34
35
|
readonly with: {
|
|
35
36
|
<Next extends CompactionOperations | undefined>(patch: RoutePatch<Body, Prepared> & {
|
|
36
37
|
readonly compact: Next;
|
package/dist/route/client.js
CHANGED
|
@@ -9,6 +9,7 @@ import { applyEffortUpdates } from "../effort-updates.js";
|
|
|
9
9
|
import { normalizeToolHistory } from "../tool-history.js";
|
|
10
10
|
import { sanitizeSurrogates } from "../utils/sanitize.js";
|
|
11
11
|
import * as ProviderShared from "../protocols/shared.js";
|
|
12
|
+
import { ToolSchemaProjection } from "../protocols/utils/tool-schema.js";
|
|
12
13
|
import { AIError, CompactionResponse, CompactionCheckpointResponse, AIErrorReason, GenerationOptions, HttpOptions, LLMRequest, LLMResponse, LanguageModel, LLMEvent, InvalidProviderOutputError, ProviderConfigurationError, ProviderID, mergeGenerationOptions, mergeHttpOptions, mergeProviderOptions, } from "../schema/index.js";
|
|
13
14
|
const makeRouteLanguageModel = (route, mapped) => {
|
|
14
15
|
const provider = route.provider ?? ("provider" in mapped ? mapped.provider : undefined);
|
|
@@ -118,6 +119,7 @@ function makeFromTransport(input) {
|
|
|
118
119
|
defaults: routeInput.defaults ?? {},
|
|
119
120
|
body: protocol.body,
|
|
120
121
|
supportsEffortUpdates: protocol.supportsEffortUpdates,
|
|
122
|
+
sanitizer: protocol.sanitizer,
|
|
121
123
|
with: (patch) => {
|
|
122
124
|
const { compact, id, provider, providerMetadataKey, auth, transport, endpoint, ...defaults } = patch;
|
|
123
125
|
return build({
|
|
@@ -210,7 +212,7 @@ const prepareRequest = (request) => {
|
|
|
210
212
|
const sanitized = LLMRequest.update(original, sanitizeSurrogates({ ...LLMRequest.input(original), model: undefined }));
|
|
211
213
|
// Deduplicate per sibling level; a tool and a namespace may share a name.
|
|
212
214
|
const dedupe = (tools) => [...new Map(tools.map((tool) => [`${tool.type}:${tool.name}`, tool])).values()].map((tool) => tool.type === "tool" ? tool : { ...tool, tools: dedupe(tool.tools) });
|
|
213
|
-
const resolved = applyCachePolicy(applyEffortUpdates(LLMRequest.update(sanitized, { tools: dedupe(sanitized.tools) })));
|
|
215
|
+
const resolved = applyCachePolicy(applyEffortUpdates(LLMRequest.update(sanitized, { tools: ToolSchemaProjection.tools(dedupe(sanitized.tools), sanitized.model) })));
|
|
214
216
|
const headers = resolved.model.route.headers?.({ request: resolved });
|
|
215
217
|
return headers === undefined
|
|
216
218
|
? resolved
|
package/dist/route/media.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Auth } from "./auth.js";
|
|
|
3
3
|
import { Endpoint } from "./endpoint.js";
|
|
4
4
|
import { type Interface } from "./executor-service.js";
|
|
5
5
|
import { MediaProtocol } from "./media-protocol.js";
|
|
6
|
-
import { Generation
|
|
6
|
+
import { Generation } from "../generation.js";
|
|
7
7
|
import { AIError, HttpOptions, ProviderID } from "../schema/index.js";
|
|
8
8
|
export type Execute = Interface["execute"];
|
|
9
9
|
/** The minimum a media request must carry for the route to build a transport request. */
|
|
@@ -30,7 +30,7 @@ export declare const deployment: (input: {
|
|
|
30
30
|
readonly http?: HttpOptions.Input;
|
|
31
31
|
}, auth: Auth.Definition) => Omit<ModelInput, "id">;
|
|
32
32
|
/** One request, one response. */
|
|
33
|
-
export interface
|
|
33
|
+
export interface InlineRoute<Request extends MediaRequest, Response> {
|
|
34
34
|
readonly kind: "inline";
|
|
35
35
|
readonly id: string;
|
|
36
36
|
readonly provider: ProviderID;
|
|
@@ -56,7 +56,7 @@ export interface StreamRoute<Request extends MediaRequest, Event, Response> {
|
|
|
56
56
|
readonly stream: (request: Request, execute: Execute) => Stream.Stream<Event, AIError>;
|
|
57
57
|
readonly generate: (request: Request, execute: Execute) => Effect.Effect<Response, AIError>;
|
|
58
58
|
}
|
|
59
|
-
export type AnyRoute<Request extends MediaRequest, Event, Response> =
|
|
59
|
+
export type AnyRoute<Request extends MediaRequest, Event, Response> = InlineRoute<Request, Response> | StreamRoute<Request, Event, Response> | QueuedRoute<Request, Response>;
|
|
60
60
|
export interface Composition<Request extends MediaRequest> {
|
|
61
61
|
readonly endpoint: Endpoint.Definition<MediaProtocol.Body, Request>;
|
|
62
62
|
readonly auth: Auth.Definition;
|
|
@@ -79,7 +79,7 @@ export interface StreamInput<Request extends MediaRequest, Event, Response, Fram
|
|
|
79
79
|
* rejection, URL and query rendering, auth headers, JSON, multipart, or binary encoding, and handing responses back
|
|
80
80
|
* to the protocol.
|
|
81
81
|
*/
|
|
82
|
-
export declare const inline: <Request extends MediaRequest, Response>(input: InlineInput<Request, Response>) =>
|
|
82
|
+
export declare const inline: <Request extends MediaRequest, Response>(input: InlineInput<Request, Response>) => InlineRoute<Request, Response>;
|
|
83
83
|
/**
|
|
84
84
|
* Compose a queued media protocol the same way, adding `start`/`resume` handles whose polls reuse the route's auth,
|
|
85
85
|
* deployment headers, and (for `start`) the request's `http` overlay. The token is decoded once at the boundary and
|
|
@@ -88,14 +88,4 @@ export declare const inline: <Request extends MediaRequest, Response>(input: Inl
|
|
|
88
88
|
export declare const queued: <Request extends MediaRequest, Response, Token>(input: QueuedInput<Request, Response, Token>) => QueuedRoute<Request, Response>;
|
|
89
89
|
/** Compose a streaming media protocol; `generate` runs the same stream in `generate` mode and folds it with `collect`. */
|
|
90
90
|
export declare const stream: <Request extends MediaRequest, Event, Response, Frame, State>(input: StreamInput<Request, Event, Response, Frame, State>) => StreamRoute<Request, Event, Response>;
|
|
91
|
-
export declare const dispatch: <Event, Response>(input: {
|
|
92
|
-
readonly modality: string;
|
|
93
|
-
readonly execute: Execute;
|
|
94
|
-
readonly responseEvents: (response: Response) => ReadonlyArray<Event>;
|
|
95
|
-
}) => {
|
|
96
|
-
start: <Request extends MediaRequest>(route: AnyRoute<Request, Event, Response>, request: Request) => Effect.Effect<Generation<Response>, AIError, never>;
|
|
97
|
-
resume: <Request extends MediaRequest>(route: AnyRoute<Request, Event, Response>, model: MediaRequest["model"], token: unknown) => Effect.Effect<Generation<Response>, AIError, never>;
|
|
98
|
-
generate: <Request extends MediaRequest>(route: AnyRoute<Request, Event, Response>, request: Request, options?: AwaitOptions) => Effect.Effect<Response, AIError, never>;
|
|
99
|
-
stream: <Request extends MediaRequest>(route: AnyRoute<Request, Event, Response>, request: Request, options?: AwaitOptions) => Stream.Stream<Event | Observation, AIError>;
|
|
100
|
-
};
|
|
101
91
|
export * as MediaRoute from "./media.js";
|