@yourgpt/llm-sdk 2.6.0-beta.0 → 2.6.0-beta.1
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/README.md +77 -0
- package/dist/adapters/index.d.mts +11 -13
- package/dist/adapters/index.d.ts +11 -13
- package/dist/adapters/index.js +255 -164
- package/dist/adapters/index.mjs +255 -164
- package/dist/{base-C58Dsr9p.d.ts → base-BdTpUAWI.d.ts} +2 -1
- package/dist/{base-tNgbBaSo.d.mts → base-CkeT7u-O.d.mts} +2 -1
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/fallback/index.js +75 -39
- package/dist/fallback/index.mjs +75 -39
- package/dist/index.d.mts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +75 -28
- package/dist/index.mjs +75 -28
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +255 -164
- package/dist/providers/fireworks/index.mjs +255 -164
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +255 -164
- package/dist/providers/google/index.mjs +255 -164
- 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 +6 -23
- package/dist/providers/openai/index.d.ts +6 -23
- package/dist/providers/openai/index.js +656 -450
- package/dist/providers/openai/index.mjs +656 -450
- package/dist/providers/openrouter/index.d.mts +3 -3
- package/dist/providers/openrouter/index.d.ts +3 -3
- package/dist/providers/openrouter/index.js +255 -164
- package/dist/providers/openrouter/index.mjs +255 -164
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +255 -164
- package/dist/providers/togetherai/index.mjs +255 -164
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +255 -164
- package/dist/providers/xai/index.mjs +255 -164
- package/dist/{types-BkQCSiIt.d.mts → types-BW3csYo5.d.mts} +22 -1
- package/dist/{types-BkQCSiIt.d.ts → types-BW3csYo5.d.ts} +22 -1
- package/dist/{types-B6dhnguR.d.mts → types-BWRYIvl_.d.mts} +11 -4
- package/dist/{types-CCxPmkmK.d.ts → types-CpXcT-tY.d.ts} +11 -4
- package/dist/{types-BQ31QIsA.d.ts → types-DA54bSmX.d.ts} +3 -11
- package/dist/{types-BSSiJW2o.d.mts → types-NOswlhm9.d.mts} +3 -11
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/package.json +115 -48
- package/LICENSE +0 -21
package/dist/adapters/index.js
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/core/openai-parameters.ts
|
|
4
|
+
function capabilities(model) {
|
|
5
|
+
const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
|
|
6
|
+
const major = Number(gpt?.[1] ?? 0);
|
|
7
|
+
const minor = Number(gpt?.[2] ?? 0);
|
|
8
|
+
const chat = gpt?.[3]?.startsWith("chat") ?? false;
|
|
9
|
+
const reasoning = /^o\d+(?:-|$)/i.test(model) || major >= 5 && !chat;
|
|
10
|
+
const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
|
|
11
|
+
return { major, minor, reasoning, supportsNone };
|
|
12
|
+
}
|
|
13
|
+
function requiresOpenAIResponses(model, baseUrl, options = {}) {
|
|
14
|
+
if (options.parameterPolicy === "passthrough") return false;
|
|
15
|
+
const c = capabilities(model);
|
|
16
|
+
if (!c.reasoning || options.reasoningEffort === "none") return false;
|
|
17
|
+
if (!(c.major >= 6 || c.major === 5 && c.minor >= 4)) return false;
|
|
18
|
+
if (!baseUrl) return true;
|
|
19
|
+
try {
|
|
20
|
+
return new URL(baseUrl).hostname === "api.openai.com";
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function buildOpenAIParameters(model, maxTokens, temperature, options = {}, api = "chat") {
|
|
26
|
+
const c = capabilities(model ?? "");
|
|
27
|
+
const normalize = options.parameterPolicy !== "passthrough";
|
|
28
|
+
const effort = options.reasoningEffort;
|
|
29
|
+
if (normalize && c.reasoning && effort === "none" && !c.supportsNone) {
|
|
30
|
+
throw new Error(`${model} does not support reasoningEffort: none`);
|
|
31
|
+
}
|
|
32
|
+
if (normalize && c.major >= 6 && effort === "minimal") {
|
|
33
|
+
throw new Error(`${model} does not support reasoningEffort: minimal`);
|
|
34
|
+
}
|
|
35
|
+
const result = {
|
|
36
|
+
[api === "responses" ? "max_output_tokens" : normalize && c.reasoning ? "max_completion_tokens" : "max_tokens"]: maxTokens
|
|
37
|
+
};
|
|
38
|
+
if (effort !== void 0) {
|
|
39
|
+
if (api === "responses") result.reasoning = { effort };
|
|
40
|
+
else result.reasoning_effort = effort;
|
|
41
|
+
}
|
|
42
|
+
if (temperature !== void 0) {
|
|
43
|
+
if (!normalize || !c.reasoning || effort === "none" && c.supportsNone) {
|
|
44
|
+
result.temperature = temperature;
|
|
45
|
+
} else {
|
|
46
|
+
(options.onWarning ?? console.warn)(
|
|
47
|
+
`[llm-sdk] ${model}: omitted temperature because reasoning is enabled.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
3
54
|
// src/adapters/base.ts
|
|
4
55
|
function stringifyForDebug(value) {
|
|
5
56
|
return JSON.stringify(
|
|
@@ -119,16 +170,6 @@ function normalizeObjectJsonSchema(schema) {
|
|
|
119
170
|
}
|
|
120
171
|
return normalized;
|
|
121
172
|
}
|
|
122
|
-
function isOpenAIReasoningModel(modelId) {
|
|
123
|
-
if (!modelId) return false;
|
|
124
|
-
return /^(o1|o3|o4|gpt-5)/i.test(modelId);
|
|
125
|
-
}
|
|
126
|
-
function buildOpenAITokenParams(modelId, maxTokens, temperature) {
|
|
127
|
-
if (isOpenAIReasoningModel(modelId)) {
|
|
128
|
-
return { max_completion_tokens: maxTokens };
|
|
129
|
-
}
|
|
130
|
-
return { max_tokens: maxTokens, temperature };
|
|
131
|
-
}
|
|
132
173
|
function stripSchemaKeys(schema, keysToDrop, options = {}) {
|
|
133
174
|
if (Array.isArray(schema)) {
|
|
134
175
|
return schema.map((item) => stripSchemaKeys(item, keysToDrop, options));
|
|
@@ -475,6 +516,28 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
475
516
|
return formatted;
|
|
476
517
|
}
|
|
477
518
|
|
|
519
|
+
// src/core/provider-error.ts
|
|
520
|
+
function providerErrorEvent(error, code) {
|
|
521
|
+
const details = error ?? {};
|
|
522
|
+
const event = {
|
|
523
|
+
type: "error",
|
|
524
|
+
message: error instanceof Error ? error.message : String(error),
|
|
525
|
+
code,
|
|
526
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
527
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
528
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
529
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
530
|
+
};
|
|
531
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
532
|
+
return event;
|
|
533
|
+
}
|
|
534
|
+
function throwIfAborted(signal) {
|
|
535
|
+
if (!signal?.aborted) return;
|
|
536
|
+
const error = new Error("The operation was aborted");
|
|
537
|
+
error.name = "AbortError";
|
|
538
|
+
throw error;
|
|
539
|
+
}
|
|
540
|
+
|
|
478
541
|
// src/core/utils.ts
|
|
479
542
|
function generateId(prefix = "id") {
|
|
480
543
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
@@ -506,39 +569,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
506
569
|
const { default: OpenAI } = await import('openai');
|
|
507
570
|
this.client = new OpenAI({
|
|
508
571
|
apiKey: this.config.apiKey,
|
|
509
|
-
baseURL: this.config.baseUrl
|
|
572
|
+
baseURL: this.config.baseUrl,
|
|
573
|
+
organization: this.config.organization,
|
|
574
|
+
defaultHeaders: this.config.headers
|
|
510
575
|
});
|
|
511
576
|
}
|
|
512
577
|
return this.client;
|
|
513
578
|
}
|
|
579
|
+
parameterOptions(request) {
|
|
580
|
+
return {
|
|
581
|
+
...this.config,
|
|
582
|
+
reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
toolDefinitions(request) {
|
|
586
|
+
if (request.toolDefinitions?.length) return request.toolDefinitions;
|
|
587
|
+
return formatTools(request.actions ?? []).map((tool) => ({
|
|
588
|
+
name: tool.function.name,
|
|
589
|
+
description: tool.function.description ?? "",
|
|
590
|
+
location: "server",
|
|
591
|
+
inputSchema: tool.function.parameters
|
|
592
|
+
}));
|
|
593
|
+
}
|
|
514
594
|
shouldUseResponsesApi(request) {
|
|
515
|
-
|
|
516
|
-
if (
|
|
517
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
|
|
595
|
+
if (this.toolDefinitions(request).length === 0) return false;
|
|
596
|
+
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
518
597
|
return true;
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
598
|
+
return requiresOpenAIResponses(
|
|
599
|
+
request.config?.model || this.model,
|
|
600
|
+
this.config.baseUrl,
|
|
601
|
+
this.parameterOptions(request)
|
|
522
602
|
);
|
|
523
603
|
}
|
|
524
|
-
/**
|
|
525
|
-
* Whether this model rejects function tools on /v1/chat/completions.
|
|
526
|
-
*
|
|
527
|
-
* Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
|
|
528
|
-
* providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
|
|
529
|
-
* restriction and may not implement /v1/responses at all.
|
|
530
|
-
*/
|
|
531
|
-
requiresResponsesApiForTools(modelId) {
|
|
532
|
-
if (!modelId) return false;
|
|
533
|
-
if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
|
|
534
|
-
const baseUrl = this.config.baseUrl;
|
|
535
|
-
if (!baseUrl) return true;
|
|
536
|
-
try {
|
|
537
|
-
return new URL(baseUrl).hostname === "api.openai.com";
|
|
538
|
-
} catch {
|
|
539
|
-
return false;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
604
|
/**
|
|
543
605
|
* Convert one message's content to Responses content parts.
|
|
544
606
|
*
|
|
@@ -569,7 +631,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
569
631
|
});
|
|
570
632
|
}
|
|
571
633
|
buildResponsesInput(request) {
|
|
572
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
|
|
634
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
573
635
|
const input = [];
|
|
574
636
|
for (const message of sourceMessages) {
|
|
575
637
|
if (message.role === "system") {
|
|
@@ -619,6 +681,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
619
681
|
}
|
|
620
682
|
return input;
|
|
621
683
|
}
|
|
684
|
+
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
685
|
+
formatRawMessages(messages) {
|
|
686
|
+
return messages.map((message) => {
|
|
687
|
+
const { attachments, ...rest } = message;
|
|
688
|
+
let content = message.content;
|
|
689
|
+
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
690
|
+
content = null;
|
|
691
|
+
}
|
|
692
|
+
if (Array.isArray(attachments) && attachments.length > 0) {
|
|
693
|
+
const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
|
|
694
|
+
(attachment) => attachmentToOpenAIImage(attachment)
|
|
695
|
+
).filter((image) => image !== null);
|
|
696
|
+
if (images.length > 0) {
|
|
697
|
+
const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
|
|
698
|
+
content = [...parts, ...images];
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return { ...rest, content };
|
|
702
|
+
});
|
|
703
|
+
}
|
|
622
704
|
/**
|
|
623
705
|
* Build the web_search tool for the Responses API, or undefined when web
|
|
624
706
|
* search is off.
|
|
@@ -700,13 +782,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
700
782
|
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
|
|
701
783
|
id: item.call_id ?? item.id ?? generateToolCallId(),
|
|
702
784
|
name: item.name,
|
|
703
|
-
args: (
|
|
704
|
-
try {
|
|
705
|
-
return JSON.parse(item.arguments ?? "{}");
|
|
706
|
-
} catch {
|
|
707
|
-
return {};
|
|
708
|
-
}
|
|
709
|
-
})()
|
|
785
|
+
args: JSON.parse(item.arguments ?? "{}")
|
|
710
786
|
})) : [];
|
|
711
787
|
return {
|
|
712
788
|
content,
|
|
@@ -730,18 +806,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
730
806
|
instructions: request.systemPrompt,
|
|
731
807
|
input: this.buildResponsesInput(request),
|
|
732
808
|
tools: this.buildResponsesTools(
|
|
733
|
-
|
|
809
|
+
this.toolDefinitions(request),
|
|
734
810
|
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
|
|
735
811
|
this.buildResponsesWebSearchTool(request)
|
|
736
812
|
),
|
|
737
|
-
tool_choice: openaiToolOptions?.toolChoice
|
|
813
|
+
tool_choice: openaiToolOptions?.toolChoice,
|
|
738
814
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
815
|
+
...buildOpenAIParameters(
|
|
816
|
+
modelIdForPayload,
|
|
817
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
818
|
+
request.config?.temperature ?? this.config.temperature,
|
|
819
|
+
this.parameterOptions(request),
|
|
820
|
+
"responses"
|
|
821
|
+
),
|
|
745
822
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
746
823
|
stream
|
|
747
824
|
};
|
|
@@ -749,10 +826,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
749
826
|
}
|
|
750
827
|
async completeWithResponses(request) {
|
|
751
828
|
const client = await this.getClient();
|
|
829
|
+
throwIfAborted(request.signal);
|
|
752
830
|
const payload = this.buildResponsesPayload(request, false);
|
|
753
831
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
754
|
-
|
|
832
|
+
if (!client.responses?.create)
|
|
833
|
+
throw new Error(
|
|
834
|
+
"This OpenAI client does not support Responses; install an openai version with Responses support."
|
|
835
|
+
);
|
|
836
|
+
const response = await client.responses.create(payload, {
|
|
837
|
+
signal: request.signal
|
|
838
|
+
});
|
|
839
|
+
throwIfAborted(request.signal);
|
|
755
840
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
841
|
+
if (response.status && response.status !== "completed") {
|
|
842
|
+
throw Object.assign(
|
|
843
|
+
new Error(
|
|
844
|
+
response.error?.message ?? `Responses request ${response.status}`
|
|
845
|
+
),
|
|
846
|
+
response.error
|
|
847
|
+
);
|
|
848
|
+
}
|
|
756
849
|
return this.parseResponsesResult(response);
|
|
757
850
|
}
|
|
758
851
|
/**
|
|
@@ -770,13 +863,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
770
863
|
*/
|
|
771
864
|
async *streamWithResponses(request) {
|
|
772
865
|
const client = await this.getClient();
|
|
866
|
+
throwIfAborted(request.signal);
|
|
773
867
|
const payload = this.buildResponsesPayload(request, true);
|
|
774
868
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
775
|
-
|
|
869
|
+
if (!client.responses?.create)
|
|
870
|
+
throw new Error(
|
|
871
|
+
"This OpenAI client does not support Responses; install an openai version with Responses support."
|
|
872
|
+
);
|
|
873
|
+
const stream = await client.responses.create(payload, {
|
|
874
|
+
signal: request.signal
|
|
875
|
+
});
|
|
776
876
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
777
877
|
let usage;
|
|
778
878
|
const citations = [];
|
|
879
|
+
let completed = false;
|
|
779
880
|
function* flushToolCalls() {
|
|
881
|
+
for (const call of toolCalls.values()) {
|
|
882
|
+
if (!call.name)
|
|
883
|
+
throw new Error("Responses tool call is missing its name");
|
|
884
|
+
JSON.parse(call.arguments || "{}");
|
|
885
|
+
}
|
|
780
886
|
for (const call of toolCalls.values()) {
|
|
781
887
|
yield { type: "action:start", id: call.id, name: call.name };
|
|
782
888
|
yield { type: "action:args", id: call.id, args: call.arguments };
|
|
@@ -785,7 +891,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
785
891
|
toolCalls.clear();
|
|
786
892
|
}
|
|
787
893
|
for await (const event of stream) {
|
|
788
|
-
|
|
894
|
+
throwIfAborted(request.signal);
|
|
789
895
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
790
896
|
const index = event?.output_index ?? 0;
|
|
791
897
|
switch (event?.type) {
|
|
@@ -815,8 +921,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
815
921
|
}
|
|
816
922
|
break;
|
|
817
923
|
}
|
|
818
|
-
case "response.completed":
|
|
819
|
-
|
|
924
|
+
case "response.completed": {
|
|
925
|
+
completed = true;
|
|
820
926
|
const found = this.collectResponsesCitations(
|
|
821
927
|
event.response?.output,
|
|
822
928
|
citations.length
|
|
@@ -832,13 +938,27 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
832
938
|
}
|
|
833
939
|
break;
|
|
834
940
|
}
|
|
835
|
-
case "
|
|
836
|
-
case "response.failed":
|
|
941
|
+
case "response.incomplete":
|
|
837
942
|
throw new Error(
|
|
838
|
-
|
|
943
|
+
`Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
|
|
944
|
+
);
|
|
945
|
+
case "error":
|
|
946
|
+
case "response.failed": {
|
|
947
|
+
const details = event.response?.error ?? event;
|
|
948
|
+
throw Object.assign(
|
|
949
|
+
new Error(details.message ?? "Responses stream failed"),
|
|
950
|
+
{
|
|
951
|
+
code: details.code,
|
|
952
|
+
param: details.param,
|
|
953
|
+
status: details.status
|
|
954
|
+
}
|
|
839
955
|
);
|
|
956
|
+
}
|
|
840
957
|
}
|
|
841
958
|
}
|
|
959
|
+
throwIfAborted(request.signal);
|
|
960
|
+
if (!completed)
|
|
961
|
+
throw new Error("Responses stream ended without a completed response");
|
|
842
962
|
yield* flushToolCalls();
|
|
843
963
|
if (citations.length > 0) {
|
|
844
964
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
@@ -847,6 +967,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
847
967
|
yield { type: "done", usage };
|
|
848
968
|
}
|
|
849
969
|
async *stream(request) {
|
|
970
|
+
throwIfAborted(request.signal);
|
|
850
971
|
if (this.shouldUseResponsesApi(request)) {
|
|
851
972
|
const messageId2 = generateMessageId();
|
|
852
973
|
yield { type: "message:start", id: messageId2 };
|
|
@@ -854,47 +975,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
854
975
|
yield* this.streamWithResponses(request);
|
|
855
976
|
return;
|
|
856
977
|
} catch (error) {
|
|
857
|
-
yield
|
|
858
|
-
type: "error",
|
|
859
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
860
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
861
|
-
};
|
|
978
|
+
yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
|
|
862
979
|
return;
|
|
863
980
|
}
|
|
864
981
|
}
|
|
865
982
|
const client = await this.getClient();
|
|
866
983
|
let messages;
|
|
867
984
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
868
|
-
const processedMessages = request.rawMessages
|
|
869
|
-
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
|
|
870
|
-
return { ...msg, content: null };
|
|
871
|
-
}
|
|
872
|
-
const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
|
|
873
|
-
if (hasAttachments) {
|
|
874
|
-
const content = [];
|
|
875
|
-
if (msg.content) {
|
|
876
|
-
content.push({ type: "text", text: msg.content });
|
|
877
|
-
}
|
|
878
|
-
for (const attachment of msg.attachments) {
|
|
879
|
-
if (attachment.type === "image") {
|
|
880
|
-
let imageUrl;
|
|
881
|
-
if (attachment.url) {
|
|
882
|
-
imageUrl = attachment.url;
|
|
883
|
-
} else if (attachment.data) {
|
|
884
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
885
|
-
} else {
|
|
886
|
-
continue;
|
|
887
|
-
}
|
|
888
|
-
content.push({
|
|
889
|
-
type: "image_url",
|
|
890
|
-
image_url: { url: imageUrl, detail: "auto" }
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
return { ...msg, content, attachments: void 0 };
|
|
895
|
-
}
|
|
896
|
-
return msg;
|
|
897
|
-
});
|
|
985
|
+
const processedMessages = this.formatRawMessages(request.rawMessages);
|
|
898
986
|
if (request.systemPrompt) {
|
|
899
987
|
const hasSystem = processedMessages.some((m) => m.role === "system");
|
|
900
988
|
if (!hasSystem) {
|
|
@@ -914,7 +1002,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
914
1002
|
request.systemPrompt
|
|
915
1003
|
);
|
|
916
1004
|
}
|
|
917
|
-
const tools = request.
|
|
1005
|
+
const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
|
|
1006
|
+
type: "function",
|
|
1007
|
+
function: {
|
|
1008
|
+
name: tool.name,
|
|
1009
|
+
description: tool.description,
|
|
1010
|
+
parameters: normalizeObjectJsonSchema(
|
|
1011
|
+
tool.inputSchema
|
|
1012
|
+
)
|
|
1013
|
+
}
|
|
1014
|
+
})) : formatTools(request.actions ?? []);
|
|
918
1015
|
const webSearchConfig = request.webSearch ?? this.config.webSearch;
|
|
919
1016
|
if (webSearchConfig) {
|
|
920
1017
|
const webSearchTool = {
|
|
@@ -943,26 +1040,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
943
1040
|
tools: tools.length > 0 ? tools : void 0,
|
|
944
1041
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
945
1042
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
946
|
-
...
|
|
1043
|
+
...buildOpenAIParameters(
|
|
947
1044
|
modelIdForPayload,
|
|
948
1045
|
request.config?.maxTokens ?? this.config.maxTokens,
|
|
949
|
-
request.config?.temperature ?? this.config.temperature
|
|
1046
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1047
|
+
this.parameterOptions(request)
|
|
950
1048
|
),
|
|
951
1049
|
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
952
1050
|
stream: true,
|
|
953
1051
|
stream_options: { include_usage: true }
|
|
954
1052
|
};
|
|
955
1053
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
956
|
-
const stream = await client.chat.completions.create(payload
|
|
957
|
-
|
|
1054
|
+
const stream = await client.chat.completions.create(payload, {
|
|
1055
|
+
signal: request.signal
|
|
1056
|
+
});
|
|
1057
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
1058
|
+
let finishReason;
|
|
958
1059
|
const collectedCitations = [];
|
|
959
1060
|
let citationIndex = 0;
|
|
960
1061
|
let usage;
|
|
961
1062
|
for await (const chunk of stream) {
|
|
962
1063
|
logProviderPayload("openai", "stream chunk", chunk, request.debug);
|
|
963
|
-
|
|
964
|
-
break;
|
|
965
|
-
}
|
|
1064
|
+
throwIfAborted(request.signal);
|
|
966
1065
|
const delta = chunk.choices[0]?.delta;
|
|
967
1066
|
const choice = chunk.choices[0];
|
|
968
1067
|
if (delta?.content) {
|
|
@@ -985,38 +1084,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
985
1084
|
}
|
|
986
1085
|
}
|
|
987
1086
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
const tcExtraContent = toolCall.extra_content;
|
|
1004
|
-
currentToolCall = {
|
|
1005
|
-
id: toolCall.id,
|
|
1006
|
-
name: toolCall.function?.name || "",
|
|
1007
|
-
arguments: toolCall.function?.arguments || "",
|
|
1008
|
-
...tcExtraContent ? { extra_content: tcExtraContent } : {}
|
|
1009
|
-
};
|
|
1010
|
-
yield {
|
|
1011
|
-
type: "action:start",
|
|
1012
|
-
id: currentToolCall.id,
|
|
1013
|
-
name: currentToolCall.name,
|
|
1014
|
-
...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
|
|
1015
|
-
};
|
|
1016
|
-
} else if (currentToolCall && toolCall.function?.arguments) {
|
|
1017
|
-
currentToolCall.arguments += toolCall.function.arguments;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1087
|
+
for (const part of delta?.tool_calls ?? []) {
|
|
1088
|
+
const index = part.index ?? 0;
|
|
1089
|
+
const call = toolCalls.get(index) ?? {
|
|
1090
|
+
id: "",
|
|
1091
|
+
name: "",
|
|
1092
|
+
arguments: ""
|
|
1093
|
+
};
|
|
1094
|
+
if (part.id) call.id = part.id;
|
|
1095
|
+
if (part.function?.name) call.name += part.function.name;
|
|
1096
|
+
if (part.function?.arguments)
|
|
1097
|
+
call.arguments += part.function.arguments;
|
|
1098
|
+
if (part.extra_content) call.extra_content = part.extra_content;
|
|
1099
|
+
toolCalls.set(index, call);
|
|
1020
1100
|
}
|
|
1021
1101
|
if (chunk.usage) {
|
|
1022
1102
|
usage = {
|
|
@@ -1025,21 +1105,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1025
1105
|
total_tokens: chunk.usage.total_tokens
|
|
1026
1106
|
};
|
|
1027
1107
|
}
|
|
1028
|
-
if (choice?.finish_reason)
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1108
|
+
if (choice?.finish_reason) finishReason = choice.finish_reason;
|
|
1109
|
+
}
|
|
1110
|
+
throwIfAborted(request.signal);
|
|
1111
|
+
if (!finishReason)
|
|
1112
|
+
throw new Error("OpenAI stream ended without a finish reason");
|
|
1113
|
+
if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
|
|
1114
|
+
throw new Error("OpenAI stream ended with incomplete tool calls");
|
|
1115
|
+
}
|
|
1116
|
+
for (const call of toolCalls.values()) {
|
|
1117
|
+
if (!call.id || !call.name)
|
|
1118
|
+
throw new Error("OpenAI stream contains an incomplete tool call");
|
|
1119
|
+
JSON.parse(call.arguments || "{}");
|
|
1120
|
+
}
|
|
1121
|
+
for (const call of toolCalls.values()) {
|
|
1122
|
+
yield {
|
|
1123
|
+
type: "action:start",
|
|
1124
|
+
id: call.id,
|
|
1125
|
+
name: call.name,
|
|
1126
|
+
...call.extra_content ? { extra_content: call.extra_content } : {}
|
|
1127
|
+
};
|
|
1128
|
+
yield { type: "action:args", id: call.id, args: call.arguments };
|
|
1129
|
+
yield { type: "action:end", id: call.id, name: call.name };
|
|
1043
1130
|
}
|
|
1044
1131
|
if (collectedCitations.length > 0) {
|
|
1045
1132
|
const uniqueCitations = deduplicateCitations(collectedCitations);
|
|
@@ -1048,26 +1135,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1048
1135
|
yield { type: "message:end" };
|
|
1049
1136
|
yield { type: "done", usage };
|
|
1050
1137
|
} catch (error) {
|
|
1051
|
-
yield {
|
|
1052
|
-
type: "error",
|
|
1053
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
1054
|
-
code: `${this.provider.toUpperCase()}_ERROR`
|
|
1055
|
-
};
|
|
1138
|
+
yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
|
|
1056
1139
|
}
|
|
1057
1140
|
}
|
|
1058
1141
|
async complete(request) {
|
|
1142
|
+
throwIfAborted(request.signal);
|
|
1059
1143
|
if (this.shouldUseResponsesApi(request)) {
|
|
1060
1144
|
return this.completeWithResponses(request);
|
|
1061
1145
|
}
|
|
1062
1146
|
const client = await this.getClient();
|
|
1063
1147
|
let messages;
|
|
1064
1148
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
1065
|
-
const sanitized = request.rawMessages
|
|
1066
|
-
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
|
|
1067
|
-
return { ...msg, content: null };
|
|
1068
|
-
}
|
|
1069
|
-
return msg;
|
|
1070
|
-
});
|
|
1149
|
+
const sanitized = this.formatRawMessages(request.rawMessages);
|
|
1071
1150
|
if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
|
|
1072
1151
|
messages = [
|
|
1073
1152
|
{ role: "system", content: request.systemPrompt },
|
|
@@ -1082,7 +1161,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1082
1161
|
request.systemPrompt
|
|
1083
1162
|
);
|
|
1084
1163
|
}
|
|
1085
|
-
const tools = request.
|
|
1164
|
+
const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
|
|
1165
|
+
type: "function",
|
|
1166
|
+
function: {
|
|
1167
|
+
name: tool.name,
|
|
1168
|
+
description: tool.description,
|
|
1169
|
+
parameters: normalizeObjectJsonSchema(
|
|
1170
|
+
tool.inputSchema
|
|
1171
|
+
)
|
|
1172
|
+
}
|
|
1173
|
+
})) : formatTools(request.actions ?? []);
|
|
1086
1174
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1087
1175
|
const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
|
|
1088
1176
|
type: "function",
|
|
@@ -1097,16 +1185,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1097
1185
|
tools: tools.length > 0 ? tools : void 0,
|
|
1098
1186
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
1099
1187
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
1100
|
-
...
|
|
1188
|
+
...buildOpenAIParameters(
|
|
1101
1189
|
modelIdForCompletePayload,
|
|
1102
1190
|
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1103
|
-
request.config?.temperature ?? this.config.temperature
|
|
1191
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1192
|
+
this.parameterOptions(request)
|
|
1104
1193
|
),
|
|
1105
1194
|
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
1106
1195
|
stream: false
|
|
1107
1196
|
};
|
|
1108
1197
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
1109
|
-
const response = await client.chat.completions.create(payload
|
|
1198
|
+
const response = await client.chat.completions.create(payload, {
|
|
1199
|
+
signal: request.signal
|
|
1200
|
+
});
|
|
1110
1201
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
1111
1202
|
const choice = response.choices?.[0];
|
|
1112
1203
|
const message = choice?.message;
|