@opencode-ai/ai 0.0.0-dev-18326 → 0.0.0-dev-18332
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/protocols/anthropic-messages.d.ts +1 -0
- package/dist/protocols/anthropic-messages.js +36 -31
- package/dist/protocols/bedrock-converse.d.ts +1 -0
- package/dist/protocols/bedrock-converse.js +23 -19
- package/dist/protocols/gemini.d.ts +1 -0
- package/dist/protocols/gemini.js +35 -21
- package/dist/protocols/openai-chat.d.ts +1 -0
- package/dist/protocols/openai-chat.js +25 -18
- package/dist/providers/amazon-bedrock-mantle.d.ts +1 -0
- package/dist/providers/amazon-bedrock-mantle.js +3 -1
- package/dist/providers/amazon-bedrock.js +1 -0
- package/dist/providers/google-vertex-chat.js +1 -0
- package/dist/providers/google-vertex-responses.js +1 -0
- package/dist/providers/google-vertex.js +1 -1
- package/dist/providers/openrouter.js +1 -0
- package/dist/route/client.d.ts +1 -0
- package/dist/route/client.js +5 -1
- package/package.json +3 -3
|
@@ -603,6 +603,7 @@ export declare const protocol: Protocol<{
|
|
|
603
603
|
} | undefined;
|
|
604
604
|
readonly content_block?: unknown;
|
|
605
605
|
}, {
|
|
606
|
+
providerMetadataKey: string;
|
|
606
607
|
tools: Partial<Record<number, ToolStream.PendingTool>>;
|
|
607
608
|
reasoningSignatures: {};
|
|
608
609
|
lifecycle: Lifecycle.State;
|
|
@@ -313,18 +313,18 @@ const cacheControl = (breakpoints, cache) => {
|
|
|
313
313
|
breakpoints.remaining -= 1;
|
|
314
314
|
return Cache.ttlBucket(cache.ttlSeconds) === "1h" ? EPHEMERAL_1H : EPHEMERAL_5M;
|
|
315
315
|
};
|
|
316
|
-
const
|
|
317
|
-
const signatureFromMetadata = (metadata) => {
|
|
318
|
-
const
|
|
319
|
-
if (!ProviderShared.isRecord(
|
|
316
|
+
const providerMetadata = (key, metadata) => ({ [key]: metadata });
|
|
317
|
+
const signatureFromMetadata = (metadata, key) => {
|
|
318
|
+
const provider = metadata?.[key];
|
|
319
|
+
if (!ProviderShared.isRecord(provider))
|
|
320
320
|
return undefined;
|
|
321
|
-
return typeof
|
|
321
|
+
return typeof provider.signature === "string" ? provider.signature : undefined;
|
|
322
322
|
};
|
|
323
|
-
const redactedDataFromMetadata = (metadata) => {
|
|
324
|
-
const
|
|
325
|
-
if (!ProviderShared.isRecord(
|
|
323
|
+
const redactedDataFromMetadata = (metadata, key) => {
|
|
324
|
+
const provider = metadata?.[key];
|
|
325
|
+
if (!ProviderShared.isRecord(provider))
|
|
326
326
|
return undefined;
|
|
327
|
-
return typeof
|
|
327
|
+
return typeof provider.redactedData === "string" ? provider.redactedData : undefined;
|
|
328
328
|
};
|
|
329
329
|
const lowerTool = (breakpoints, tool, inputSchema) => ({
|
|
330
330
|
name: tool.name,
|
|
@@ -379,13 +379,13 @@ const serverToolResultType = (name) => {
|
|
|
379
379
|
return "web_fetch_tool_result";
|
|
380
380
|
return undefined;
|
|
381
381
|
};
|
|
382
|
-
const lowerServerToolResult = Effect.fn("AnthropicMessages.lowerServerToolResult")(function* (part) {
|
|
382
|
+
const lowerServerToolResult = Effect.fn("AnthropicMessages.lowerServerToolResult")(function* (part, providerMetadataKey) {
|
|
383
383
|
const wireType = serverToolResultType(part.name);
|
|
384
384
|
if (!wireType)
|
|
385
385
|
return yield* invalid(`Anthropic Messages does not know how to round-trip server tool result for ${part.name}`);
|
|
386
386
|
// Prefer the provider-owned replay payload; fall back to the result value for
|
|
387
387
|
// histories constructed directly from provider events.
|
|
388
|
-
const payload = part.providerMetadata?.
|
|
388
|
+
const payload = part.providerMetadata?.[providerMetadataKey]?.["result"] ?? part.result.value;
|
|
389
389
|
return {
|
|
390
390
|
type: wireType,
|
|
391
391
|
tool_use_id: scrubToolCallID(part.id),
|
|
@@ -658,6 +658,7 @@ const lowerNativeSystemUpdate = Effect.fn("AnthropicMessages.lowerNativeSystemUp
|
|
|
658
658
|
});
|
|
659
659
|
const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (request, breakpoints) {
|
|
660
660
|
const messages = [];
|
|
661
|
+
const providerMetadataKey = request.model.route.providerMetadataKey ?? String(request.model.provider);
|
|
661
662
|
for (const [index, message] of request.messages.entries()) {
|
|
662
663
|
if (message.role === "system") {
|
|
663
664
|
if (splitsLocalToolResults(request.messages, index))
|
|
@@ -701,8 +702,8 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (re
|
|
|
701
702
|
if (part.type === "reasoning") {
|
|
702
703
|
// A signature marks visible thinking; only signature-less parts carrying
|
|
703
704
|
// redactedData round-trip as opaque redacted_thinking blocks.
|
|
704
|
-
const signature = part.encrypted ?? signatureFromMetadata(part.providerMetadata);
|
|
705
|
-
const redactedData = redactedDataFromMetadata(part.providerMetadata);
|
|
705
|
+
const signature = part.encrypted ?? signatureFromMetadata(part.providerMetadata, providerMetadataKey);
|
|
706
|
+
const redactedData = redactedDataFromMetadata(part.providerMetadata, providerMetadataKey);
|
|
706
707
|
if (signature === undefined && redactedData !== undefined) {
|
|
707
708
|
content.push({ type: "redacted_thinking", data: redactedData });
|
|
708
709
|
continue;
|
|
@@ -732,7 +733,7 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (re
|
|
|
732
733
|
continue;
|
|
733
734
|
}
|
|
734
735
|
if (part.type === "tool-result" && part.providerExecuted) {
|
|
735
|
-
content.push(yield* lowerServerToolResult(part));
|
|
736
|
+
content.push(yield* lowerServerToolResult(part, providerMetadataKey));
|
|
736
737
|
continue;
|
|
737
738
|
}
|
|
738
739
|
return yield* invalid(`Anthropic Messages assistant messages only support text, reasoning, and tool-call content for now`);
|
|
@@ -897,7 +898,7 @@ const mapFinishReason = (reason) => {
|
|
|
897
898
|
// inclusive `inputTokens` the rest of the contract expects. Extended
|
|
898
899
|
// thinking tokens are included in `output_tokens`; newer responses also
|
|
899
900
|
// expose that subset through `output_tokens_details.thinking_tokens`.
|
|
900
|
-
const mapUsage = (usage) => {
|
|
901
|
+
const mapUsage = (usage, providerMetadataKey) => {
|
|
901
902
|
if (!usage)
|
|
902
903
|
return undefined;
|
|
903
904
|
const nonCached = usage.input_tokens ?? undefined;
|
|
@@ -912,7 +913,7 @@ const mapUsage = (usage) => {
|
|
|
912
913
|
cacheWriteInputTokens: cacheWrite,
|
|
913
914
|
reasoningTokens: usage.output_tokens_details?.thinking_tokens,
|
|
914
915
|
totalTokens: ProviderShared.totalTokens(inputTokens, usage.output_tokens, undefined),
|
|
915
|
-
providerMetadata: {
|
|
916
|
+
providerMetadata: { [providerMetadataKey]: usage },
|
|
916
917
|
});
|
|
917
918
|
};
|
|
918
919
|
// Anthropic emits usage on `message_start` and again on `message_delta` — the
|
|
@@ -920,7 +921,7 @@ const mapUsage = (usage) => {
|
|
|
920
921
|
// field prefers `right` when defined, falls back to `left`. `inputTokens` is
|
|
921
922
|
// recomputed from the merged breakdown so the inclusive total stays
|
|
922
923
|
// consistent with `nonCached + cacheRead + cacheWrite`.
|
|
923
|
-
const mergeUsage = (left, right) => {
|
|
924
|
+
const mergeUsage = (left, right, providerMetadataKey) => {
|
|
924
925
|
if (!left)
|
|
925
926
|
return right;
|
|
926
927
|
if (!right)
|
|
@@ -940,7 +941,8 @@ const mergeUsage = (left, right) => {
|
|
|
940
941
|
reasoningTokens,
|
|
941
942
|
totalTokens: ProviderShared.totalTokens(inputTokens, outputTokens, undefined),
|
|
942
943
|
providerMetadata: {
|
|
943
|
-
|
|
944
|
+
[providerMetadataKey]: mergeJsonRecords(left.providerMetadata?.[providerMetadataKey], right.providerMetadata?.[providerMetadataKey]) ??
|
|
945
|
+
{},
|
|
944
946
|
},
|
|
945
947
|
});
|
|
946
948
|
};
|
|
@@ -955,7 +957,7 @@ const SERVER_TOOL_RESULT_NAMES = {
|
|
|
955
957
|
web_fetch_tool_result: "web_fetch",
|
|
956
958
|
};
|
|
957
959
|
const isServerToolResultType = (type) => type in SERVER_TOOL_RESULT_NAMES;
|
|
958
|
-
const serverToolResultEvent = (block) => {
|
|
960
|
+
const serverToolResultEvent = (block, providerMetadataKey) => {
|
|
959
961
|
if (!block.type || !isServerToolResultType(block.type))
|
|
960
962
|
return undefined;
|
|
961
963
|
const errorPayload = typeof block.content === "object" && block.content !== null && "type" in block.content
|
|
@@ -969,13 +971,13 @@ const serverToolResultEvent = (block) => {
|
|
|
969
971
|
providerExecuted: true,
|
|
970
972
|
// The complete payload is irreducible provider replay state: subsequent
|
|
971
973
|
// stateless requests must round-trip the typed result block verbatim.
|
|
972
|
-
providerMetadata:
|
|
974
|
+
providerMetadata: providerMetadata(providerMetadataKey, { blockType: block.type, result: block.content }),
|
|
973
975
|
});
|
|
974
976
|
};
|
|
975
977
|
const NO_EVENTS = [];
|
|
976
978
|
const onMessageStart = (state, event) => {
|
|
977
|
-
const usage = mapUsage(event.message?.usage);
|
|
978
|
-
return [usage ? { ...state, usage: mergeUsage(state.usage, usage) } : state, NO_EVENTS];
|
|
979
|
+
const usage = mapUsage(event.message?.usage, state.providerMetadataKey);
|
|
980
|
+
return [usage ? { ...state, usage: mergeUsage(state.usage, usage, state.providerMetadataKey) } : state, NO_EVENTS];
|
|
979
981
|
};
|
|
980
982
|
const onContentBlockStart = (state, event) => {
|
|
981
983
|
const block = event.content_block;
|
|
@@ -1021,13 +1023,15 @@ const onContentBlockStart = (state, event) => {
|
|
|
1021
1023
|
if (block.type === "thinking" && block.thinking !== undefined) {
|
|
1022
1024
|
const events = [];
|
|
1023
1025
|
const id = `reasoning-${event.index ?? 0}`;
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
+
const metadata = block.signature === undefined
|
|
1027
|
+
? undefined
|
|
1028
|
+
: providerMetadata(state.providerMetadataKey, { signature: block.signature });
|
|
1029
|
+
const lifecycle = Lifecycle.reasoningStart(state.lifecycle, events, id, metadata);
|
|
1026
1030
|
return [
|
|
1027
1031
|
{
|
|
1028
1032
|
...state,
|
|
1029
1033
|
lifecycle: block.thinking
|
|
1030
|
-
? Lifecycle.reasoningDelta(lifecycle, events, id, block.thinking,
|
|
1034
|
+
? Lifecycle.reasoningDelta(lifecycle, events, id, block.thinking, metadata)
|
|
1031
1035
|
: lifecycle,
|
|
1032
1036
|
reasoningSignatures: event.index === undefined || block.signature === undefined
|
|
1033
1037
|
? state.reasoningSignatures
|
|
@@ -1044,12 +1048,12 @@ const onContentBlockStart = (state, event) => {
|
|
|
1044
1048
|
return [
|
|
1045
1049
|
{
|
|
1046
1050
|
...state,
|
|
1047
|
-
lifecycle: Lifecycle.reasoningStart(state.lifecycle, events, `reasoning-${event.index ?? 0}`,
|
|
1051
|
+
lifecycle: Lifecycle.reasoningStart(state.lifecycle, events, `reasoning-${event.index ?? 0}`, providerMetadata(state.providerMetadataKey, { redactedData: block.data })),
|
|
1048
1052
|
},
|
|
1049
1053
|
events,
|
|
1050
1054
|
];
|
|
1051
1055
|
}
|
|
1052
|
-
const result = serverToolResultEvent(block);
|
|
1056
|
+
const result = serverToolResultEvent(block, state.providerMetadataKey);
|
|
1053
1057
|
if (!result)
|
|
1054
1058
|
return [state, NO_EVENTS];
|
|
1055
1059
|
const events = [];
|
|
@@ -1114,14 +1118,14 @@ const onContentBlockStop = Effect.fn("AnthropicMessages.onContentBlockStop")(fun
|
|
|
1114
1118
|
const signature = state.reasoningSignatures[event.index];
|
|
1115
1119
|
const lifecycle = resultEvents.length
|
|
1116
1120
|
? Lifecycle.stepStart(state.lifecycle, events)
|
|
1117
|
-
: Lifecycle.reasoningEnd(Lifecycle.textEnd(state.lifecycle, events, `text-${event.index}`), events, `reasoning-${event.index}`, signature === undefined ? undefined :
|
|
1121
|
+
: Lifecycle.reasoningEnd(Lifecycle.textEnd(state.lifecycle, events, `text-${event.index}`), events, `reasoning-${event.index}`, signature === undefined ? undefined : providerMetadata(state.providerMetadataKey, { signature }));
|
|
1118
1122
|
events.push(...resultEvents);
|
|
1119
1123
|
const reasoningSignatures = { ...state.reasoningSignatures };
|
|
1120
1124
|
delete reasoningSignatures[event.index];
|
|
1121
1125
|
return [{ ...state, lifecycle, tools: result.tools, reasoningSignatures }, events];
|
|
1122
1126
|
});
|
|
1123
1127
|
const onMessageDelta = (state, event) => {
|
|
1124
|
-
const usage = mergeUsage(state.usage, mapUsage(event.usage));
|
|
1128
|
+
const usage = mergeUsage(state.usage, mapUsage(event.usage, state.providerMetadataKey), state.providerMetadataKey);
|
|
1125
1129
|
return [
|
|
1126
1130
|
{
|
|
1127
1131
|
...state,
|
|
@@ -1133,7 +1137,7 @@ const onMessageDelta = (state, event) => {
|
|
|
1133
1137
|
},
|
|
1134
1138
|
providerMetadata: event.delta?.stop_sequence === null || event.delta?.stop_sequence === undefined
|
|
1135
1139
|
? undefined
|
|
1136
|
-
:
|
|
1140
|
+
: providerMetadata(state.providerMetadataKey, { stopSequence: event.delta.stop_sequence }),
|
|
1137
1141
|
},
|
|
1138
1142
|
},
|
|
1139
1143
|
NO_EVENTS,
|
|
@@ -1246,7 +1250,8 @@ export const protocol = Protocol.make({
|
|
|
1246
1250
|
},
|
|
1247
1251
|
stream: {
|
|
1248
1252
|
event: Protocol.jsonEvent(AnthropicEvent),
|
|
1249
|
-
initial: () => ({
|
|
1253
|
+
initial: (request) => ({
|
|
1254
|
+
providerMetadataKey: request.model.route.providerMetadataKey ?? String(request.model.provider),
|
|
1250
1255
|
tools: ToolStream.empty(),
|
|
1251
1256
|
reasoningSignatures: {},
|
|
1252
1257
|
lifecycle: Lifecycle.initial(),
|
|
@@ -127,6 +127,7 @@ declare const BedrockConverseBody: Schema.Struct<{
|
|
|
127
127
|
}>;
|
|
128
128
|
export type BedrockConverseBody = Schema.Schema.Type<typeof BedrockConverseBody>;
|
|
129
129
|
interface ParserState {
|
|
130
|
+
readonly providerMetadataKey: string;
|
|
130
131
|
readonly tools: ToolStream.State<number>;
|
|
131
132
|
readonly pendingFinish: {
|
|
132
133
|
readonly reason: FinishReasonDetails;
|
|
@@ -181,15 +181,17 @@ const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("Bedrock
|
|
|
181
181
|
required: () => ({ any: {} }),
|
|
182
182
|
tool: (name) => ({ tool: { name } }),
|
|
183
183
|
});
|
|
184
|
-
const
|
|
185
|
-
const reasoningSignature = (part) => {
|
|
186
|
-
const
|
|
184
|
+
const providerMetadata = (key, metadata) => ({ [key]: metadata });
|
|
185
|
+
const reasoningSignature = (part, providerMetadataKey) => {
|
|
186
|
+
const metadata = part.providerMetadata?.[providerMetadataKey];
|
|
187
187
|
return (part.encrypted ??
|
|
188
|
-
(ProviderShared.isRecord(
|
|
188
|
+
(ProviderShared.isRecord(metadata) && typeof metadata.signature === "string" ? metadata.signature : undefined));
|
|
189
189
|
};
|
|
190
|
-
const reasoningRedactedData = (part) => {
|
|
191
|
-
const
|
|
192
|
-
return ProviderShared.isRecord(
|
|
190
|
+
const reasoningRedactedData = (part, providerMetadataKey) => {
|
|
191
|
+
const metadata = part.providerMetadata?.[providerMetadataKey];
|
|
192
|
+
return ProviderShared.isRecord(metadata) && typeof metadata.redactedData === "string"
|
|
193
|
+
? metadata.redactedData
|
|
194
|
+
: undefined;
|
|
193
195
|
};
|
|
194
196
|
const lowerToolCall = (part) => ({
|
|
195
197
|
toolUse: {
|
|
@@ -230,6 +232,7 @@ const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (
|
|
|
230
232
|
});
|
|
231
233
|
const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (request, breakpoints) {
|
|
232
234
|
const messages = [];
|
|
235
|
+
const providerMetadataKey = request.model.route.providerMetadataKey ?? String(request.model.provider);
|
|
233
236
|
for (const message of request.messages) {
|
|
234
237
|
if (message.role === "system") {
|
|
235
238
|
const part = yield* ProviderShared.wrappedSystemUpdate("Bedrock Converse", message);
|
|
@@ -276,8 +279,8 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (requ
|
|
|
276
279
|
continue;
|
|
277
280
|
}
|
|
278
281
|
if (part.type === "reasoning") {
|
|
279
|
-
const signature = reasoningSignature(part);
|
|
280
|
-
const redactedData = reasoningRedactedData(part);
|
|
282
|
+
const signature = reasoningSignature(part, providerMetadataKey);
|
|
283
|
+
const redactedData = reasoningRedactedData(part, providerMetadataKey);
|
|
281
284
|
if (signature === undefined && redactedData !== undefined) {
|
|
282
285
|
content.push({ reasoningContent: { redactedContent: redactedData } });
|
|
283
286
|
continue;
|
|
@@ -371,7 +374,7 @@ const mapFinishReason = (reason) => {
|
|
|
371
374
|
};
|
|
372
375
|
// AWS reports inputTokens separately from cache reads and writes.
|
|
373
376
|
// Bedrock does not break reasoning out of outputTokens for current models.
|
|
374
|
-
const mapUsage = (usage) => {
|
|
377
|
+
const mapUsage = (usage, providerMetadataKey) => {
|
|
375
378
|
if (!usage)
|
|
376
379
|
return undefined;
|
|
377
380
|
const inputTokens = ProviderShared.sumTokens(usage.inputTokens, usage.cacheReadInputTokens, usage.cacheWriteInputTokens);
|
|
@@ -382,7 +385,7 @@ const mapUsage = (usage) => {
|
|
|
382
385
|
cacheReadInputTokens: usage.cacheReadInputTokens,
|
|
383
386
|
cacheWriteInputTokens: usage.cacheWriteInputTokens,
|
|
384
387
|
totalTokens: ProviderShared.totalTokens(inputTokens, usage.outputTokens, usage.totalTokens),
|
|
385
|
-
providerMetadata: {
|
|
388
|
+
providerMetadata: { [providerMetadataKey]: usage },
|
|
386
389
|
});
|
|
387
390
|
};
|
|
388
391
|
const step = (state, event) => Effect.gen(function* () {
|
|
@@ -423,13 +426,13 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
423
426
|
const reasoning = event.contentBlockDelta.delta.reasoningContent;
|
|
424
427
|
const events = [];
|
|
425
428
|
const redactedData = reasoning.redactedContent ?? reasoning.data;
|
|
426
|
-
const
|
|
427
|
-
?
|
|
429
|
+
const metadata = reasoning.signature
|
|
430
|
+
? providerMetadata(state.providerMetadataKey, { signature: reasoning.signature })
|
|
428
431
|
: redactedData !== undefined
|
|
429
|
-
?
|
|
432
|
+
? providerMetadata(state.providerMetadataKey, { redactedData })
|
|
430
433
|
: undefined;
|
|
431
|
-
const lifecycle = reasoning.text !== undefined ||
|
|
432
|
-
? Lifecycle.reasoningDelta(state.lifecycle, events, `reasoning-${index}`, reasoning.text ?? "",
|
|
434
|
+
const lifecycle = reasoning.text !== undefined || metadata !== undefined
|
|
435
|
+
? Lifecycle.reasoningDelta(state.lifecycle, events, `reasoning-${index}`, reasoning.text ?? "", metadata)
|
|
433
436
|
: state.lifecycle;
|
|
434
437
|
return [
|
|
435
438
|
{
|
|
@@ -460,7 +463,7 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
460
463
|
const lifecycle = resultEvents.length
|
|
461
464
|
? Lifecycle.stepStart(state.lifecycle, events)
|
|
462
465
|
: Lifecycle.reasoningEnd(Lifecycle.textEnd(state.lifecycle, events, `text-${index}`), events, `reasoning-${index}`, state.reasoningSignatures[index]
|
|
463
|
-
?
|
|
466
|
+
? providerMetadata(state.providerMetadataKey, { signature: state.reasoningSignatures[index] })
|
|
464
467
|
: undefined);
|
|
465
468
|
events.push(...resultEvents);
|
|
466
469
|
return [
|
|
@@ -491,7 +494,7 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
491
494
|
];
|
|
492
495
|
}
|
|
493
496
|
if (event.metadata) {
|
|
494
|
-
const usage = mapUsage(event.metadata.usage) ?? state.pendingFinish?.usage;
|
|
497
|
+
const usage = mapUsage(event.metadata.usage, state.providerMetadataKey) ?? state.pendingFinish?.usage;
|
|
495
498
|
return [
|
|
496
499
|
{
|
|
497
500
|
...state,
|
|
@@ -548,7 +551,8 @@ export const protocol = Protocol.make({
|
|
|
548
551
|
},
|
|
549
552
|
stream: {
|
|
550
553
|
event: BedrockEvent,
|
|
551
|
-
initial: () => ({
|
|
554
|
+
initial: (request) => ({
|
|
555
|
+
providerMetadataKey: request.model.route.providerMetadataKey ?? String(request.model.provider),
|
|
552
556
|
tools: ToolStream.empty(),
|
|
553
557
|
pendingFinish: undefined,
|
|
554
558
|
hasToolCalls: false,
|
package/dist/protocols/gemini.js
CHANGED
|
@@ -197,19 +197,20 @@ const lowerUserPart = Effect.fn("Gemini.lowerUserPart")(function* (part) {
|
|
|
197
197
|
const media = ProviderShared.normalizeMedia(part);
|
|
198
198
|
return { inlineData: { mimeType: media.mime, data: media.base64 } };
|
|
199
199
|
});
|
|
200
|
-
const
|
|
201
|
-
const thoughtSignature = (
|
|
202
|
-
const
|
|
203
|
-
return ProviderShared.isRecord(
|
|
204
|
-
?
|
|
200
|
+
const providerMetadata = (key, metadata) => ({ [key]: metadata });
|
|
201
|
+
const thoughtSignature = (metadata, key) => {
|
|
202
|
+
const value = metadata?.[key];
|
|
203
|
+
return ProviderShared.isRecord(value) && typeof value.thoughtSignature === "string"
|
|
204
|
+
? value.thoughtSignature
|
|
205
205
|
: undefined;
|
|
206
206
|
};
|
|
207
|
-
const lowerToolCall = (part, omitIds) => ({
|
|
207
|
+
const lowerToolCall = (part, omitIds, metadataKey) => ({
|
|
208
208
|
functionCall: { ...(omitIds ? {} : { id: part.id }), name: part.name, args: part.input },
|
|
209
|
-
thoughtSignature: thoughtSignature(part.providerMetadata),
|
|
209
|
+
thoughtSignature: thoughtSignature(part.providerMetadata, metadataKey),
|
|
210
210
|
});
|
|
211
211
|
const lowerMessages = Effect.fn("Gemini.lowerMessages")(function* (request) {
|
|
212
212
|
const contents = [];
|
|
213
|
+
const metadataKey = request.model.route.providerMetadataKey ?? String(request.model.provider);
|
|
213
214
|
const omitCallIds = omitsFunctionCallIds(request.model.id);
|
|
214
215
|
const legacyToolMedia = routesLegacyToolMedia(request.model.id);
|
|
215
216
|
let pendingMedia;
|
|
@@ -251,15 +252,19 @@ const lowerMessages = Effect.fn("Gemini.lowerMessages")(function* (request) {
|
|
|
251
252
|
if (!ProviderShared.supportsContent(part, ["text", "reasoning", "tool-call"]))
|
|
252
253
|
return yield* ProviderShared.unsupportedContent("Gemini", "assistant", ["text", "reasoning", "tool-call"]);
|
|
253
254
|
if (part.type === "text") {
|
|
254
|
-
parts.push({ text: part.text, thoughtSignature: thoughtSignature(part.providerMetadata) });
|
|
255
|
+
parts.push({ text: part.text, thoughtSignature: thoughtSignature(part.providerMetadata, metadataKey) });
|
|
255
256
|
continue;
|
|
256
257
|
}
|
|
257
258
|
if (part.type === "reasoning") {
|
|
258
|
-
parts.push({
|
|
259
|
+
parts.push({
|
|
260
|
+
text: part.text,
|
|
261
|
+
thought: true,
|
|
262
|
+
thoughtSignature: thoughtSignature(part.providerMetadata, metadataKey),
|
|
263
|
+
});
|
|
259
264
|
continue;
|
|
260
265
|
}
|
|
261
266
|
if (part.type === "tool-call") {
|
|
262
|
-
const lowered = lowerToolCall(part, omitCallIds);
|
|
267
|
+
const lowered = lowerToolCall(part, omitCallIds, metadataKey);
|
|
263
268
|
const signature = lowered.thoughtSignature;
|
|
264
269
|
parts.push({
|
|
265
270
|
...lowered,
|
|
@@ -396,7 +401,7 @@ const fromRequest = Effect.fn("Gemini.fromRequest")(function* (request) {
|
|
|
396
401
|
// `cachedContentTokenCount` subset. `candidatesTokenCount` is *exclusive*
|
|
397
402
|
// of `thoughtsTokenCount` — visible-only, not a total — so we sum the two
|
|
398
403
|
// to produce the inclusive `outputTokens` the rest of the contract expects.
|
|
399
|
-
const mapUsage = (usage) => {
|
|
404
|
+
const mapUsage = (usage, metadataKey) => {
|
|
400
405
|
if (!usage)
|
|
401
406
|
return undefined;
|
|
402
407
|
// Explicit provider nulls decode as `null`; normalize to `undefined` so the
|
|
@@ -418,7 +423,7 @@ const mapUsage = (usage) => {
|
|
|
418
423
|
cacheReadInputTokens: cached,
|
|
419
424
|
reasoningTokens: thoughts,
|
|
420
425
|
totalTokens: ProviderShared.totalTokens(promptTokens, outputTokens, usage.totalTokenCount ?? undefined),
|
|
421
|
-
providerMetadata:
|
|
426
|
+
providerMetadata: providerMetadata(metadataKey, usage),
|
|
422
427
|
});
|
|
423
428
|
};
|
|
424
429
|
const mapFinishReason = (finishReason, hasToolCalls) => {
|
|
@@ -458,16 +463,18 @@ const finish = (state) => {
|
|
|
458
463
|
const events = [];
|
|
459
464
|
let lifecycle = state.lifecycle;
|
|
460
465
|
if (state.reasoningSignature !== undefined)
|
|
461
|
-
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0",
|
|
466
|
+
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", providerMetadata(state.providerMetadataKey, { thoughtSignature: state.reasoningSignature }));
|
|
462
467
|
if (state.textSignature !== undefined)
|
|
463
|
-
lifecycle = Lifecycle.textEnd(lifecycle, events, "text-0",
|
|
468
|
+
lifecycle = Lifecycle.textEnd(lifecycle, events, "text-0", providerMetadata(state.providerMetadataKey, { thoughtSignature: state.textSignature }));
|
|
464
469
|
Lifecycle.finish(lifecycle, events, {
|
|
465
470
|
reason: {
|
|
466
471
|
normalized: promptBlockReason === undefined ? mapFinishReason(finishReason, state.hasToolCalls) : "content-filter",
|
|
467
472
|
raw: finishReason,
|
|
468
473
|
},
|
|
469
474
|
usage: state.usage,
|
|
470
|
-
providerMetadata: state.promptFeedback === undefined
|
|
475
|
+
providerMetadata: state.promptFeedback === undefined
|
|
476
|
+
? undefined
|
|
477
|
+
: providerMetadata(state.providerMetadataKey, { promptFeedback: state.promptFeedback }),
|
|
471
478
|
});
|
|
472
479
|
return events;
|
|
473
480
|
};
|
|
@@ -475,7 +482,9 @@ const step = (state, event) => {
|
|
|
475
482
|
const nextState = {
|
|
476
483
|
...state,
|
|
477
484
|
promptFeedback: event.promptFeedback ?? state.promptFeedback,
|
|
478
|
-
usage: event.usageMetadata
|
|
485
|
+
usage: event.usageMetadata
|
|
486
|
+
? (mapUsage(event.usageMetadata, state.providerMetadataKey) ?? state.usage)
|
|
487
|
+
: state.usage,
|
|
479
488
|
};
|
|
480
489
|
const candidate = event.candidates?.[0];
|
|
481
490
|
if (!candidate?.content)
|
|
@@ -510,11 +519,13 @@ const step = (state, event) => {
|
|
|
510
519
|
textSignature = signature;
|
|
511
520
|
if ("text" in part && part.text.length > 0) {
|
|
512
521
|
if (part.thought) {
|
|
513
|
-
lifecycle = Lifecycle.reasoningDelta(lifecycle, events, "reasoning-0", part.text, signature ?
|
|
522
|
+
lifecycle = Lifecycle.reasoningDelta(lifecycle, events, "reasoning-0", part.text, signature ? providerMetadata(state.providerMetadataKey, { thoughtSignature: signature }) : undefined);
|
|
514
523
|
continue;
|
|
515
524
|
}
|
|
516
|
-
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningSignature
|
|
517
|
-
|
|
525
|
+
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningSignature
|
|
526
|
+
? providerMetadata(state.providerMetadataKey, { thoughtSignature: reasoningSignature })
|
|
527
|
+
: undefined);
|
|
528
|
+
lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", part.text, textSignature ? providerMetadata(state.providerMetadataKey, { thoughtSignature: textSignature }) : undefined);
|
|
518
529
|
textSignature = undefined;
|
|
519
530
|
continue;
|
|
520
531
|
}
|
|
@@ -529,14 +540,16 @@ const step = (state, event) => {
|
|
|
529
540
|
if (supplied !== undefined)
|
|
530
541
|
seenCallIds.add(supplied);
|
|
531
542
|
const id = supplied !== undefined && !duplicate ? supplied : `tool_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
532
|
-
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningSignature
|
|
543
|
+
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningSignature
|
|
544
|
+
? providerMetadata(state.providerMetadataKey, { thoughtSignature: reasoningSignature })
|
|
545
|
+
: undefined);
|
|
533
546
|
lifecycle = Lifecycle.stepStart(lifecycle, events);
|
|
534
547
|
events.push(LLMEvent.toolCall({
|
|
535
548
|
id,
|
|
536
549
|
name: part.functionCall.name,
|
|
537
550
|
input,
|
|
538
551
|
providerMetadata: part.thoughtSignature
|
|
539
|
-
?
|
|
552
|
+
? providerMetadata(state.providerMetadataKey, { thoughtSignature: part.thoughtSignature })
|
|
540
553
|
: undefined,
|
|
541
554
|
}));
|
|
542
555
|
hasToolCalls = true;
|
|
@@ -572,6 +585,7 @@ export const protocol = Protocol.make({
|
|
|
572
585
|
event: Protocol.jsonEvent(GeminiEvent),
|
|
573
586
|
initial: (request) => ({
|
|
574
587
|
route: `${request.model.provider}/${request.model.route.id}`,
|
|
588
|
+
providerMetadataKey: request.model.route.providerMetadataKey ?? String(request.model.provider),
|
|
575
589
|
hasToolCalls: false,
|
|
576
590
|
lifecycle: Lifecycle.initial(),
|
|
577
591
|
}),
|
|
@@ -269,6 +269,7 @@ interface PendingToolDelta {
|
|
|
269
269
|
readonly input: string;
|
|
270
270
|
}
|
|
271
271
|
export interface ParserState {
|
|
272
|
+
readonly providerMetadataKey: string;
|
|
272
273
|
readonly tools: ToolStream.State<number>;
|
|
273
274
|
readonly pendingTools: Partial<Record<number, PendingToolDelta>>;
|
|
274
275
|
readonly toolCallEvents: ReadonlyArray<LLMEvent>;
|
|
@@ -207,16 +207,16 @@ const lowerMedia = Effect.fn("OpenAIChat.lowerMedia")(function* (part) {
|
|
|
207
207
|
return { type: "image_url", image_url: { url: media.dataUrl } };
|
|
208
208
|
});
|
|
209
209
|
const openAICompatibleReasoningContent = (native) => isRecord(native) && typeof native.reasoning_content === "string" ? native.reasoning_content : undefined;
|
|
210
|
-
const reasoningField = (part) => {
|
|
211
|
-
const field = part.providerMetadata?.
|
|
210
|
+
const reasoningField = (part, providerMetadataKey) => {
|
|
211
|
+
const field = part.providerMetadata?.[providerMetadataKey]?.reasoningField;
|
|
212
212
|
return typeof field === "string" ? field : undefined;
|
|
213
213
|
};
|
|
214
|
-
const reasoningDetails = (parts, native) => {
|
|
214
|
+
const reasoningDetails = (parts, native, providerMetadataKey) => {
|
|
215
215
|
const observed = parts.flatMap((part) => {
|
|
216
|
-
const details = part.providerMetadata?.
|
|
216
|
+
const details = part.providerMetadata?.[providerMetadataKey]?.reasoningDetails;
|
|
217
217
|
return Array.isArray(details) ? details : [];
|
|
218
218
|
});
|
|
219
|
-
if (parts.some((part) => Array.isArray(part.providerMetadata?.
|
|
219
|
+
if (parts.some((part) => Array.isArray(part.providerMetadata?.[providerMetadataKey]?.reasoningDetails)))
|
|
220
220
|
return observed;
|
|
221
221
|
if (isRecord(native) && Array.isArray(native.reasoning_details))
|
|
222
222
|
return native.reasoning_details;
|
|
@@ -262,10 +262,12 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
|
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
const text = reasoning.map((part) => part.text).join("");
|
|
265
|
-
const details = reasoningDetails(reasoning, message.native?.openaiCompatible);
|
|
266
|
-
const observedField = reasoning
|
|
265
|
+
const details = reasoningDetails(reasoning, message.native?.openaiCompatible, options.providerMetadataKey);
|
|
266
|
+
const observedField = reasoning
|
|
267
|
+
.map((part) => reasoningField(part, options.providerMetadataKey))
|
|
268
|
+
.find((value) => value !== undefined);
|
|
267
269
|
const nativeReasoning = openAICompatibleReasoningContent(message.native?.openaiCompatible);
|
|
268
|
-
const fullyStructured = reasoning.every((part) => Array.isArray(part.providerMetadata?.
|
|
270
|
+
const fullyStructured = reasoning.every((part) => Array.isArray(part.providerMetadata?.[options.providerMetadataKey]?.reasoningDetails));
|
|
269
271
|
const field = (() => {
|
|
270
272
|
if (configuredField !== undefined && (requireReasoning || reasoning.length > 0 || nativeReasoning !== undefined))
|
|
271
273
|
return configuredField;
|
|
@@ -359,6 +361,7 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request,
|
|
|
359
361
|
const mistral = ["mistral", "devstral", "codestral", "pixtral", "mixtral"].some((family) => modelID.includes(family));
|
|
360
362
|
const lowering = {
|
|
361
363
|
...options,
|
|
364
|
+
providerMetadataKey: request.model.route.providerMetadataKey ?? String(request.model.provider),
|
|
362
365
|
toolCallID: (id) => {
|
|
363
366
|
if (mistral)
|
|
364
367
|
return id
|
|
@@ -644,7 +647,7 @@ const mapFinishReason = Effect.fn("OpenAIChat.mapFinishReason")(function* (event
|
|
|
644
647
|
// Providers differ on cache-hit location: OpenAI uses
|
|
645
648
|
// `prompt_tokens_details.cached_tokens`, DeepSeek uses
|
|
646
649
|
// `prompt_cache_hit_tokens`, and Zai uses top-level `cached_tokens`.
|
|
647
|
-
const mapUsage = (usage) => {
|
|
650
|
+
const mapUsage = (usage, providerMetadataKey) => {
|
|
648
651
|
if (!usage)
|
|
649
652
|
return undefined;
|
|
650
653
|
const input = usage.prompt_tokens ?? undefined;
|
|
@@ -664,7 +667,7 @@ const mapUsage = (usage) => {
|
|
|
664
667
|
cacheWriteInputTokens: cacheWrite,
|
|
665
668
|
reasoningTokens: reasoning,
|
|
666
669
|
totalTokens: ProviderShared.totalTokens(input, output, usage.total_tokens ?? undefined),
|
|
667
|
-
providerMetadata: {
|
|
670
|
+
providerMetadata: { [providerMetadataKey]: usage },
|
|
668
671
|
});
|
|
669
672
|
};
|
|
670
673
|
const toolIndexByID = (tools, pendingTools, id) => {
|
|
@@ -725,8 +728,8 @@ const conflictingReasoningTextDetails = (previous, current) => conflictingDetail
|
|
|
725
728
|
conflictingDetailValue(previous.format, current.format) ||
|
|
726
729
|
(Boolean(previous.signature) && Boolean(current.signature) && previous.signature !== current.signature);
|
|
727
730
|
const conflictingDetailValue = (previous, current) => previous !== undefined && previous !== null && current !== undefined && current !== null && previous !== current;
|
|
728
|
-
const reasoningMetadata = (field, details) => ({
|
|
729
|
-
|
|
731
|
+
const reasoningMetadata = (providerMetadataKey, field, details) => ({
|
|
732
|
+
[providerMetadataKey]: {
|
|
730
733
|
...(field ? { reasoningField: field } : {}),
|
|
731
734
|
...(details ? { reasoningDetails: details } : {}),
|
|
732
735
|
},
|
|
@@ -751,7 +754,9 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
751
754
|
// Moonshot (and a few other OpenAI-compatible providers) attach usage to
|
|
752
755
|
// `choice.usage` instead of the top-level `usage` field.
|
|
753
756
|
const choiceUsage = choice?.usage;
|
|
754
|
-
const usage = mapUsage(event.usage
|
|
757
|
+
const usage = mapUsage(event.usage, state.providerMetadataKey) ??
|
|
758
|
+
(choiceUsage ? mapUsage(choiceUsage, state.providerMetadataKey) : undefined) ??
|
|
759
|
+
state.usage;
|
|
755
760
|
const rawFinishReason = choice?.finish_reason;
|
|
756
761
|
const finishReason = rawFinishReason
|
|
757
762
|
? {
|
|
@@ -782,7 +787,7 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
782
787
|
if (detailDelta !== undefined)
|
|
783
788
|
appendReasoningDetails(state.reasoningDetails, detailDelta);
|
|
784
789
|
const reasoningDetailsObserved = state.reasoningDetailsObserved || detailDelta !== undefined;
|
|
785
|
-
const deltaMetadata = reasoningMetadata(reasoningField);
|
|
790
|
+
const deltaMetadata = reasoningMetadata(state.providerMetadataKey, reasoningField);
|
|
786
791
|
const text = detailDelta?.length ? (detailText(detailDelta) ?? reasoning?.text) : reasoning?.text;
|
|
787
792
|
if (text !== undefined)
|
|
788
793
|
lifecycle = Lifecycle.reasoningDelta(lifecycle, events, "reasoning-0", text, deltaMetadata);
|
|
@@ -792,11 +797,11 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
792
797
|
lifecycle = Lifecycle.reasoningStart(lifecycle, events, "reasoning-0", deltaMetadata);
|
|
793
798
|
const reasoningEmitted = state.reasoningEmitted || lifecycle.reasoning.has("reasoning-0");
|
|
794
799
|
if (delta?.content) {
|
|
795
|
-
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
|
|
800
|
+
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(state.providerMetadataKey, reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
|
|
796
801
|
lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", delta.content);
|
|
797
802
|
}
|
|
798
803
|
if (delta?.refusal) {
|
|
799
|
-
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
|
|
804
|
+
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(state.providerMetadataKey, reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
|
|
800
805
|
lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", delta.refusal);
|
|
801
806
|
}
|
|
802
807
|
// Compatible providers may omit indexes. Prefer durable identity, then use
|
|
@@ -841,6 +846,7 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
841
846
|
: undefined;
|
|
842
847
|
return [
|
|
843
848
|
{
|
|
849
|
+
providerMetadataKey: state.providerMetadataKey,
|
|
844
850
|
tools: finished?.tools ?? tools,
|
|
845
851
|
pendingTools,
|
|
846
852
|
toolCallEvents: finished?.events ?? state.toolCallEvents,
|
|
@@ -880,9 +886,9 @@ const finishEvents = Effect.fn("OpenAIChat.finishEvents")(function* (state) {
|
|
|
880
886
|
normalized: state.finishReason.normalized === "stop" && hasToolCalls ? "tool-calls" : state.finishReason.normalized,
|
|
881
887
|
}
|
|
882
888
|
: { normalized: hasToolCalls ? "tool-calls" : "stop" };
|
|
883
|
-
const metadata = reasoningMetadata(state.reasoningField, state.reasoningDetailsObserved ? state.reasoningDetails : undefined);
|
|
889
|
+
const metadata = reasoningMetadata(state.providerMetadataKey, state.reasoningField, state.reasoningDetailsObserved ? state.reasoningDetails : undefined);
|
|
884
890
|
const started = state.reasoningDetailsObserved && !state.reasoningEmitted
|
|
885
|
-
? Lifecycle.reasoningStart(state.lifecycle, events, "reasoning-0", reasoningMetadata(state.reasoningField))
|
|
891
|
+
? Lifecycle.reasoningStart(state.lifecycle, events, "reasoning-0", reasoningMetadata(state.providerMetadataKey, state.reasoningField))
|
|
886
892
|
: state.lifecycle;
|
|
887
893
|
const ended = Lifecycle.reasoningEnd(started, events, "reasoning-0", metadata);
|
|
888
894
|
const lifecycle = toolCallEvents.length ? Lifecycle.stepStart(ended, events) : ended;
|
|
@@ -908,6 +914,7 @@ export const protocol = Protocol.make({
|
|
|
908
914
|
stream: {
|
|
909
915
|
event: Protocol.jsonEvent(OpenAIChatEvent),
|
|
910
916
|
initial: (request) => ({
|
|
917
|
+
providerMetadataKey: request.model.route.providerMetadataKey ?? String(request.model.provider),
|
|
911
918
|
tools: ToolStream.empty(),
|
|
912
919
|
pendingTools: {},
|
|
913
920
|
toolCallEvents: [],
|
|
@@ -17,6 +17,7 @@ export interface Settings extends ProviderPackage.Settings {
|
|
|
17
17
|
readonly baseURL?: string;
|
|
18
18
|
readonly credentials?: Credentials;
|
|
19
19
|
readonly region?: string;
|
|
20
|
+
readonly topP?: number;
|
|
20
21
|
readonly providerOptions?: OpenAIProviderOptionsInput;
|
|
21
22
|
}
|
|
22
23
|
export declare const routes: (Route<{
|
|
@@ -9,7 +9,7 @@ export const id = ProviderID.make("amazon-bedrock");
|
|
|
9
9
|
const responsesRoute = Route.make({
|
|
10
10
|
id: "bedrock-mantle-responses",
|
|
11
11
|
provider: id,
|
|
12
|
-
providerMetadataKey:
|
|
12
|
+
providerMetadataKey: "mantle",
|
|
13
13
|
protocol: OpenAIResponses.protocol,
|
|
14
14
|
endpoint: OpenAIResponses.route.endpoint,
|
|
15
15
|
auth: OpenAIResponses.route.auth,
|
|
@@ -19,6 +19,7 @@ const responsesRoute = Route.make({
|
|
|
19
19
|
const chatRoute = OpenAIChat.route.with({
|
|
20
20
|
id: "bedrock-mantle-chat",
|
|
21
21
|
provider: id,
|
|
22
|
+
providerMetadataKey: "mantle",
|
|
22
23
|
});
|
|
23
24
|
export const routes = [responsesRoute, chatRoute];
|
|
24
25
|
const configuredRoute = (route, input) => {
|
|
@@ -63,6 +64,7 @@ const config = (settings) => {
|
|
|
63
64
|
apiKey: settings.auth === "sigv4" ? undefined : settings.apiKey,
|
|
64
65
|
baseURL: settings.baseURL,
|
|
65
66
|
credentials: settings.credentials,
|
|
67
|
+
generation: settings.topP === undefined ? undefined : { topP: settings.topP },
|
|
66
68
|
headers: settings.headers === undefined ? undefined : { ...settings.headers },
|
|
67
69
|
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
|
68
70
|
providerOptions: settings.providerOptions,
|
|
@@ -10,6 +10,7 @@ const configuredRoute = (input) => {
|
|
|
10
10
|
return BedrockConverse.route.with({
|
|
11
11
|
...rest,
|
|
12
12
|
provider: id,
|
|
13
|
+
providerMetadataKey: "bedrock",
|
|
13
14
|
endpoint: { baseURL: baseURL ?? bedrockBaseURL(resolvedRegion) },
|
|
14
15
|
auth: apiKey === undefined ? BedrockConverse.sigV4Auth(credentials) : Auth.bearer(apiKey),
|
|
15
16
|
});
|
|
@@ -38,7 +38,7 @@ const protocol = {
|
|
|
38
38
|
const route = Route.make({
|
|
39
39
|
id: "google-vertex-gemini",
|
|
40
40
|
provider: id,
|
|
41
|
-
providerMetadataKey: "
|
|
41
|
+
providerMetadataKey: "vertex",
|
|
42
42
|
protocol,
|
|
43
43
|
endpoint: Endpoint.path(({ request }) => {
|
|
44
44
|
const model = String(request.model.id);
|
|
@@ -84,6 +84,7 @@ const bodyOptions = (input) => {
|
|
|
84
84
|
export const route = Route.make({
|
|
85
85
|
id: ADAPTER,
|
|
86
86
|
provider: profile.provider,
|
|
87
|
+
providerMetadataKey: "openrouter",
|
|
87
88
|
protocol,
|
|
88
89
|
endpoint: Endpoint.path("/chat/completions", { baseURL: profile.baseURL }),
|
|
89
90
|
framing: Framing.sse,
|
package/dist/route/client.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export interface RouteDefaultsInput {
|
|
|
49
49
|
export interface RoutePatch<Body, Prepared> extends RouteDefaultsInput {
|
|
50
50
|
readonly id?: string;
|
|
51
51
|
readonly provider?: string | ProviderID;
|
|
52
|
+
readonly providerMetadataKey?: string;
|
|
52
53
|
readonly auth?: Auth.Definition;
|
|
53
54
|
readonly transport?: Transport<Body, Prepared, unknown>;
|
|
54
55
|
readonly endpoint?: EndpointPatch<Body>;
|
package/dist/route/client.js
CHANGED
|
@@ -98,11 +98,15 @@ function makeFromTransport(input) {
|
|
|
98
98
|
defaults: routeInput.defaults ?? {},
|
|
99
99
|
body: protocol.body,
|
|
100
100
|
with: (patch) => {
|
|
101
|
-
const { id, provider, auth, transport, endpoint, ...defaults } = patch;
|
|
101
|
+
const { id, provider, providerMetadataKey, auth, transport, endpoint, ...defaults } = patch;
|
|
102
102
|
return build({
|
|
103
103
|
...routeInput,
|
|
104
104
|
id: id ?? routeInput.id,
|
|
105
105
|
provider: provider ?? routeInput.provider,
|
|
106
|
+
providerMetadataKey: providerMetadataKey ??
|
|
107
|
+
(provider !== undefined && String(provider) !== String(routeInput.provider)
|
|
108
|
+
? String(provider)
|
|
109
|
+
: routeInput.providerMetadataKey),
|
|
106
110
|
auth: auth ?? routeInput.auth,
|
|
107
111
|
endpoint: endpoint ? Endpoint.merge(routeInput.endpoint, endpoint) : routeInput.endpoint,
|
|
108
112
|
transport: transport ?? routeInput.transport,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-18332",
|
|
4
4
|
"name": "@opencode-ai/ai",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@clack/prompts": "1.0.0-alpha.1",
|
|
32
32
|
"@effect/platform-node": "4.0.0-rc.111",
|
|
33
|
-
"@opencode-ai/http-recorder": "0.0.0-dev-
|
|
33
|
+
"@opencode-ai/http-recorder": "0.0.0-dev-18332",
|
|
34
34
|
"@tsconfig/bun": "1.0.9",
|
|
35
35
|
"@types/bun": "1.3.13",
|
|
36
36
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@smithy/eventstream-codec": "4.2.14",
|
|
41
41
|
"@smithy/util-utf8": "4.2.2",
|
|
42
|
-
"@opencode-ai/schema": "0.0.0-dev-
|
|
42
|
+
"@opencode-ai/schema": "0.0.0-dev-18332",
|
|
43
43
|
"aws4fetch": "1.0.20",
|
|
44
44
|
"effect": "4.0.0-rc.111",
|
|
45
45
|
"google-auth-library": "10.5.0"
|