@opencode-ai/ai 0.0.0-beta-18219 → 0.0.0-beta-18269
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/cache-policy.js +1 -1
- package/dist/protocols/anthropic-messages.js +8 -4
- package/dist/protocols/open-responses.d.ts +231 -25
- package/dist/protocols/open-responses.js +98 -79
- package/dist/protocols/openai-chat.d.ts +1 -0
- package/dist/protocols/openai-chat.js +36 -17
- package/dist/protocols/openai-compatible-responses.d.ts +37 -3
- package/dist/protocols/openai-responses.d.ts +403 -50
- package/dist/protocols/openai-responses.js +30 -21
- package/dist/protocols/shared.d.ts +3 -4
- package/dist/protocols/shared.js +18 -5
- package/dist/protocols/utils/open-responses-options.d.ts +0 -1
- package/dist/protocols/utils/open-responses-options.js +0 -1
- package/dist/protocols/xai-responses.d.ts +52 -3
- package/dist/protocols/xai-responses.js +31 -1
- package/dist/provider-error.js +4 -2
- package/dist/providers/amazon-bedrock-mantle.d.ts +65 -3
- package/dist/providers/azure.d.ts +65 -3
- package/dist/providers/cerebras.d.ts +228 -0
- package/dist/providers/cerebras.js +35 -0
- package/dist/providers/deepinfra.d.ts +228 -0
- package/dist/providers/deepinfra.js +38 -0
- package/dist/providers/google-vertex-responses.d.ts +37 -3
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +3 -0
- package/dist/providers/openai-compatible-responses.d.ts +37 -3
- package/dist/providers/openai.d.ts +65 -3
- package/dist/providers/togetherai.d.ts +228 -0
- package/dist/providers/togetherai.js +35 -0
- package/dist/schema/options.d.ts +2 -0
- package/dist/schema/options.js +2 -0
- package/package.json +3 -3
|
@@ -54,10 +54,43 @@ const OpenResponsesReasoningItem = Schema.Struct({
|
|
|
54
54
|
summary: Schema.Array(OpenResponsesReasoningSummaryText),
|
|
55
55
|
encrypted_content: optionalNull(Schema.String),
|
|
56
56
|
});
|
|
57
|
-
const
|
|
58
|
-
type: Schema.tag("
|
|
57
|
+
const OpenResponsesWebSearchCall = Schema.StructWithRest(Schema.Struct({
|
|
58
|
+
type: Schema.tag("web_search_call"),
|
|
59
59
|
id: Schema.String,
|
|
60
|
-
|
|
60
|
+
status: Schema.optional(Schema.String),
|
|
61
|
+
action: optionalNull(JsonObject),
|
|
62
|
+
}), [JsonObject]);
|
|
63
|
+
const OpenResponsesFileSearchCall = Schema.StructWithRest(Schema.Struct({
|
|
64
|
+
type: Schema.tag("file_search_call"),
|
|
65
|
+
id: Schema.String,
|
|
66
|
+
status: Schema.optional(Schema.String),
|
|
67
|
+
queries: Schema.optional(Schema.Array(Schema.String)),
|
|
68
|
+
results: optionalNull(Schema.Array(JsonObject)),
|
|
69
|
+
}), [JsonObject]);
|
|
70
|
+
const OpenResponsesCodeInterpreterCall = Schema.StructWithRest(Schema.Struct({
|
|
71
|
+
type: Schema.tag("code_interpreter_call"),
|
|
72
|
+
id: Schema.String,
|
|
73
|
+
status: Schema.optional(Schema.String),
|
|
74
|
+
code: optionalNull(Schema.String),
|
|
75
|
+
container_id: optionalNull(Schema.String),
|
|
76
|
+
outputs: optionalNull(Schema.Array(JsonObject)),
|
|
77
|
+
}), [JsonObject]);
|
|
78
|
+
const OpenResponsesMCPCall = Schema.StructWithRest(Schema.Struct({
|
|
79
|
+
type: Schema.tag("mcp_call"),
|
|
80
|
+
id: Schema.String,
|
|
81
|
+
status: Schema.optional(Schema.String),
|
|
82
|
+
server_label: Schema.optional(Schema.String),
|
|
83
|
+
name: Schema.optional(Schema.String),
|
|
84
|
+
arguments: Schema.optional(Schema.String),
|
|
85
|
+
output: optionalNull(Schema.String),
|
|
86
|
+
error: Schema.optional(Schema.Unknown),
|
|
87
|
+
}), [JsonObject]);
|
|
88
|
+
export const HostedToolItem = Schema.Union([
|
|
89
|
+
OpenResponsesWebSearchCall,
|
|
90
|
+
OpenResponsesFileSearchCall,
|
|
91
|
+
OpenResponsesCodeInterpreterCall,
|
|
92
|
+
OpenResponsesMCPCall,
|
|
93
|
+
]);
|
|
61
94
|
// `function_call_output.output` accepts either a plain string or an ordered
|
|
62
95
|
// array of content items so tools can return images and files in addition to text.
|
|
63
96
|
// https://www.openresponses.org/reference
|
|
@@ -83,7 +116,6 @@ export const InputItem = Schema.Union([
|
|
|
83
116
|
phase: Schema.optionalKey(MessagePhase),
|
|
84
117
|
}),
|
|
85
118
|
OpenResponsesReasoningItem,
|
|
86
|
-
OpenResponsesItemReference,
|
|
87
119
|
Schema.Struct({
|
|
88
120
|
type: Schema.tag("function_call"),
|
|
89
121
|
id: Schema.optionalKey(Schema.String),
|
|
@@ -96,6 +128,7 @@ export const InputItem = Schema.Union([
|
|
|
96
128
|
call_id: Schema.String,
|
|
97
129
|
output: OpenResponsesFunctionCallOutput,
|
|
98
130
|
}),
|
|
131
|
+
HostedToolItem,
|
|
99
132
|
]);
|
|
100
133
|
export const Tool = Schema.Struct({
|
|
101
134
|
type: Schema.tag("function"),
|
|
@@ -248,41 +281,36 @@ export const lowerToolChoice = (protocolName, toolChoice) => ProviderShared.matc
|
|
|
248
281
|
required: () => "required",
|
|
249
282
|
tool: (toolName) => ({ type: "function", name: toolName }),
|
|
250
283
|
});
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
// resending; anything else is treated as absent so the item is resent without
|
|
254
|
-
// an id (or skipped, for items that cannot be expressed without one).
|
|
255
|
-
const ITEM_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
284
|
+
// Server-issued item ids need a nonempty prefix and suffix, but the prefix is
|
|
285
|
+
// provider-defined and does not necessarily identify the item's semantic type.
|
|
256
286
|
const itemID = (providerMetadata, providerMetadataKey) => {
|
|
257
287
|
const metadata = providerMetadata?.[providerMetadataKey];
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
: undefined;
|
|
288
|
+
if (!ProviderShared.isRecord(metadata) || typeof metadata.itemId !== "string")
|
|
289
|
+
return undefined;
|
|
290
|
+
const separator = metadata.itemId.indexOf("_");
|
|
291
|
+
return separator > 0 && separator < metadata.itemId.length - 1 ? metadata.itemId : undefined;
|
|
263
292
|
};
|
|
264
|
-
const
|
|
265
|
-
const lowerToolCall = (part, providerMetadataKey, extension) => {
|
|
293
|
+
const lowerToolCall = (part, providerMetadataKey) => {
|
|
266
294
|
const id = itemID(part.providerMetadata, providerMetadataKey);
|
|
267
295
|
return {
|
|
268
296
|
type: "function_call",
|
|
269
|
-
...(
|
|
297
|
+
...(id === undefined ? {} : { id }),
|
|
270
298
|
call_id: part.id,
|
|
271
299
|
name: part.name,
|
|
272
300
|
arguments: ProviderShared.encodeJson(part.input),
|
|
273
301
|
};
|
|
274
302
|
};
|
|
275
|
-
const lowerReasoning = (part, providerMetadataKey
|
|
303
|
+
const lowerReasoning = (part, providerMetadataKey) => {
|
|
276
304
|
const metadata = part.providerMetadata?.[providerMetadataKey];
|
|
277
|
-
|
|
278
|
-
if (!ProviderShared.isRecord(metadata) || !acceptsItemID(extension, "reasoning", id))
|
|
305
|
+
if (!ProviderShared.isRecord(metadata))
|
|
279
306
|
return undefined;
|
|
307
|
+
const id = itemID(part.providerMetadata, providerMetadataKey);
|
|
280
308
|
const encryptedContent = typeof metadata.reasoningEncryptedContent === "string" || metadata.reasoningEncryptedContent === null
|
|
281
309
|
? metadata.reasoningEncryptedContent
|
|
282
310
|
: undefined;
|
|
283
311
|
return {
|
|
284
312
|
type: "reasoning",
|
|
285
|
-
id,
|
|
313
|
+
...(id === undefined ? {} : { id }),
|
|
286
314
|
summary: part.text.length > 0 ? [{ type: "summary_text", text: part.text }] : [],
|
|
287
315
|
encrypted_content: encryptedContent,
|
|
288
316
|
};
|
|
@@ -341,9 +369,7 @@ const lowerToolResultOutput = Effect.fnUntraced(function* (part, request, extens
|
|
|
341
369
|
return yield* Effect.forEach(content, (item) => lowerToolResultContentItem(item, request, extension));
|
|
342
370
|
});
|
|
343
371
|
const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (request, extension) {
|
|
344
|
-
const
|
|
345
|
-
const input = [...system];
|
|
346
|
-
const store = OpenResponsesOptions.resolve(request).store;
|
|
372
|
+
const input = [];
|
|
347
373
|
const providerMetadataKey = request.model.route.providerMetadataKey ?? "openresponses";
|
|
348
374
|
for (const message of request.messages) {
|
|
349
375
|
if (message.role === "system") {
|
|
@@ -363,15 +389,13 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
|
|
|
363
389
|
if (message.role === "assistant") {
|
|
364
390
|
const content = [];
|
|
365
391
|
const reasoningItems = {};
|
|
366
|
-
const
|
|
367
|
-
const hostedToolReferences = new Set();
|
|
392
|
+
const hostedToolItems = new Set();
|
|
368
393
|
const flushText = () => {
|
|
369
394
|
if (content.length === 0)
|
|
370
395
|
return;
|
|
371
396
|
const groups = content.reduce((groups, part) => {
|
|
372
397
|
const metadata = part.providerMetadata?.[providerMetadataKey];
|
|
373
|
-
const
|
|
374
|
-
const id = acceptsItemID(extension, "message", rawID) ? rawID : undefined;
|
|
398
|
+
const id = itemID(part.providerMetadata, providerMetadataKey);
|
|
375
399
|
const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase) : undefined;
|
|
376
400
|
const group = groups.at(-1);
|
|
377
401
|
if (group && group.id === id && group.phase === phase)
|
|
@@ -396,23 +420,18 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
|
|
|
396
420
|
}
|
|
397
421
|
if (part.type === "reasoning") {
|
|
398
422
|
flushText();
|
|
399
|
-
const reasoning = lowerReasoning(part, providerMetadataKey
|
|
423
|
+
const reasoning = lowerReasoning(part, providerMetadataKey);
|
|
400
424
|
if (!reasoning)
|
|
401
425
|
continue;
|
|
402
|
-
|
|
403
|
-
if (!reasoningReferences.has(reasoning.id))
|
|
404
|
-
input.push({ type: "item_reference", id: reasoning.id });
|
|
405
|
-
reasoningReferences.add(reasoning.id);
|
|
406
|
-
continue;
|
|
407
|
-
}
|
|
408
|
-
const existing = reasoningItems[reasoning.id];
|
|
426
|
+
const existing = reasoning.id === undefined ? undefined : reasoningItems[reasoning.id];
|
|
409
427
|
if (existing) {
|
|
410
428
|
existing.summary.push(...reasoning.summary);
|
|
411
429
|
if (typeof reasoning.encrypted_content === "string")
|
|
412
430
|
existing.encrypted_content = reasoning.encrypted_content;
|
|
413
431
|
continue;
|
|
414
432
|
}
|
|
415
|
-
|
|
433
|
+
if (reasoning.id !== undefined)
|
|
434
|
+
reasoningItems[reasoning.id] = reasoning;
|
|
416
435
|
input.push(reasoning);
|
|
417
436
|
continue;
|
|
418
437
|
}
|
|
@@ -420,28 +439,31 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
|
|
|
420
439
|
flushText();
|
|
421
440
|
if (part.providerExecuted === true)
|
|
422
441
|
continue;
|
|
423
|
-
input.push(lowerToolCall(part, providerMetadataKey
|
|
442
|
+
input.push(lowerToolCall(part, providerMetadataKey));
|
|
424
443
|
continue;
|
|
425
444
|
}
|
|
426
445
|
if (part.type === "tool-result" && part.providerExecuted === true) {
|
|
427
446
|
flushText();
|
|
428
447
|
const id = itemID(part.providerMetadata, providerMetadataKey);
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if (store === false) {
|
|
433
|
-
// The server is not storing this exchange, so the tool outcome has to
|
|
434
|
-
// travel in the input. Non-content results degrade to their text form.
|
|
435
|
-
const content = part.result.type === "content"
|
|
448
|
+
const hosted = part.result.type !== "json"
|
|
449
|
+
? undefined
|
|
450
|
+
: Schema.is(HostedToolItem)(part.result.value)
|
|
436
451
|
? part.result.value
|
|
437
|
-
:
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
452
|
+
: extension.lowerHostedToolItem?.(part.result.value);
|
|
453
|
+
if (id !== undefined && hosted?.id === id) {
|
|
454
|
+
if (!hostedToolItems.has(id)) {
|
|
455
|
+
input.push(hosted);
|
|
456
|
+
hostedToolItems.add(id);
|
|
457
|
+
}
|
|
458
|
+
continue;
|
|
442
459
|
}
|
|
443
|
-
|
|
444
|
-
|
|
460
|
+
const content = part.result.type === "content"
|
|
461
|
+
? part.result.value
|
|
462
|
+
: [{ type: "text", text: ProviderShared.toolResultText(part) }];
|
|
463
|
+
input.push({
|
|
464
|
+
role: "user",
|
|
465
|
+
content: yield* Effect.forEach(content, (item) => lowerHostedToolResultContentItem(item, request, extension)),
|
|
466
|
+
});
|
|
445
467
|
continue;
|
|
446
468
|
}
|
|
447
469
|
return yield* ProviderShared.unsupportedContent(extension.name, "assistant", [
|
|
@@ -468,10 +490,11 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
|
|
|
468
490
|
});
|
|
469
491
|
const lowerOptions = (request) => {
|
|
470
492
|
const options = OpenResponsesOptions.resolve(request);
|
|
493
|
+
const instructions = ProviderShared.joinText(request.system);
|
|
471
494
|
const cacheKey = ProviderShared.promptCacheKey(request);
|
|
472
495
|
const parallelToolCalls = resolveParallelToolCalls(request);
|
|
473
496
|
return {
|
|
474
|
-
...(
|
|
497
|
+
...(instructions ? { instructions } : {}),
|
|
475
498
|
...(options.store !== undefined ? { store: options.store } : {}),
|
|
476
499
|
...(options.metadata ? { metadata: options.metadata } : {}),
|
|
477
500
|
...(options.safetyIdentifier ? { safety_identifier: options.safetyIdentifier } : {}),
|
|
@@ -675,26 +698,24 @@ const onOutputItemAdded = (state, event) => {
|
|
|
675
698
|
events,
|
|
676
699
|
];
|
|
677
700
|
}
|
|
678
|
-
if (item?.type !== "function_call" || !item.
|
|
701
|
+
if (item?.type !== "function_call" || !item.call_id)
|
|
679
702
|
return [state, NO_EVENTS];
|
|
680
|
-
const
|
|
703
|
+
const id = item.id ?? item.call_id;
|
|
704
|
+
const metadata = item.id ? providerMetadata(state, { itemId: item.id }) : undefined;
|
|
681
705
|
const events = [];
|
|
682
706
|
const lifecycle = Lifecycle.stepStart(state.lifecycle, events);
|
|
683
707
|
return [
|
|
684
708
|
{
|
|
685
709
|
...state,
|
|
686
710
|
lifecycle,
|
|
687
|
-
tools: ToolStream.start(state.tools,
|
|
688
|
-
id: item.call_id
|
|
711
|
+
tools: ToolStream.start(state.tools, id, {
|
|
712
|
+
id: item.call_id,
|
|
689
713
|
name: item.name ?? "",
|
|
690
714
|
input: item.arguments ?? "",
|
|
691
715
|
providerMetadata: metadata,
|
|
692
716
|
}),
|
|
693
717
|
},
|
|
694
|
-
[
|
|
695
|
-
...events,
|
|
696
|
-
LLMEvent.toolInputStart({ id: item.call_id ?? item.id, name: item.name ?? "", providerMetadata: metadata }),
|
|
697
|
-
],
|
|
718
|
+
[...events, LLMEvent.toolInputStart({ id: item.call_id, name: item.name ?? "", providerMetadata: metadata })],
|
|
698
719
|
];
|
|
699
720
|
};
|
|
700
721
|
const onReasoningSummaryPartAdded = (state, event) => {
|
|
@@ -733,25 +754,21 @@ const onReasoningSummaryPartDone = (state, event) => {
|
|
|
733
754
|
const item = state.reasoningItems[event.item_id];
|
|
734
755
|
if (!item)
|
|
735
756
|
return [state, NO_EVENTS];
|
|
736
|
-
const events = [];
|
|
737
757
|
return [
|
|
738
758
|
{
|
|
739
759
|
...state,
|
|
740
|
-
lifecycle: state.store !== false
|
|
741
|
-
? Lifecycle.reasoningEnd(state.lifecycle, events, `${event.item_id}:${event.summary_index}`, providerMetadata(state, { itemId: event.item_id }))
|
|
742
|
-
: state.lifecycle,
|
|
743
760
|
reasoningItems: {
|
|
744
761
|
...state.reasoningItems,
|
|
745
762
|
[event.item_id]: {
|
|
746
763
|
...item,
|
|
747
764
|
summaryParts: {
|
|
748
765
|
...item.summaryParts,
|
|
749
|
-
[event.summary_index]:
|
|
766
|
+
[event.summary_index]: "can-conclude",
|
|
750
767
|
},
|
|
751
768
|
},
|
|
752
769
|
},
|
|
753
770
|
},
|
|
754
|
-
|
|
771
|
+
NO_EVENTS,
|
|
755
772
|
];
|
|
756
773
|
};
|
|
757
774
|
const onFunctionCallArgumentsDelta = Effect.fn("OpenResponses.onFunctionCallArgumentsDelta")(function* (state, event) {
|
|
@@ -801,18 +818,19 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
801
818
|
];
|
|
802
819
|
}
|
|
803
820
|
if (item.type === "function_call") {
|
|
804
|
-
if (!item.
|
|
821
|
+
if (!item.call_id || !item.name)
|
|
805
822
|
return [state, NO_EVENTS];
|
|
806
|
-
const
|
|
823
|
+
const id = item.id ?? item.call_id;
|
|
824
|
+
const tools = state.tools[id]
|
|
807
825
|
? state.tools
|
|
808
|
-
: ToolStream.start(state.tools,
|
|
826
|
+
: ToolStream.start(state.tools, id, {
|
|
809
827
|
id: item.call_id,
|
|
810
828
|
name: item.name,
|
|
811
|
-
providerMetadata: providerMetadata(state, { itemId: item.id }),
|
|
829
|
+
providerMetadata: item.id ? providerMetadata(state, { itemId: item.id }) : undefined,
|
|
812
830
|
});
|
|
813
831
|
const result = item.arguments === undefined
|
|
814
|
-
? yield* ToolStream.finish(state.id, tools,
|
|
815
|
-
: yield* ToolStream.finishWithInput(state.id, tools,
|
|
832
|
+
? yield* ToolStream.finish(state.id, tools, id)
|
|
833
|
+
: yield* ToolStream.finishWithInput(state.id, tools, id, item.arguments);
|
|
816
834
|
const events = [];
|
|
817
835
|
const resultEvents = result.events ?? [];
|
|
818
836
|
const lifecycle = resultEvents.length ? Lifecycle.stepStart(state.lifecycle, events) : state.lifecycle;
|
|
@@ -855,9 +873,10 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
855
873
|
const onResponseFinish = Effect.fn("OpenResponses.onResponseFinish")(function* (state, event) {
|
|
856
874
|
const reconciled = event.type === "response.completed"
|
|
857
875
|
? yield* Effect.reduce(event.response?.output ?? [], () => [state, NO_EVENTS], ([current, events], item) => {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
876
|
+
const id = item.id ?? (item.type === "function_call" ? item.call_id : undefined);
|
|
877
|
+
if (!id ||
|
|
878
|
+
((item.type !== "function_call" || !current.tools[id]) &&
|
|
879
|
+
(item.type !== "reasoning" || !current.reasoningItems[id])))
|
|
861
880
|
return Effect.succeed([current, events]);
|
|
862
881
|
return onOutputItemDone(current, { type: "response.output_item.done", item }).pipe(Effect.map(([next, emitted]) => [next, [...events, ...emitted]]));
|
|
863
882
|
})
|
|
@@ -967,8 +986,9 @@ export const step = (state, input) => {
|
|
|
967
986
|
if (event.type === "response.output_item.added") {
|
|
968
987
|
if (event.item?.type === "message" && !event.item.id)
|
|
969
988
|
return ProviderShared.eventError(state.id, `${event.type} message is missing id`);
|
|
970
|
-
|
|
971
|
-
|
|
989
|
+
const id = event.item?.id ?? (event.item?.type === "function_call" ? event.item.call_id : undefined);
|
|
990
|
+
return Effect.succeed(onOutputItemAdded(event.output_index !== undefined && id
|
|
991
|
+
? { ...state, outputItems: { ...state.outputItems, [event.output_index]: id } }
|
|
972
992
|
: state, event));
|
|
973
993
|
}
|
|
974
994
|
if (event.type === "response.function_call_arguments.delta" || event.type === "response.function_call_arguments.done")
|
|
@@ -1006,7 +1026,6 @@ export const initial = (request, extension = BASE) => ({
|
|
|
1006
1026
|
messageItems: new Set(),
|
|
1007
1027
|
messagePhases: {},
|
|
1008
1028
|
reasoningItems: {},
|
|
1009
|
-
store: OpenResponsesOptions.resolve(request).store,
|
|
1010
1029
|
});
|
|
1011
1030
|
export const protocol = Protocol.make({
|
|
1012
1031
|
id: ADAPTER,
|
|
@@ -285,6 +285,7 @@ export interface ParserState {
|
|
|
285
285
|
}
|
|
286
286
|
interface LoweringOptions {
|
|
287
287
|
readonly cacheControl?: (cache: CacheHint | undefined) => Schema.Schema.Type<typeof OpenAIChatCacheControl> | undefined;
|
|
288
|
+
readonly toolCallID?: (id: string) => string;
|
|
288
289
|
}
|
|
289
290
|
export declare const fromRequest: (request: LLMRequest, options?: LoweringOptions | undefined) => Effect.Effect<{
|
|
290
291
|
reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
|
|
@@ -192,8 +192,8 @@ const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("OpenAI C
|
|
|
192
192
|
required: () => "required",
|
|
193
193
|
tool: (name) => ({ type: "function", function: { name } }),
|
|
194
194
|
});
|
|
195
|
-
const lowerToolCall = (part) => ({
|
|
196
|
-
id: part.id,
|
|
195
|
+
const lowerToolCall = (part, options) => ({
|
|
196
|
+
id: options.toolCallID?.(part.id) ?? part.id,
|
|
197
197
|
type: "function",
|
|
198
198
|
function: {
|
|
199
199
|
name: part.name,
|
|
@@ -241,7 +241,7 @@ const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (mes
|
|
|
241
241
|
};
|
|
242
242
|
return { role: "user", content };
|
|
243
243
|
});
|
|
244
|
-
const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(function* (message, configuredField, options
|
|
244
|
+
const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(function* (message, configuredField, requireReasoning, options) {
|
|
245
245
|
const content = [];
|
|
246
246
|
const reasoning = [];
|
|
247
247
|
const toolCalls = [];
|
|
@@ -257,7 +257,7 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
|
|
|
257
257
|
continue;
|
|
258
258
|
}
|
|
259
259
|
if (part.type === "tool-call") {
|
|
260
|
-
toolCalls.push(lowerToolCall(part));
|
|
260
|
+
toolCalls.push(lowerToolCall(part, options));
|
|
261
261
|
continue;
|
|
262
262
|
}
|
|
263
263
|
}
|
|
@@ -267,22 +267,22 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
|
|
|
267
267
|
const nativeReasoning = openAICompatibleReasoningContent(message.native?.openaiCompatible);
|
|
268
268
|
const fullyStructured = reasoning.every((part) => Array.isArray(part.providerMetadata?.openai?.reasoningDetails));
|
|
269
269
|
const field = (() => {
|
|
270
|
-
if (configuredField !== undefined)
|
|
270
|
+
if (configuredField !== undefined && (requireReasoning || reasoning.length > 0 || nativeReasoning !== undefined))
|
|
271
271
|
return configuredField;
|
|
272
272
|
if (reasoning.length === 0)
|
|
273
|
-
return undefined;
|
|
273
|
+
return requireReasoning ? "reasoning_content" : undefined;
|
|
274
274
|
if (observedField !== undefined)
|
|
275
275
|
return observedField;
|
|
276
276
|
if (nativeReasoning !== undefined)
|
|
277
277
|
return "reasoning_content";
|
|
278
|
-
if (!fullyStructured)
|
|
278
|
+
if (!fullyStructured || requireReasoning)
|
|
279
279
|
return "reasoning_content";
|
|
280
280
|
})();
|
|
281
281
|
const reasoningText = (() => {
|
|
282
282
|
if (configuredField !== undefined)
|
|
283
|
-
return reasoning.length === 0 ? (nativeReasoning ?? "") : text;
|
|
283
|
+
return reasoning.length === 0 ? (nativeReasoning ?? (requireReasoning ? "" : undefined)) : text;
|
|
284
284
|
if (reasoning.length === 0)
|
|
285
|
-
return nativeReasoning;
|
|
285
|
+
return nativeReasoning ?? (requireReasoning ? "" : undefined);
|
|
286
286
|
return text;
|
|
287
287
|
})();
|
|
288
288
|
const cached = message.content.findLast((part) => "cache" in part && part.cache !== undefined);
|
|
@@ -307,7 +307,7 @@ const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (m
|
|
|
307
307
|
if (part.result.type !== "content") {
|
|
308
308
|
messages.push({
|
|
309
309
|
role: "tool",
|
|
310
|
-
tool_call_id: part.id,
|
|
310
|
+
tool_call_id: options.toolCallID?.(part.id) ?? part.id,
|
|
311
311
|
content: ProviderShared.toolResultText(part),
|
|
312
312
|
cache_control: options.cacheControl?.(part.cache),
|
|
313
313
|
});
|
|
@@ -317,7 +317,7 @@ const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (m
|
|
|
317
317
|
const text = content.filter((item) => item.type === "text").map((item) => item.text);
|
|
318
318
|
messages.push({
|
|
319
319
|
role: "tool",
|
|
320
|
-
tool_call_id: part.id,
|
|
320
|
+
tool_call_id: options.toolCallID?.(part.id) ?? part.id,
|
|
321
321
|
content: text.join("\n"),
|
|
322
322
|
cache_control: options.cacheControl?.(part.cache),
|
|
323
323
|
});
|
|
@@ -326,11 +326,11 @@ const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (m
|
|
|
326
326
|
}
|
|
327
327
|
return { messages, images };
|
|
328
328
|
});
|
|
329
|
-
const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (message, reasoningField, options
|
|
329
|
+
const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (message, reasoningField, requireReasoning, options) {
|
|
330
330
|
if (message.role === "user")
|
|
331
331
|
return [yield* lowerUserMessage(message, options)];
|
|
332
332
|
if (message.role === "assistant")
|
|
333
|
-
return [yield* lowerAssistantMessage(message, reasoningField, options)];
|
|
333
|
+
return [yield* lowerAssistantMessage(message, reasoningField, requireReasoning, options)];
|
|
334
334
|
return (yield* lowerToolMessages(message, options)).messages;
|
|
335
335
|
});
|
|
336
336
|
const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request, options) {
|
|
@@ -349,8 +349,27 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request,
|
|
|
349
349
|
]
|
|
350
350
|
: [{ role: "system", content: ProviderShared.joinText(request.system) }];
|
|
351
351
|
const messages = [...system];
|
|
352
|
-
const
|
|
353
|
-
|
|
352
|
+
const modelID = request.model.id.toLowerCase();
|
|
353
|
+
const requireReasoning = request.model.compatibility?.requireReasoning ??
|
|
354
|
+
(request.model.compatibility?.reasoningField !== undefined ||
|
|
355
|
+
request.model.provider === "deepseek" ||
|
|
356
|
+
request.model.route.endpoint.baseURL?.toLowerCase().includes("deepseek.com") ||
|
|
357
|
+
modelID.includes("deepseek"));
|
|
358
|
+
const reasoningField = request.model.compatibility?.reasoningField;
|
|
359
|
+
const mistral = ["mistral", "devstral", "codestral", "pixtral", "mixtral"].some((family) => modelID.includes(family));
|
|
360
|
+
const lowering = {
|
|
361
|
+
...options,
|
|
362
|
+
toolCallID: (id) => {
|
|
363
|
+
if (mistral)
|
|
364
|
+
return id.replace(/[^a-zA-Z0-9]/g, "").slice(0, 9).padEnd(9, "0");
|
|
365
|
+
if (modelID.includes("claude"))
|
|
366
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
367
|
+
if (request.model.provider === "openai" || request.model.provider === "azure" || modelID.startsWith("openai/"))
|
|
368
|
+
return id.slice(0, 40);
|
|
369
|
+
return id;
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
const requireAssistantAfterTool = request.model.compatibility?.requireAssistantAfterTool ?? mistral;
|
|
354
373
|
const bridgeTools = () => {
|
|
355
374
|
if (requireAssistantAfterTool && messages.at(-1)?.role === "tool")
|
|
356
375
|
messages.push({ role: "assistant", content: "Done." });
|
|
@@ -408,13 +427,13 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request,
|
|
|
408
427
|
if (message.role === "assistant" && message.content.every((part) => part.type === "text" && part.text.trim() === ""))
|
|
409
428
|
continue;
|
|
410
429
|
if (message.role === "tool") {
|
|
411
|
-
const lowered = yield* lowerToolMessages(message,
|
|
430
|
+
const lowered = yield* lowerToolMessages(message, lowering);
|
|
412
431
|
messages.push(...lowered.messages);
|
|
413
432
|
pendingImages.push(...lowered.images);
|
|
414
433
|
continue;
|
|
415
434
|
}
|
|
416
435
|
flushImages();
|
|
417
|
-
messages.push(...(yield* lowerMessage(message,
|
|
436
|
+
messages.push(...(yield* lowerMessage(message, reasoningField, requireReasoning, lowering)));
|
|
418
437
|
}
|
|
419
438
|
flushImages();
|
|
420
439
|
return messages;
|
|
@@ -7,6 +7,43 @@ export type OpenAICompatibleResponsesLanguageModelInput = RouteRoutedLanguageMod
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const route: Route<{
|
|
9
9
|
readonly input: readonly ({
|
|
10
|
+
readonly [x: string]: unknown;
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly type: "web_search_call";
|
|
13
|
+
readonly status?: string | undefined;
|
|
14
|
+
readonly action?: {
|
|
15
|
+
readonly [x: string]: unknown;
|
|
16
|
+
} | null | undefined;
|
|
17
|
+
} | {
|
|
18
|
+
readonly [x: string]: unknown;
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly type: "file_search_call";
|
|
21
|
+
readonly status?: string | undefined;
|
|
22
|
+
readonly queries?: readonly string[] | undefined;
|
|
23
|
+
readonly results?: readonly {
|
|
24
|
+
readonly [x: string]: unknown;
|
|
25
|
+
}[] | null | undefined;
|
|
26
|
+
} | {
|
|
27
|
+
readonly [x: string]: unknown;
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly type: "code_interpreter_call";
|
|
30
|
+
readonly status?: string | undefined;
|
|
31
|
+
readonly code?: string | null | undefined;
|
|
32
|
+
readonly container_id?: string | null | undefined;
|
|
33
|
+
readonly outputs?: readonly {
|
|
34
|
+
readonly [x: string]: unknown;
|
|
35
|
+
}[] | null | undefined;
|
|
36
|
+
} | {
|
|
37
|
+
readonly [x: string]: unknown;
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly type: "mcp_call";
|
|
40
|
+
readonly status?: string | undefined;
|
|
41
|
+
readonly name?: string | undefined;
|
|
42
|
+
readonly output?: string | null | undefined;
|
|
43
|
+
readonly error?: unknown;
|
|
44
|
+
readonly arguments?: string | undefined;
|
|
45
|
+
readonly server_label?: string | undefined;
|
|
46
|
+
} | {
|
|
10
47
|
readonly type: "reasoning";
|
|
11
48
|
readonly summary: readonly {
|
|
12
49
|
readonly type: "summary_text";
|
|
@@ -14,9 +51,6 @@ export declare const route: Route<{
|
|
|
14
51
|
}[];
|
|
15
52
|
readonly id?: string | undefined;
|
|
16
53
|
readonly encrypted_content?: string | null | undefined;
|
|
17
|
-
} | {
|
|
18
|
-
readonly type: "item_reference";
|
|
19
|
-
readonly id: string;
|
|
20
54
|
} | {
|
|
21
55
|
readonly role: "system";
|
|
22
56
|
readonly content: string;
|