@yourgpt/llm-sdk 2.6.0-beta.2 → 2.6.0
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/LICENSE +21 -0
- package/README.md +87 -17
- package/dist/adapters/index.d.mts +11 -13
- package/dist/adapters/index.d.ts +11 -13
- package/dist/adapters/index.js +406 -114
- package/dist/adapters/index.mjs +406 -114
- package/dist/audio-K-Z3-Bce.d.mts +191 -0
- package/dist/audio-K-Z3-Bce.d.ts +191 -0
- package/dist/{base-BICaQaRS.d.mts → base-6LzczuCg.d.ts} +8 -1
- package/dist/{base-CpRPB8u8.d.ts → base-DySbTP8C.d.mts} +8 -1
- package/dist/decisions-CJzOt87t.d.mts +137 -0
- package/dist/decisions-CJzOt87t.d.ts +137 -0
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/http-BQxUT5A9.d.mts +9 -0
- package/dist/http-BQxUT5A9.d.ts +9 -0
- package/dist/index.d.mts +17 -9
- package/dist/index.d.ts +17 -9
- package/dist/index.js +698 -205
- package/dist/index.mjs +695 -206
- package/dist/providers/anthropic/index.d.mts +7 -4
- package/dist/providers/anthropic/index.d.ts +7 -4
- package/dist/providers/anthropic/index.js +389 -115
- package/dist/providers/anthropic/index.mjs +389 -115
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/cloudflare/index.d.mts +11 -0
- package/dist/providers/cloudflare/index.d.ts +11 -0
- package/dist/providers/cloudflare/index.js +743 -0
- package/dist/providers/cloudflare/index.mjs +741 -0
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +181 -60
- package/dist/providers/fireworks/index.mjs +181 -60
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +181 -60
- package/dist/providers/google/index.mjs +181 -60
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/openai/index.d.mts +38 -6
- package/dist/providers/openai/index.d.ts +38 -6
- package/dist/providers/openai/index.js +1451 -85
- package/dist/providers/openai/index.mjs +1449 -86
- package/dist/providers/openrouter/index.d.mts +21 -4
- package/dist/providers/openrouter/index.d.ts +21 -4
- package/dist/providers/openrouter/index.js +1040 -131
- package/dist/providers/openrouter/index.mjs +1040 -132
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +181 -60
- package/dist/providers/togetherai/index.mjs +181 -60
- package/dist/providers/typesafe/index.d.mts +8 -0
- package/dist/providers/typesafe/index.d.ts +8 -0
- package/dist/providers/typesafe/index.js +735 -0
- package/dist/providers/typesafe/index.mjs +733 -0
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +181 -60
- package/dist/providers/xai/index.mjs +181 -60
- package/dist/{types-DCFqkJAy.d.ts → types-B0y6VZSQ.d.ts} +1 -1
- package/dist/{types-DHQEMFHA.d.mts → types-BXQMtaCX.d.ts} +17 -3
- package/dist/{types-C3RgRbEC.d.mts → types-BY6BVhFg.d.mts} +1 -1
- package/dist/{types-Dikj3En4.d.ts → types-C7_qVSSd.d.mts} +17 -3
- package/dist/{types-Dg1Bcg1k.d.mts → types-D7lzMMLu.d.mts} +13 -1
- package/dist/{types-Dg1Bcg1k.d.ts → types-D7lzMMLu.d.ts} +13 -1
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/docs/decisions.md +174 -0
- package/docs/media.md +201 -0
- package/docs/multimodal-and-audio.md +9 -2
- package/package.json +34 -12
- package/dist/audio-BBSwnjo8.d.mts +0 -92
- package/dist/audio-BBSwnjo8.d.ts +0 -92
|
@@ -113,6 +113,19 @@ function capabilities(model) {
|
|
|
113
113
|
const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
|
|
114
114
|
return { major, minor, reasoning, supportsNone };
|
|
115
115
|
}
|
|
116
|
+
function filterOpenAIResponseInclude(model, include, options = {}) {
|
|
117
|
+
const c = capabilities(model);
|
|
118
|
+
let result = include;
|
|
119
|
+
if (options.parameterPolicy !== "passthrough" && c.reasoning && !(options.reasoningEffort === "none" && c.supportsNone) && include.includes("message.output_text.logprobs")) {
|
|
120
|
+
result = include.filter(
|
|
121
|
+
(value) => value !== "message.output_text.logprobs"
|
|
122
|
+
);
|
|
123
|
+
(options.onWarning ?? console.warn)(
|
|
124
|
+
`[llm-sdk] ${model}: omitted message.output_text.logprobs because reasoning is enabled.`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return result.length ? result : void 0;
|
|
128
|
+
}
|
|
116
129
|
function requiresOpenAIResponses(model, baseUrl, options = {}) {
|
|
117
130
|
if (options.parameterPolicy === "passthrough") return false;
|
|
118
131
|
const c = capabilities(model);
|
|
@@ -274,6 +287,7 @@ function toOpenAIResponseFormat(rf) {
|
|
|
274
287
|
};
|
|
275
288
|
}
|
|
276
289
|
function toOpenAIResponsesTextFormat(rf) {
|
|
290
|
+
if (rf?.type === "json_object") return { type: "json_object" };
|
|
277
291
|
if (!rf || rf.type !== "json_schema") return void 0;
|
|
278
292
|
return {
|
|
279
293
|
type: "json_schema",
|
|
@@ -668,6 +682,63 @@ function formatMessagesForGoogle(messages) {
|
|
|
668
682
|
});
|
|
669
683
|
}
|
|
670
684
|
|
|
685
|
+
// src/core/provider-error.ts
|
|
686
|
+
function invalidProviderResponse(message) {
|
|
687
|
+
return Object.assign(new Error(message), {
|
|
688
|
+
name: "InvalidProviderResponseError",
|
|
689
|
+
status: 502,
|
|
690
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
function providerErrorEvent(error, code) {
|
|
694
|
+
const details = error ?? {};
|
|
695
|
+
const event = {
|
|
696
|
+
type: "error",
|
|
697
|
+
message: error instanceof Error ? error.message : String(error),
|
|
698
|
+
code,
|
|
699
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
700
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
701
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
702
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
703
|
+
};
|
|
704
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
705
|
+
return event;
|
|
706
|
+
}
|
|
707
|
+
function throwIfAborted(signal) {
|
|
708
|
+
if (!signal?.aborted) return;
|
|
709
|
+
const error = new Error("The operation was aborted");
|
|
710
|
+
error.name = "AbortError";
|
|
711
|
+
throw error;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// src/core/tool-validation.ts
|
|
715
|
+
function parseToolArguments(value) {
|
|
716
|
+
let args = value;
|
|
717
|
+
if (typeof value === "string") {
|
|
718
|
+
try {
|
|
719
|
+
args = JSON.parse(value || "{}");
|
|
720
|
+
} catch {
|
|
721
|
+
throw invalidProviderResponse("Tool arguments are not valid JSON");
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
725
|
+
throw invalidProviderResponse("Tool arguments must be a JSON object");
|
|
726
|
+
return args;
|
|
727
|
+
}
|
|
728
|
+
function validateToolCalls(calls) {
|
|
729
|
+
const ids = /* @__PURE__ */ new Set();
|
|
730
|
+
for (const call of calls) {
|
|
731
|
+
if (!call || typeof call.id !== "string" || !call.id || typeof call.name !== "string" || !call.name || ids.has(call.id))
|
|
732
|
+
throw invalidProviderResponse(
|
|
733
|
+
"Tool calls have missing or duplicate identities"
|
|
734
|
+
);
|
|
735
|
+
ids.add(call.id);
|
|
736
|
+
if (typeof call.args === "string")
|
|
737
|
+
throw invalidProviderResponse("Parsed tool arguments must be an object");
|
|
738
|
+
parseToolArguments(call.args);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
671
742
|
// src/core/openai-responses.ts
|
|
672
743
|
function resolveOpenAITransport(defaults, overrides) {
|
|
673
744
|
return {
|
|
@@ -715,6 +786,54 @@ function responseMetadata(response) {
|
|
|
715
786
|
}
|
|
716
787
|
};
|
|
717
788
|
}
|
|
789
|
+
function responseReplayMetadata(metadata) {
|
|
790
|
+
const response = metadata?.openai?.response;
|
|
791
|
+
if (!response) return metadata;
|
|
792
|
+
const output = response.output.map((item) => {
|
|
793
|
+
const fields = ["type", "id", "status"];
|
|
794
|
+
switch (item.type) {
|
|
795
|
+
case "reasoning":
|
|
796
|
+
fields.push("encrypted_content");
|
|
797
|
+
break;
|
|
798
|
+
case "message":
|
|
799
|
+
fields.push("role", "phase");
|
|
800
|
+
break;
|
|
801
|
+
case "function_call":
|
|
802
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
803
|
+
break;
|
|
804
|
+
case "tool_search_call":
|
|
805
|
+
fields.push("call_id", "execution", "arguments");
|
|
806
|
+
break;
|
|
807
|
+
case "tool_search_output":
|
|
808
|
+
fields.push("call_id", "tools");
|
|
809
|
+
break;
|
|
810
|
+
case "web_search_call":
|
|
811
|
+
fields.push("action");
|
|
812
|
+
break;
|
|
813
|
+
default:
|
|
814
|
+
return stripItemDiagnostics(item);
|
|
815
|
+
}
|
|
816
|
+
const replay = Object.fromEntries(
|
|
817
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
818
|
+
);
|
|
819
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
820
|
+
if (item.type === "message")
|
|
821
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
822
|
+
(part) => part?.type === "output_text" && typeof part.text === "string" ? [{ type: "output_text", text: part.text, annotations: [] }] : part?.type === "refusal" && typeof part.refusal === "string" ? [{ type: "refusal", refusal: part.refusal }] : []
|
|
823
|
+
) : [];
|
|
824
|
+
return stripItemDiagnostics(replay);
|
|
825
|
+
});
|
|
826
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
827
|
+
}
|
|
828
|
+
function stripItemDiagnostics(item) {
|
|
829
|
+
const {
|
|
830
|
+
usage: _usage,
|
|
831
|
+
logprobs: _logprobs,
|
|
832
|
+
metadata: _metadata,
|
|
833
|
+
...state
|
|
834
|
+
} = item;
|
|
835
|
+
return state;
|
|
836
|
+
}
|
|
718
837
|
function getResponseReplay(metadata) {
|
|
719
838
|
const response = metadata?.openai?.response;
|
|
720
839
|
if (response === void 0) return void 0;
|
|
@@ -723,29 +842,7 @@ function getResponseReplay(metadata) {
|
|
|
723
842
|
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
724
843
|
);
|
|
725
844
|
}
|
|
726
|
-
return response
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
// src/core/provider-error.ts
|
|
730
|
-
function providerErrorEvent(error, code) {
|
|
731
|
-
const details = error ?? {};
|
|
732
|
-
const event = {
|
|
733
|
-
type: "error",
|
|
734
|
-
message: error instanceof Error ? error.message : String(error),
|
|
735
|
-
code,
|
|
736
|
-
...typeof details.status === "number" ? { status: details.status } : {},
|
|
737
|
-
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
738
|
-
...typeof details.param === "string" ? { param: details.param } : {},
|
|
739
|
-
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
740
|
-
};
|
|
741
|
-
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
742
|
-
return event;
|
|
743
|
-
}
|
|
744
|
-
function throwIfAborted(signal) {
|
|
745
|
-
if (!signal?.aborted) return;
|
|
746
|
-
const error = new Error("The operation was aborted");
|
|
747
|
-
error.name = "AbortError";
|
|
748
|
-
throw error;
|
|
845
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
749
846
|
}
|
|
750
847
|
|
|
751
848
|
// src/core/utils.ts
|
|
@@ -755,9 +852,6 @@ function generateId(prefix = "id") {
|
|
|
755
852
|
function generateMessageId() {
|
|
756
853
|
return generateId("msg");
|
|
757
854
|
}
|
|
758
|
-
function generateToolCallId() {
|
|
759
|
-
return generateId("call");
|
|
760
|
-
}
|
|
761
855
|
|
|
762
856
|
// src/adapters/openai.ts
|
|
763
857
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
@@ -781,6 +875,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
781
875
|
apiKey: this.config.apiKey,
|
|
782
876
|
baseURL: this.config.baseUrl,
|
|
783
877
|
organization: this.config.organization,
|
|
878
|
+
project: this.config.project,
|
|
879
|
+
timeout: this.config.timeout,
|
|
784
880
|
defaultHeaders: this.config.headers
|
|
785
881
|
});
|
|
786
882
|
}
|
|
@@ -903,7 +999,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
903
999
|
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
904
1000
|
return messages.map((message) => {
|
|
905
1001
|
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
906
|
-
let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput,
|
|
1002
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
907
1003
|
if (preserveProviderMetadata && modelOutput)
|
|
908
1004
|
rest.modelOutput = modelOutput;
|
|
909
1005
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
@@ -1006,17 +1102,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1006
1102
|
const seenCallIds = /* @__PURE__ */ new Set();
|
|
1007
1103
|
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
1008
1104
|
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
1009
|
-
throw
|
|
1105
|
+
throw invalidProviderResponse(
|
|
1106
|
+
"Responses contains an incomplete function call"
|
|
1107
|
+
);
|
|
1010
1108
|
}
|
|
1011
1109
|
if (seenCallIds.has(item.call_id))
|
|
1012
|
-
throw
|
|
1110
|
+
throw invalidProviderResponse(
|
|
1111
|
+
"Responses contains duplicate function call IDs"
|
|
1112
|
+
);
|
|
1013
1113
|
seenCallIds.add(item.call_id);
|
|
1014
|
-
|
|
1114
|
+
let args;
|
|
1115
|
+
try {
|
|
1116
|
+
args = JSON.parse(item.arguments);
|
|
1117
|
+
} catch {
|
|
1118
|
+
throw invalidProviderResponse(
|
|
1119
|
+
"Responses function arguments must be valid JSON"
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1015
1122
|
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1016
|
-
throw
|
|
1123
|
+
throw invalidProviderResponse(
|
|
1017
1124
|
"Responses function arguments must be a JSON object"
|
|
1018
1125
|
);
|
|
1019
|
-
return {
|
|
1126
|
+
return {
|
|
1127
|
+
id: item.call_id,
|
|
1128
|
+
name: item.name,
|
|
1129
|
+
args
|
|
1130
|
+
};
|
|
1020
1131
|
}) : [];
|
|
1021
1132
|
return {
|
|
1022
1133
|
content,
|
|
@@ -1047,6 +1158,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1047
1158
|
request.config?.responseFormat
|
|
1048
1159
|
);
|
|
1049
1160
|
const modelIdForPayload = request.config?.model || this.model;
|
|
1161
|
+
const include = filterOpenAIResponseInclude(
|
|
1162
|
+
modelIdForPayload,
|
|
1163
|
+
[
|
|
1164
|
+
.../* @__PURE__ */ new Set([
|
|
1165
|
+
...options?.include ?? [],
|
|
1166
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1167
|
+
])
|
|
1168
|
+
],
|
|
1169
|
+
this.parameterOptions(request)
|
|
1170
|
+
);
|
|
1050
1171
|
const payload = {
|
|
1051
1172
|
model: modelIdForPayload,
|
|
1052
1173
|
instructions: request.systemPrompt,
|
|
@@ -1070,14 +1191,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1070
1191
|
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1071
1192
|
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1072
1193
|
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1073
|
-
...
|
|
1074
|
-
include: [
|
|
1075
|
-
.../* @__PURE__ */ new Set([
|
|
1076
|
-
...options?.include ?? [],
|
|
1077
|
-
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1078
|
-
])
|
|
1079
|
-
]
|
|
1080
|
-
} : {},
|
|
1194
|
+
...include ? { include } : {},
|
|
1081
1195
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
1082
1196
|
stream
|
|
1083
1197
|
};
|
|
@@ -1259,7 +1373,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1259
1373
|
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1260
1374
|
for (const call of toolCalls.values()) {
|
|
1261
1375
|
if (!call.id || !call.name)
|
|
1262
|
-
throw
|
|
1376
|
+
throw invalidProviderResponse(
|
|
1377
|
+
"Responses stream contains an incomplete tool call"
|
|
1378
|
+
);
|
|
1263
1379
|
uniqueCalls.set(call.id, call);
|
|
1264
1380
|
}
|
|
1265
1381
|
toolCalls.clear();
|
|
@@ -1446,15 +1562,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1446
1562
|
}
|
|
1447
1563
|
throwIfAborted(request.signal);
|
|
1448
1564
|
if (!finishReason)
|
|
1449
|
-
throw
|
|
1565
|
+
throw invalidProviderResponse(
|
|
1566
|
+
"OpenAI stream ended without a finish reason"
|
|
1567
|
+
);
|
|
1450
1568
|
if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
|
|
1451
|
-
throw
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
if (!call.id || !call.name)
|
|
1455
|
-
throw new Error("OpenAI stream contains an incomplete tool call");
|
|
1456
|
-
JSON.parse(call.arguments || "{}");
|
|
1569
|
+
throw invalidProviderResponse(
|
|
1570
|
+
"OpenAI stream ended with incomplete tool calls"
|
|
1571
|
+
);
|
|
1457
1572
|
}
|
|
1573
|
+
validateToolCalls(
|
|
1574
|
+
[...toolCalls.values()].map((call) => ({
|
|
1575
|
+
...call,
|
|
1576
|
+
args: parseToolArguments(call.arguments)
|
|
1577
|
+
}))
|
|
1578
|
+
);
|
|
1458
1579
|
for (const call of toolCalls.values()) {
|
|
1459
1580
|
yield {
|
|
1460
1581
|
type: "action:start",
|
|
@@ -1538,20 +1659,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1538
1659
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
1539
1660
|
const choice = response.choices?.[0];
|
|
1540
1661
|
const message = choice?.message;
|
|
1662
|
+
const toolCalls = (message?.tool_calls ?? []).map((toolCall) => ({
|
|
1663
|
+
id: toolCall.id,
|
|
1664
|
+
name: toolCall.function?.name,
|
|
1665
|
+
args: parseToolArguments(toolCall.function?.arguments ?? "{}"),
|
|
1666
|
+
...toolCall.extra_content ? { extra_content: toolCall.extra_content } : {}
|
|
1667
|
+
}));
|
|
1668
|
+
validateToolCalls(toolCalls);
|
|
1669
|
+
if (toolCalls.length && choice?.finish_reason && !["tool_calls", "function_call"].includes(choice.finish_reason))
|
|
1670
|
+
throw invalidProviderResponse(
|
|
1671
|
+
"OpenAI response ended with incomplete tool calls"
|
|
1672
|
+
);
|
|
1541
1673
|
return {
|
|
1542
1674
|
content: message?.content ?? "",
|
|
1543
|
-
toolCalls
|
|
1544
|
-
id: toolCall.id ?? generateToolCallId(),
|
|
1545
|
-
name: toolCall.function?.name ?? "",
|
|
1546
|
-
args: (() => {
|
|
1547
|
-
try {
|
|
1548
|
-
return JSON.parse(toolCall.function?.arguments ?? "{}");
|
|
1549
|
-
} catch {
|
|
1550
|
-
return {};
|
|
1551
|
-
}
|
|
1552
|
-
})(),
|
|
1553
|
-
...toolCall.extra_content ? { extra_content: toolCall.extra_content } : {}
|
|
1554
|
-
})) ?? [],
|
|
1675
|
+
toolCalls,
|
|
1555
1676
|
usage: response.usage ? {
|
|
1556
1677
|
promptTokens: response.usage.prompt_tokens,
|
|
1557
1678
|
completionTokens: response.usage.completion_tokens,
|
|
@@ -111,6 +111,19 @@ function capabilities(model) {
|
|
|
111
111
|
const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
|
|
112
112
|
return { major, minor, reasoning, supportsNone };
|
|
113
113
|
}
|
|
114
|
+
function filterOpenAIResponseInclude(model, include, options = {}) {
|
|
115
|
+
const c = capabilities(model);
|
|
116
|
+
let result = include;
|
|
117
|
+
if (options.parameterPolicy !== "passthrough" && c.reasoning && !(options.reasoningEffort === "none" && c.supportsNone) && include.includes("message.output_text.logprobs")) {
|
|
118
|
+
result = include.filter(
|
|
119
|
+
(value) => value !== "message.output_text.logprobs"
|
|
120
|
+
);
|
|
121
|
+
(options.onWarning ?? console.warn)(
|
|
122
|
+
`[llm-sdk] ${model}: omitted message.output_text.logprobs because reasoning is enabled.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return result.length ? result : void 0;
|
|
126
|
+
}
|
|
114
127
|
function requiresOpenAIResponses(model, baseUrl, options = {}) {
|
|
115
128
|
if (options.parameterPolicy === "passthrough") return false;
|
|
116
129
|
const c = capabilities(model);
|
|
@@ -272,6 +285,7 @@ function toOpenAIResponseFormat(rf) {
|
|
|
272
285
|
};
|
|
273
286
|
}
|
|
274
287
|
function toOpenAIResponsesTextFormat(rf) {
|
|
288
|
+
if (rf?.type === "json_object") return { type: "json_object" };
|
|
275
289
|
if (!rf || rf.type !== "json_schema") return void 0;
|
|
276
290
|
return {
|
|
277
291
|
type: "json_schema",
|
|
@@ -666,6 +680,63 @@ function formatMessagesForGoogle(messages) {
|
|
|
666
680
|
});
|
|
667
681
|
}
|
|
668
682
|
|
|
683
|
+
// src/core/provider-error.ts
|
|
684
|
+
function invalidProviderResponse(message) {
|
|
685
|
+
return Object.assign(new Error(message), {
|
|
686
|
+
name: "InvalidProviderResponseError",
|
|
687
|
+
status: 502,
|
|
688
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
function providerErrorEvent(error, code) {
|
|
692
|
+
const details = error ?? {};
|
|
693
|
+
const event = {
|
|
694
|
+
type: "error",
|
|
695
|
+
message: error instanceof Error ? error.message : String(error),
|
|
696
|
+
code,
|
|
697
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
698
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
699
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
700
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
701
|
+
};
|
|
702
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
703
|
+
return event;
|
|
704
|
+
}
|
|
705
|
+
function throwIfAborted(signal) {
|
|
706
|
+
if (!signal?.aborted) return;
|
|
707
|
+
const error = new Error("The operation was aborted");
|
|
708
|
+
error.name = "AbortError";
|
|
709
|
+
throw error;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// src/core/tool-validation.ts
|
|
713
|
+
function parseToolArguments(value) {
|
|
714
|
+
let args = value;
|
|
715
|
+
if (typeof value === "string") {
|
|
716
|
+
try {
|
|
717
|
+
args = JSON.parse(value || "{}");
|
|
718
|
+
} catch {
|
|
719
|
+
throw invalidProviderResponse("Tool arguments are not valid JSON");
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (args === null || typeof args !== "object" || Array.isArray(args))
|
|
723
|
+
throw invalidProviderResponse("Tool arguments must be a JSON object");
|
|
724
|
+
return args;
|
|
725
|
+
}
|
|
726
|
+
function validateToolCalls(calls) {
|
|
727
|
+
const ids = /* @__PURE__ */ new Set();
|
|
728
|
+
for (const call of calls) {
|
|
729
|
+
if (!call || typeof call.id !== "string" || !call.id || typeof call.name !== "string" || !call.name || ids.has(call.id))
|
|
730
|
+
throw invalidProviderResponse(
|
|
731
|
+
"Tool calls have missing or duplicate identities"
|
|
732
|
+
);
|
|
733
|
+
ids.add(call.id);
|
|
734
|
+
if (typeof call.args === "string")
|
|
735
|
+
throw invalidProviderResponse("Parsed tool arguments must be an object");
|
|
736
|
+
parseToolArguments(call.args);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
669
740
|
// src/core/openai-responses.ts
|
|
670
741
|
function resolveOpenAITransport(defaults, overrides) {
|
|
671
742
|
return {
|
|
@@ -713,6 +784,54 @@ function responseMetadata(response) {
|
|
|
713
784
|
}
|
|
714
785
|
};
|
|
715
786
|
}
|
|
787
|
+
function responseReplayMetadata(metadata) {
|
|
788
|
+
const response = metadata?.openai?.response;
|
|
789
|
+
if (!response) return metadata;
|
|
790
|
+
const output = response.output.map((item) => {
|
|
791
|
+
const fields = ["type", "id", "status"];
|
|
792
|
+
switch (item.type) {
|
|
793
|
+
case "reasoning":
|
|
794
|
+
fields.push("encrypted_content");
|
|
795
|
+
break;
|
|
796
|
+
case "message":
|
|
797
|
+
fields.push("role", "phase");
|
|
798
|
+
break;
|
|
799
|
+
case "function_call":
|
|
800
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
801
|
+
break;
|
|
802
|
+
case "tool_search_call":
|
|
803
|
+
fields.push("call_id", "execution", "arguments");
|
|
804
|
+
break;
|
|
805
|
+
case "tool_search_output":
|
|
806
|
+
fields.push("call_id", "tools");
|
|
807
|
+
break;
|
|
808
|
+
case "web_search_call":
|
|
809
|
+
fields.push("action");
|
|
810
|
+
break;
|
|
811
|
+
default:
|
|
812
|
+
return stripItemDiagnostics(item);
|
|
813
|
+
}
|
|
814
|
+
const replay = Object.fromEntries(
|
|
815
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
816
|
+
);
|
|
817
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
818
|
+
if (item.type === "message")
|
|
819
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
820
|
+
(part) => part?.type === "output_text" && typeof part.text === "string" ? [{ type: "output_text", text: part.text, annotations: [] }] : part?.type === "refusal" && typeof part.refusal === "string" ? [{ type: "refusal", refusal: part.refusal }] : []
|
|
821
|
+
) : [];
|
|
822
|
+
return stripItemDiagnostics(replay);
|
|
823
|
+
});
|
|
824
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
825
|
+
}
|
|
826
|
+
function stripItemDiagnostics(item) {
|
|
827
|
+
const {
|
|
828
|
+
usage: _usage,
|
|
829
|
+
logprobs: _logprobs,
|
|
830
|
+
metadata: _metadata,
|
|
831
|
+
...state
|
|
832
|
+
} = item;
|
|
833
|
+
return state;
|
|
834
|
+
}
|
|
716
835
|
function getResponseReplay(metadata) {
|
|
717
836
|
const response = metadata?.openai?.response;
|
|
718
837
|
if (response === void 0) return void 0;
|
|
@@ -721,29 +840,7 @@ function getResponseReplay(metadata) {
|
|
|
721
840
|
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
722
841
|
);
|
|
723
842
|
}
|
|
724
|
-
return response
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
// src/core/provider-error.ts
|
|
728
|
-
function providerErrorEvent(error, code) {
|
|
729
|
-
const details = error ?? {};
|
|
730
|
-
const event = {
|
|
731
|
-
type: "error",
|
|
732
|
-
message: error instanceof Error ? error.message : String(error),
|
|
733
|
-
code,
|
|
734
|
-
...typeof details.status === "number" ? { status: details.status } : {},
|
|
735
|
-
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
736
|
-
...typeof details.param === "string" ? { param: details.param } : {},
|
|
737
|
-
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
738
|
-
};
|
|
739
|
-
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
740
|
-
return event;
|
|
741
|
-
}
|
|
742
|
-
function throwIfAborted(signal) {
|
|
743
|
-
if (!signal?.aborted) return;
|
|
744
|
-
const error = new Error("The operation was aborted");
|
|
745
|
-
error.name = "AbortError";
|
|
746
|
-
throw error;
|
|
843
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
747
844
|
}
|
|
748
845
|
|
|
749
846
|
// src/core/utils.ts
|
|
@@ -753,9 +850,6 @@ function generateId(prefix = "id") {
|
|
|
753
850
|
function generateMessageId() {
|
|
754
851
|
return generateId("msg");
|
|
755
852
|
}
|
|
756
|
-
function generateToolCallId() {
|
|
757
|
-
return generateId("call");
|
|
758
|
-
}
|
|
759
853
|
|
|
760
854
|
// src/adapters/openai.ts
|
|
761
855
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
@@ -779,6 +873,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
779
873
|
apiKey: this.config.apiKey,
|
|
780
874
|
baseURL: this.config.baseUrl,
|
|
781
875
|
organization: this.config.organization,
|
|
876
|
+
project: this.config.project,
|
|
877
|
+
timeout: this.config.timeout,
|
|
782
878
|
defaultHeaders: this.config.headers
|
|
783
879
|
});
|
|
784
880
|
}
|
|
@@ -901,7 +997,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
901
997
|
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
902
998
|
return messages.map((message) => {
|
|
903
999
|
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
904
|
-
let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput,
|
|
1000
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
905
1001
|
if (preserveProviderMetadata && modelOutput)
|
|
906
1002
|
rest.modelOutput = modelOutput;
|
|
907
1003
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
@@ -1004,17 +1100,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1004
1100
|
const seenCallIds = /* @__PURE__ */ new Set();
|
|
1005
1101
|
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
1006
1102
|
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
1007
|
-
throw
|
|
1103
|
+
throw invalidProviderResponse(
|
|
1104
|
+
"Responses contains an incomplete function call"
|
|
1105
|
+
);
|
|
1008
1106
|
}
|
|
1009
1107
|
if (seenCallIds.has(item.call_id))
|
|
1010
|
-
throw
|
|
1108
|
+
throw invalidProviderResponse(
|
|
1109
|
+
"Responses contains duplicate function call IDs"
|
|
1110
|
+
);
|
|
1011
1111
|
seenCallIds.add(item.call_id);
|
|
1012
|
-
|
|
1112
|
+
let args;
|
|
1113
|
+
try {
|
|
1114
|
+
args = JSON.parse(item.arguments);
|
|
1115
|
+
} catch {
|
|
1116
|
+
throw invalidProviderResponse(
|
|
1117
|
+
"Responses function arguments must be valid JSON"
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1013
1120
|
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1014
|
-
throw
|
|
1121
|
+
throw invalidProviderResponse(
|
|
1015
1122
|
"Responses function arguments must be a JSON object"
|
|
1016
1123
|
);
|
|
1017
|
-
return {
|
|
1124
|
+
return {
|
|
1125
|
+
id: item.call_id,
|
|
1126
|
+
name: item.name,
|
|
1127
|
+
args
|
|
1128
|
+
};
|
|
1018
1129
|
}) : [];
|
|
1019
1130
|
return {
|
|
1020
1131
|
content,
|
|
@@ -1045,6 +1156,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1045
1156
|
request.config?.responseFormat
|
|
1046
1157
|
);
|
|
1047
1158
|
const modelIdForPayload = request.config?.model || this.model;
|
|
1159
|
+
const include = filterOpenAIResponseInclude(
|
|
1160
|
+
modelIdForPayload,
|
|
1161
|
+
[
|
|
1162
|
+
.../* @__PURE__ */ new Set([
|
|
1163
|
+
...options?.include ?? [],
|
|
1164
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1165
|
+
])
|
|
1166
|
+
],
|
|
1167
|
+
this.parameterOptions(request)
|
|
1168
|
+
);
|
|
1048
1169
|
const payload = {
|
|
1049
1170
|
model: modelIdForPayload,
|
|
1050
1171
|
instructions: request.systemPrompt,
|
|
@@ -1068,14 +1189,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1068
1189
|
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1069
1190
|
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1070
1191
|
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1071
|
-
...
|
|
1072
|
-
include: [
|
|
1073
|
-
.../* @__PURE__ */ new Set([
|
|
1074
|
-
...options?.include ?? [],
|
|
1075
|
-
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1076
|
-
])
|
|
1077
|
-
]
|
|
1078
|
-
} : {},
|
|
1192
|
+
...include ? { include } : {},
|
|
1079
1193
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
1080
1194
|
stream
|
|
1081
1195
|
};
|
|
@@ -1257,7 +1371,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1257
1371
|
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1258
1372
|
for (const call of toolCalls.values()) {
|
|
1259
1373
|
if (!call.id || !call.name)
|
|
1260
|
-
throw
|
|
1374
|
+
throw invalidProviderResponse(
|
|
1375
|
+
"Responses stream contains an incomplete tool call"
|
|
1376
|
+
);
|
|
1261
1377
|
uniqueCalls.set(call.id, call);
|
|
1262
1378
|
}
|
|
1263
1379
|
toolCalls.clear();
|
|
@@ -1444,15 +1560,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1444
1560
|
}
|
|
1445
1561
|
throwIfAborted(request.signal);
|
|
1446
1562
|
if (!finishReason)
|
|
1447
|
-
throw
|
|
1563
|
+
throw invalidProviderResponse(
|
|
1564
|
+
"OpenAI stream ended without a finish reason"
|
|
1565
|
+
);
|
|
1448
1566
|
if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
|
|
1449
|
-
throw
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
if (!call.id || !call.name)
|
|
1453
|
-
throw new Error("OpenAI stream contains an incomplete tool call");
|
|
1454
|
-
JSON.parse(call.arguments || "{}");
|
|
1567
|
+
throw invalidProviderResponse(
|
|
1568
|
+
"OpenAI stream ended with incomplete tool calls"
|
|
1569
|
+
);
|
|
1455
1570
|
}
|
|
1571
|
+
validateToolCalls(
|
|
1572
|
+
[...toolCalls.values()].map((call) => ({
|
|
1573
|
+
...call,
|
|
1574
|
+
args: parseToolArguments(call.arguments)
|
|
1575
|
+
}))
|
|
1576
|
+
);
|
|
1456
1577
|
for (const call of toolCalls.values()) {
|
|
1457
1578
|
yield {
|
|
1458
1579
|
type: "action:start",
|
|
@@ -1536,20 +1657,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1536
1657
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
1537
1658
|
const choice = response.choices?.[0];
|
|
1538
1659
|
const message = choice?.message;
|
|
1660
|
+
const toolCalls = (message?.tool_calls ?? []).map((toolCall) => ({
|
|
1661
|
+
id: toolCall.id,
|
|
1662
|
+
name: toolCall.function?.name,
|
|
1663
|
+
args: parseToolArguments(toolCall.function?.arguments ?? "{}"),
|
|
1664
|
+
...toolCall.extra_content ? { extra_content: toolCall.extra_content } : {}
|
|
1665
|
+
}));
|
|
1666
|
+
validateToolCalls(toolCalls);
|
|
1667
|
+
if (toolCalls.length && choice?.finish_reason && !["tool_calls", "function_call"].includes(choice.finish_reason))
|
|
1668
|
+
throw invalidProviderResponse(
|
|
1669
|
+
"OpenAI response ended with incomplete tool calls"
|
|
1670
|
+
);
|
|
1539
1671
|
return {
|
|
1540
1672
|
content: message?.content ?? "",
|
|
1541
|
-
toolCalls
|
|
1542
|
-
id: toolCall.id ?? generateToolCallId(),
|
|
1543
|
-
name: toolCall.function?.name ?? "",
|
|
1544
|
-
args: (() => {
|
|
1545
|
-
try {
|
|
1546
|
-
return JSON.parse(toolCall.function?.arguments ?? "{}");
|
|
1547
|
-
} catch {
|
|
1548
|
-
return {};
|
|
1549
|
-
}
|
|
1550
|
-
})(),
|
|
1551
|
-
...toolCall.extra_content ? { extra_content: toolCall.extra_content } : {}
|
|
1552
|
-
})) ?? [],
|
|
1673
|
+
toolCalls,
|
|
1553
1674
|
usage: response.usage ? {
|
|
1554
1675
|
promptTokens: response.usage.prompt_tokens,
|
|
1555
1676
|
completionTokens: response.usage.completion_tokens,
|