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