@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
|
@@ -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(
|
|
@@ -106,16 +157,6 @@ function normalizeObjectJsonSchema(schema) {
|
|
|
106
157
|
}
|
|
107
158
|
return normalized;
|
|
108
159
|
}
|
|
109
|
-
function isOpenAIReasoningModel(modelId) {
|
|
110
|
-
if (!modelId) return false;
|
|
111
|
-
return /^(o1|o3|o4|gpt-5)/i.test(modelId);
|
|
112
|
-
}
|
|
113
|
-
function buildOpenAITokenParams(modelId, maxTokens, temperature) {
|
|
114
|
-
if (isOpenAIReasoningModel(modelId)) {
|
|
115
|
-
return { max_completion_tokens: maxTokens };
|
|
116
|
-
}
|
|
117
|
-
return { max_tokens: maxTokens, temperature };
|
|
118
|
-
}
|
|
119
160
|
function toOpenAIResponseFormat(rf) {
|
|
120
161
|
if (!rf) return void 0;
|
|
121
162
|
if (rf.type === "json_object") return { type: "json_object" };
|
|
@@ -442,6 +483,28 @@ function formatMessages(messages) {
|
|
|
442
483
|
});
|
|
443
484
|
}
|
|
444
485
|
|
|
486
|
+
// src/core/provider-error.ts
|
|
487
|
+
function providerErrorEvent(error, code) {
|
|
488
|
+
const details = error ?? {};
|
|
489
|
+
const event = {
|
|
490
|
+
type: "error",
|
|
491
|
+
message: error instanceof Error ? error.message : String(error),
|
|
492
|
+
code,
|
|
493
|
+
...typeof details.status === "number" ? { status: details.status } : {},
|
|
494
|
+
...typeof details.code === "string" ? { providerCode: details.code } : {},
|
|
495
|
+
...typeof details.param === "string" ? { param: details.param } : {},
|
|
496
|
+
...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
|
|
497
|
+
};
|
|
498
|
+
Object.defineProperty(event, "cause", { value: error, enumerable: false });
|
|
499
|
+
return event;
|
|
500
|
+
}
|
|
501
|
+
function throwIfAborted(signal) {
|
|
502
|
+
if (!signal?.aborted) return;
|
|
503
|
+
const error = new Error("The operation was aborted");
|
|
504
|
+
error.name = "AbortError";
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
507
|
+
|
|
445
508
|
// src/core/utils.ts
|
|
446
509
|
function generateId(prefix = "id") {
|
|
447
510
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
@@ -473,39 +536,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
473
536
|
const { default: OpenAI } = await import('openai');
|
|
474
537
|
this.client = new OpenAI({
|
|
475
538
|
apiKey: this.config.apiKey,
|
|
476
|
-
baseURL: this.config.baseUrl
|
|
539
|
+
baseURL: this.config.baseUrl,
|
|
540
|
+
organization: this.config.organization,
|
|
541
|
+
defaultHeaders: this.config.headers
|
|
477
542
|
});
|
|
478
543
|
}
|
|
479
544
|
return this.client;
|
|
480
545
|
}
|
|
546
|
+
parameterOptions(request) {
|
|
547
|
+
return {
|
|
548
|
+
...this.config,
|
|
549
|
+
reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
toolDefinitions(request) {
|
|
553
|
+
if (request.toolDefinitions?.length) return request.toolDefinitions;
|
|
554
|
+
return formatTools(request.actions ?? []).map((tool) => ({
|
|
555
|
+
name: tool.function.name,
|
|
556
|
+
description: tool.function.description ?? "",
|
|
557
|
+
location: "server",
|
|
558
|
+
inputSchema: tool.function.parameters
|
|
559
|
+
}));
|
|
560
|
+
}
|
|
481
561
|
shouldUseResponsesApi(request) {
|
|
482
|
-
|
|
483
|
-
if (
|
|
484
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
|
|
562
|
+
if (this.toolDefinitions(request).length === 0) return false;
|
|
563
|
+
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
485
564
|
return true;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
565
|
+
return requiresOpenAIResponses(
|
|
566
|
+
request.config?.model || this.model,
|
|
567
|
+
this.config.baseUrl,
|
|
568
|
+
this.parameterOptions(request)
|
|
489
569
|
);
|
|
490
570
|
}
|
|
491
|
-
/**
|
|
492
|
-
* Whether this model rejects function tools on /v1/chat/completions.
|
|
493
|
-
*
|
|
494
|
-
* Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
|
|
495
|
-
* providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
|
|
496
|
-
* restriction and may not implement /v1/responses at all.
|
|
497
|
-
*/
|
|
498
|
-
requiresResponsesApiForTools(modelId) {
|
|
499
|
-
if (!modelId) return false;
|
|
500
|
-
if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
|
|
501
|
-
const baseUrl = this.config.baseUrl;
|
|
502
|
-
if (!baseUrl) return true;
|
|
503
|
-
try {
|
|
504
|
-
return new URL(baseUrl).hostname === "api.openai.com";
|
|
505
|
-
} catch {
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
571
|
/**
|
|
510
572
|
* Convert one message's content to Responses content parts.
|
|
511
573
|
*
|
|
@@ -536,7 +598,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
536
598
|
});
|
|
537
599
|
}
|
|
538
600
|
buildResponsesInput(request) {
|
|
539
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
|
|
601
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
540
602
|
const input = [];
|
|
541
603
|
for (const message of sourceMessages) {
|
|
542
604
|
if (message.role === "system") {
|
|
@@ -586,6 +648,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
586
648
|
}
|
|
587
649
|
return input;
|
|
588
650
|
}
|
|
651
|
+
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
652
|
+
formatRawMessages(messages) {
|
|
653
|
+
return messages.map((message) => {
|
|
654
|
+
const { attachments, ...rest } = message;
|
|
655
|
+
let content = message.content;
|
|
656
|
+
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
657
|
+
content = null;
|
|
658
|
+
}
|
|
659
|
+
if (Array.isArray(attachments) && attachments.length > 0) {
|
|
660
|
+
const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
|
|
661
|
+
(attachment) => attachmentToOpenAIImage(attachment)
|
|
662
|
+
).filter((image) => image !== null);
|
|
663
|
+
if (images.length > 0) {
|
|
664
|
+
const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
|
|
665
|
+
content = [...parts, ...images];
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return { ...rest, content };
|
|
669
|
+
});
|
|
670
|
+
}
|
|
589
671
|
/**
|
|
590
672
|
* Build the web_search tool for the Responses API, or undefined when web
|
|
591
673
|
* search is off.
|
|
@@ -667,13 +749,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
667
749
|
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
|
|
668
750
|
id: item.call_id ?? item.id ?? generateToolCallId(),
|
|
669
751
|
name: item.name,
|
|
670
|
-
args: (
|
|
671
|
-
try {
|
|
672
|
-
return JSON.parse(item.arguments ?? "{}");
|
|
673
|
-
} catch {
|
|
674
|
-
return {};
|
|
675
|
-
}
|
|
676
|
-
})()
|
|
752
|
+
args: JSON.parse(item.arguments ?? "{}")
|
|
677
753
|
})) : [];
|
|
678
754
|
return {
|
|
679
755
|
content,
|
|
@@ -697,18 +773,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
697
773
|
instructions: request.systemPrompt,
|
|
698
774
|
input: this.buildResponsesInput(request),
|
|
699
775
|
tools: this.buildResponsesTools(
|
|
700
|
-
|
|
776
|
+
this.toolDefinitions(request),
|
|
701
777
|
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
|
|
702
778
|
this.buildResponsesWebSearchTool(request)
|
|
703
779
|
),
|
|
704
|
-
tool_choice: openaiToolOptions?.toolChoice
|
|
780
|
+
tool_choice: openaiToolOptions?.toolChoice,
|
|
705
781
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
782
|
+
...buildOpenAIParameters(
|
|
783
|
+
modelIdForPayload,
|
|
784
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
785
|
+
request.config?.temperature ?? this.config.temperature,
|
|
786
|
+
this.parameterOptions(request),
|
|
787
|
+
"responses"
|
|
788
|
+
),
|
|
712
789
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
713
790
|
stream
|
|
714
791
|
};
|
|
@@ -716,10 +793,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
716
793
|
}
|
|
717
794
|
async completeWithResponses(request) {
|
|
718
795
|
const client = await this.getClient();
|
|
796
|
+
throwIfAborted(request.signal);
|
|
719
797
|
const payload = this.buildResponsesPayload(request, false);
|
|
720
798
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
721
|
-
|
|
799
|
+
if (!client.responses?.create)
|
|
800
|
+
throw new Error(
|
|
801
|
+
"This OpenAI client does not support Responses; install an openai version with Responses support."
|
|
802
|
+
);
|
|
803
|
+
const response = await client.responses.create(payload, {
|
|
804
|
+
signal: request.signal
|
|
805
|
+
});
|
|
806
|
+
throwIfAborted(request.signal);
|
|
722
807
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
808
|
+
if (response.status && response.status !== "completed") {
|
|
809
|
+
throw Object.assign(
|
|
810
|
+
new Error(
|
|
811
|
+
response.error?.message ?? `Responses request ${response.status}`
|
|
812
|
+
),
|
|
813
|
+
response.error
|
|
814
|
+
);
|
|
815
|
+
}
|
|
723
816
|
return this.parseResponsesResult(response);
|
|
724
817
|
}
|
|
725
818
|
/**
|
|
@@ -737,13 +830,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
737
830
|
*/
|
|
738
831
|
async *streamWithResponses(request) {
|
|
739
832
|
const client = await this.getClient();
|
|
833
|
+
throwIfAborted(request.signal);
|
|
740
834
|
const payload = this.buildResponsesPayload(request, true);
|
|
741
835
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
742
|
-
|
|
836
|
+
if (!client.responses?.create)
|
|
837
|
+
throw new Error(
|
|
838
|
+
"This OpenAI client does not support Responses; install an openai version with Responses support."
|
|
839
|
+
);
|
|
840
|
+
const stream = await client.responses.create(payload, {
|
|
841
|
+
signal: request.signal
|
|
842
|
+
});
|
|
743
843
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
744
844
|
let usage;
|
|
745
845
|
const citations = [];
|
|
846
|
+
let completed = false;
|
|
746
847
|
function* flushToolCalls() {
|
|
848
|
+
for (const call of toolCalls.values()) {
|
|
849
|
+
if (!call.name)
|
|
850
|
+
throw new Error("Responses tool call is missing its name");
|
|
851
|
+
JSON.parse(call.arguments || "{}");
|
|
852
|
+
}
|
|
747
853
|
for (const call of toolCalls.values()) {
|
|
748
854
|
yield { type: "action:start", id: call.id, name: call.name };
|
|
749
855
|
yield { type: "action:args", id: call.id, args: call.arguments };
|
|
@@ -752,7 +858,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
752
858
|
toolCalls.clear();
|
|
753
859
|
}
|
|
754
860
|
for await (const event of stream) {
|
|
755
|
-
|
|
861
|
+
throwIfAborted(request.signal);
|
|
756
862
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
757
863
|
const index = event?.output_index ?? 0;
|
|
758
864
|
switch (event?.type) {
|
|
@@ -782,8 +888,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
782
888
|
}
|
|
783
889
|
break;
|
|
784
890
|
}
|
|
785
|
-
case "response.completed":
|
|
786
|
-
|
|
891
|
+
case "response.completed": {
|
|
892
|
+
completed = true;
|
|
787
893
|
const found = this.collectResponsesCitations(
|
|
788
894
|
event.response?.output,
|
|
789
895
|
citations.length
|
|
@@ -799,13 +905,27 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
799
905
|
}
|
|
800
906
|
break;
|
|
801
907
|
}
|
|
802
|
-
case "
|
|
803
|
-
case "response.failed":
|
|
908
|
+
case "response.incomplete":
|
|
804
909
|
throw new Error(
|
|
805
|
-
|
|
910
|
+
`Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
|
|
806
911
|
);
|
|
912
|
+
case "error":
|
|
913
|
+
case "response.failed": {
|
|
914
|
+
const details = event.response?.error ?? event;
|
|
915
|
+
throw Object.assign(
|
|
916
|
+
new Error(details.message ?? "Responses stream failed"),
|
|
917
|
+
{
|
|
918
|
+
code: details.code,
|
|
919
|
+
param: details.param,
|
|
920
|
+
status: details.status
|
|
921
|
+
}
|
|
922
|
+
);
|
|
923
|
+
}
|
|
807
924
|
}
|
|
808
925
|
}
|
|
926
|
+
throwIfAborted(request.signal);
|
|
927
|
+
if (!completed)
|
|
928
|
+
throw new Error("Responses stream ended without a completed response");
|
|
809
929
|
yield* flushToolCalls();
|
|
810
930
|
if (citations.length > 0) {
|
|
811
931
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
@@ -814,6 +934,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
814
934
|
yield { type: "done", usage };
|
|
815
935
|
}
|
|
816
936
|
async *stream(request) {
|
|
937
|
+
throwIfAborted(request.signal);
|
|
817
938
|
if (this.shouldUseResponsesApi(request)) {
|
|
818
939
|
const messageId2 = generateMessageId();
|
|
819
940
|
yield { type: "message:start", id: messageId2 };
|
|
@@ -821,47 +942,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
821
942
|
yield* this.streamWithResponses(request);
|
|
822
943
|
return;
|
|
823
944
|
} catch (error) {
|
|
824
|
-
yield
|
|
825
|
-
type: "error",
|
|
826
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
827
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
828
|
-
};
|
|
945
|
+
yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
|
|
829
946
|
return;
|
|
830
947
|
}
|
|
831
948
|
}
|
|
832
949
|
const client = await this.getClient();
|
|
833
950
|
let messages;
|
|
834
951
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
835
|
-
const processedMessages = request.rawMessages
|
|
836
|
-
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
|
|
837
|
-
return { ...msg, content: null };
|
|
838
|
-
}
|
|
839
|
-
const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
|
|
840
|
-
if (hasAttachments) {
|
|
841
|
-
const content = [];
|
|
842
|
-
if (msg.content) {
|
|
843
|
-
content.push({ type: "text", text: msg.content });
|
|
844
|
-
}
|
|
845
|
-
for (const attachment of msg.attachments) {
|
|
846
|
-
if (attachment.type === "image") {
|
|
847
|
-
let imageUrl;
|
|
848
|
-
if (attachment.url) {
|
|
849
|
-
imageUrl = attachment.url;
|
|
850
|
-
} else if (attachment.data) {
|
|
851
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
852
|
-
} else {
|
|
853
|
-
continue;
|
|
854
|
-
}
|
|
855
|
-
content.push({
|
|
856
|
-
type: "image_url",
|
|
857
|
-
image_url: { url: imageUrl, detail: "auto" }
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
return { ...msg, content, attachments: void 0 };
|
|
862
|
-
}
|
|
863
|
-
return msg;
|
|
864
|
-
});
|
|
952
|
+
const processedMessages = this.formatRawMessages(request.rawMessages);
|
|
865
953
|
if (request.systemPrompt) {
|
|
866
954
|
const hasSystem = processedMessages.some((m) => m.role === "system");
|
|
867
955
|
if (!hasSystem) {
|
|
@@ -881,7 +969,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
881
969
|
request.systemPrompt
|
|
882
970
|
);
|
|
883
971
|
}
|
|
884
|
-
const tools = request.
|
|
972
|
+
const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
|
|
973
|
+
type: "function",
|
|
974
|
+
function: {
|
|
975
|
+
name: tool.name,
|
|
976
|
+
description: tool.description,
|
|
977
|
+
parameters: normalizeObjectJsonSchema(
|
|
978
|
+
tool.inputSchema
|
|
979
|
+
)
|
|
980
|
+
}
|
|
981
|
+
})) : formatTools(request.actions ?? []);
|
|
885
982
|
const webSearchConfig = request.webSearch ?? this.config.webSearch;
|
|
886
983
|
if (webSearchConfig) {
|
|
887
984
|
const webSearchTool = {
|
|
@@ -910,26 +1007,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
910
1007
|
tools: tools.length > 0 ? tools : void 0,
|
|
911
1008
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
912
1009
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
913
|
-
...
|
|
1010
|
+
...buildOpenAIParameters(
|
|
914
1011
|
modelIdForPayload,
|
|
915
1012
|
request.config?.maxTokens ?? this.config.maxTokens,
|
|
916
|
-
request.config?.temperature ?? this.config.temperature
|
|
1013
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1014
|
+
this.parameterOptions(request)
|
|
917
1015
|
),
|
|
918
1016
|
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
919
1017
|
stream: true,
|
|
920
1018
|
stream_options: { include_usage: true }
|
|
921
1019
|
};
|
|
922
1020
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
923
|
-
const stream = await client.chat.completions.create(payload
|
|
924
|
-
|
|
1021
|
+
const stream = await client.chat.completions.create(payload, {
|
|
1022
|
+
signal: request.signal
|
|
1023
|
+
});
|
|
1024
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
1025
|
+
let finishReason;
|
|
925
1026
|
const collectedCitations = [];
|
|
926
1027
|
let citationIndex = 0;
|
|
927
1028
|
let usage;
|
|
928
1029
|
for await (const chunk of stream) {
|
|
929
1030
|
logProviderPayload("openai", "stream chunk", chunk, request.debug);
|
|
930
|
-
|
|
931
|
-
break;
|
|
932
|
-
}
|
|
1031
|
+
throwIfAborted(request.signal);
|
|
933
1032
|
const delta = chunk.choices[0]?.delta;
|
|
934
1033
|
const choice = chunk.choices[0];
|
|
935
1034
|
if (delta?.content) {
|
|
@@ -952,38 +1051,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
952
1051
|
}
|
|
953
1052
|
}
|
|
954
1053
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
};
|
|
969
|
-
}
|
|
970
|
-
const tcExtraContent = toolCall.extra_content;
|
|
971
|
-
currentToolCall = {
|
|
972
|
-
id: toolCall.id,
|
|
973
|
-
name: toolCall.function?.name || "",
|
|
974
|
-
arguments: toolCall.function?.arguments || "",
|
|
975
|
-
...tcExtraContent ? { extra_content: tcExtraContent } : {}
|
|
976
|
-
};
|
|
977
|
-
yield {
|
|
978
|
-
type: "action:start",
|
|
979
|
-
id: currentToolCall.id,
|
|
980
|
-
name: currentToolCall.name,
|
|
981
|
-
...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
|
|
982
|
-
};
|
|
983
|
-
} else if (currentToolCall && toolCall.function?.arguments) {
|
|
984
|
-
currentToolCall.arguments += toolCall.function.arguments;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
1054
|
+
for (const part of delta?.tool_calls ?? []) {
|
|
1055
|
+
const index = part.index ?? 0;
|
|
1056
|
+
const call = toolCalls.get(index) ?? {
|
|
1057
|
+
id: "",
|
|
1058
|
+
name: "",
|
|
1059
|
+
arguments: ""
|
|
1060
|
+
};
|
|
1061
|
+
if (part.id) call.id = part.id;
|
|
1062
|
+
if (part.function?.name) call.name += part.function.name;
|
|
1063
|
+
if (part.function?.arguments)
|
|
1064
|
+
call.arguments += part.function.arguments;
|
|
1065
|
+
if (part.extra_content) call.extra_content = part.extra_content;
|
|
1066
|
+
toolCalls.set(index, call);
|
|
987
1067
|
}
|
|
988
1068
|
if (chunk.usage) {
|
|
989
1069
|
usage = {
|
|
@@ -992,21 +1072,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
992
1072
|
total_tokens: chunk.usage.total_tokens
|
|
993
1073
|
};
|
|
994
1074
|
}
|
|
995
|
-
if (choice?.finish_reason)
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1075
|
+
if (choice?.finish_reason) finishReason = choice.finish_reason;
|
|
1076
|
+
}
|
|
1077
|
+
throwIfAborted(request.signal);
|
|
1078
|
+
if (!finishReason)
|
|
1079
|
+
throw new Error("OpenAI stream ended without a finish reason");
|
|
1080
|
+
if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
|
|
1081
|
+
throw new Error("OpenAI stream ended with incomplete tool calls");
|
|
1082
|
+
}
|
|
1083
|
+
for (const call of toolCalls.values()) {
|
|
1084
|
+
if (!call.id || !call.name)
|
|
1085
|
+
throw new Error("OpenAI stream contains an incomplete tool call");
|
|
1086
|
+
JSON.parse(call.arguments || "{}");
|
|
1087
|
+
}
|
|
1088
|
+
for (const call of toolCalls.values()) {
|
|
1089
|
+
yield {
|
|
1090
|
+
type: "action:start",
|
|
1091
|
+
id: call.id,
|
|
1092
|
+
name: call.name,
|
|
1093
|
+
...call.extra_content ? { extra_content: call.extra_content } : {}
|
|
1094
|
+
};
|
|
1095
|
+
yield { type: "action:args", id: call.id, args: call.arguments };
|
|
1096
|
+
yield { type: "action:end", id: call.id, name: call.name };
|
|
1010
1097
|
}
|
|
1011
1098
|
if (collectedCitations.length > 0) {
|
|
1012
1099
|
const uniqueCitations = deduplicateCitations(collectedCitations);
|
|
@@ -1015,26 +1102,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1015
1102
|
yield { type: "message:end" };
|
|
1016
1103
|
yield { type: "done", usage };
|
|
1017
1104
|
} catch (error) {
|
|
1018
|
-
yield {
|
|
1019
|
-
type: "error",
|
|
1020
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
1021
|
-
code: `${this.provider.toUpperCase()}_ERROR`
|
|
1022
|
-
};
|
|
1105
|
+
yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
|
|
1023
1106
|
}
|
|
1024
1107
|
}
|
|
1025
1108
|
async complete(request) {
|
|
1109
|
+
throwIfAborted(request.signal);
|
|
1026
1110
|
if (this.shouldUseResponsesApi(request)) {
|
|
1027
1111
|
return this.completeWithResponses(request);
|
|
1028
1112
|
}
|
|
1029
1113
|
const client = await this.getClient();
|
|
1030
1114
|
let messages;
|
|
1031
1115
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
1032
|
-
const sanitized = request.rawMessages
|
|
1033
|
-
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
|
|
1034
|
-
return { ...msg, content: null };
|
|
1035
|
-
}
|
|
1036
|
-
return msg;
|
|
1037
|
-
});
|
|
1116
|
+
const sanitized = this.formatRawMessages(request.rawMessages);
|
|
1038
1117
|
if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
|
|
1039
1118
|
messages = [
|
|
1040
1119
|
{ role: "system", content: request.systemPrompt },
|
|
@@ -1049,7 +1128,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1049
1128
|
request.systemPrompt
|
|
1050
1129
|
);
|
|
1051
1130
|
}
|
|
1052
|
-
const tools = request.
|
|
1131
|
+
const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
|
|
1132
|
+
type: "function",
|
|
1133
|
+
function: {
|
|
1134
|
+
name: tool.name,
|
|
1135
|
+
description: tool.description,
|
|
1136
|
+
parameters: normalizeObjectJsonSchema(
|
|
1137
|
+
tool.inputSchema
|
|
1138
|
+
)
|
|
1139
|
+
}
|
|
1140
|
+
})) : formatTools(request.actions ?? []);
|
|
1053
1141
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1054
1142
|
const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
|
|
1055
1143
|
type: "function",
|
|
@@ -1064,16 +1152,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1064
1152
|
tools: tools.length > 0 ? tools : void 0,
|
|
1065
1153
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
1066
1154
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
1067
|
-
...
|
|
1155
|
+
...buildOpenAIParameters(
|
|
1068
1156
|
modelIdForCompletePayload,
|
|
1069
1157
|
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1070
|
-
request.config?.temperature ?? this.config.temperature
|
|
1158
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1159
|
+
this.parameterOptions(request)
|
|
1071
1160
|
),
|
|
1072
1161
|
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
1073
1162
|
stream: false
|
|
1074
1163
|
};
|
|
1075
1164
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
1076
|
-
const response = await client.chat.completions.create(payload
|
|
1165
|
+
const response = await client.chat.completions.create(payload, {
|
|
1166
|
+
signal: request.signal
|
|
1167
|
+
});
|
|
1077
1168
|
logProviderPayload("openai", "response payload", response, request.debug);
|
|
1078
1169
|
const choice = response.choices?.[0];
|
|
1079
1170
|
const message = choice?.message;
|