@demicodes/provider-openai-api 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +2 -7
- package/dist/index.mjs +24 -41
- package/package.json +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Provider, ProviderModel, ProviderModelList } from "@demicodes/provider";
|
|
2
|
+
|
|
2
3
|
//#region src/models.d.ts
|
|
3
4
|
interface OpenAIApiModelOptions {
|
|
4
5
|
id: string;
|
|
@@ -25,13 +26,7 @@ interface OpenAIApiRequestOptions {
|
|
|
25
26
|
maxRetries?: number;
|
|
26
27
|
streamOptions?: Record<string, unknown> | null;
|
|
27
28
|
extraBody?: Record<string, unknown>;
|
|
28
|
-
|
|
29
|
-
* Emit `status: 'completed'` on replayed assistant messages. Gateways that validate
|
|
30
|
-
* input against the full Responses item schema require it — Volcengine Ark rejects the
|
|
31
|
-
* item with `missing input.status` — while relay bridges reject it as an unknown
|
|
32
|
-
* parameter, so it stays off unless the provider opts in.
|
|
33
|
-
*/
|
|
34
|
-
replayAssistantStatus?: boolean;
|
|
29
|
+
passBackReasoningContent?: boolean;
|
|
35
30
|
}
|
|
36
31
|
type OpenAIApiWireApi = 'responses' | 'chat-completions';
|
|
37
32
|
interface OpenAIApiProviderOptions {
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { isAbortError, isRecord, normalizeBaseUrl, numberOrZero, parseJsonObject
|
|
|
2
2
|
import { Buffer } from "node:buffer";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { zeroUsage } from "@demicodes/core";
|
|
5
|
-
import { authStatusFromKey, clampPromptCacheKey, defineProvider, httpRequestFailedEvent, normalizeErrorCode, providerErrorFromUnknown,
|
|
5
|
+
import { authStatusFromKey, clampPromptCacheKey, defineProvider, httpRequestFailedEvent, normalizeErrorCode, providerErrorFromUnknown, withProviderId } from "@demicodes/provider";
|
|
6
6
|
//#region src/models.ts
|
|
7
7
|
const SOURCE_FETCHED_AT = "1970-01-01T00:00:00.000Z";
|
|
8
8
|
function openAIApiDefaultModels(providerId = "openai") {
|
|
@@ -266,7 +266,7 @@ function createOpenAIApiProvider(options = {}) {
|
|
|
266
266
|
function buildOpenAIResponsesBody(request, options) {
|
|
267
267
|
const body = {
|
|
268
268
|
model: request.modelId,
|
|
269
|
-
input: request.items.flatMap((item, index) => inferenceItemToOpenAIResponseInput(item, index
|
|
269
|
+
input: request.items.flatMap((item, index) => inferenceItemToOpenAIResponseInput(item, index)),
|
|
270
270
|
stream: true,
|
|
271
271
|
store: false,
|
|
272
272
|
include: ["reasoning.encrypted_content"],
|
|
@@ -421,7 +421,7 @@ function* mapOpenAIResponseEvent(event, state = newOpenAIResponseStreamState())
|
|
|
421
421
|
function buildOpenAIChatCompletionsBody(request, options) {
|
|
422
422
|
const body = {
|
|
423
423
|
model: request.modelId,
|
|
424
|
-
messages: inferenceItemsToOpenAIMessages(request.systemPrompt, request.items),
|
|
424
|
+
messages: inferenceItemsToOpenAIMessages(request.systemPrompt, request.items, options?.passBackReasoningContent === true),
|
|
425
425
|
stream: true
|
|
426
426
|
};
|
|
427
427
|
if (request.tools.length > 0) {
|
|
@@ -498,15 +498,18 @@ async function* mapOpenAIChatCompletionStream(events, signal) {
|
|
|
498
498
|
usage
|
|
499
499
|
};
|
|
500
500
|
}
|
|
501
|
-
function inferenceItemsToOpenAIMessages(systemPrompt, items) {
|
|
501
|
+
function inferenceItemsToOpenAIMessages(systemPrompt, items, passBackReasoningContent = false) {
|
|
502
502
|
const messages = [];
|
|
503
503
|
let assistant = null;
|
|
504
|
+
let pendingThinking = "";
|
|
504
505
|
const flushAssistant = () => {
|
|
506
|
+
pendingThinking = "";
|
|
505
507
|
if (!assistant) return;
|
|
506
508
|
messages.push({
|
|
507
509
|
role: "assistant",
|
|
508
510
|
content: assistant.content || null,
|
|
509
|
-
...assistant.toolCalls.length > 0 ? { tool_calls: assistant.toolCalls } : {}
|
|
511
|
+
...assistant.toolCalls.length > 0 ? { tool_calls: assistant.toolCalls } : {},
|
|
512
|
+
...passBackReasoningContent && (assistant.thinking || assistant.toolCalls.length > 0) ? { reasoning_content: assistant.thinking } : {}
|
|
510
513
|
});
|
|
511
514
|
assistant = null;
|
|
512
515
|
};
|
|
@@ -526,15 +529,19 @@ function inferenceItemsToOpenAIMessages(systemPrompt, items) {
|
|
|
526
529
|
case "assistant_text":
|
|
527
530
|
assistant ??= {
|
|
528
531
|
content: "",
|
|
529
|
-
toolCalls: []
|
|
532
|
+
toolCalls: [],
|
|
533
|
+
thinking: pendingThinking
|
|
530
534
|
};
|
|
535
|
+
pendingThinking = "";
|
|
531
536
|
assistant.content += item.text;
|
|
532
537
|
break;
|
|
533
538
|
case "tool_use":
|
|
534
539
|
assistant ??= {
|
|
535
540
|
content: "",
|
|
536
|
-
toolCalls: []
|
|
541
|
+
toolCalls: [],
|
|
542
|
+
thinking: pendingThinking
|
|
537
543
|
};
|
|
544
|
+
pendingThinking = "";
|
|
538
545
|
assistant.toolCalls.push({
|
|
539
546
|
id: item.toolUseId,
|
|
540
547
|
type: "function",
|
|
@@ -544,30 +551,18 @@ function inferenceItemsToOpenAIMessages(systemPrompt, items) {
|
|
|
544
551
|
}
|
|
545
552
|
});
|
|
546
553
|
break;
|
|
547
|
-
case "tool_result":
|
|
554
|
+
case "tool_result":
|
|
548
555
|
flushAssistant();
|
|
549
556
|
messages.push({
|
|
550
557
|
role: "tool",
|
|
551
558
|
tool_call_id: item.toolUseId,
|
|
552
559
|
content: toolResultContentToText(item.output)
|
|
553
560
|
});
|
|
554
|
-
const media = item.output.filter((block) => block.type !== "text");
|
|
555
|
-
if (media.length > 0) messages.push({
|
|
556
|
-
role: "user",
|
|
557
|
-
content: [{
|
|
558
|
-
type: "text",
|
|
559
|
-
text: `[media returned by tool call ${item.toolUseId}]`
|
|
560
|
-
}, ...media.map((block) => ({
|
|
561
|
-
type: "image_url",
|
|
562
|
-
image_url: {
|
|
563
|
-
url: `data:${block.source.mediaType};base64,${block.source.data}`,
|
|
564
|
-
detail: "auto"
|
|
565
|
-
}
|
|
566
|
-
}))]
|
|
567
|
-
});
|
|
568
561
|
break;
|
|
569
|
-
}
|
|
570
562
|
case "assistant_thinking":
|
|
563
|
+
if (passBackReasoningContent) if (assistant) assistant.thinking += item.text;
|
|
564
|
+
else pendingThinking += item.text;
|
|
565
|
+
break;
|
|
571
566
|
case "assistant_redacted_thinking": break;
|
|
572
567
|
}
|
|
573
568
|
flushAssistant();
|
|
@@ -604,6 +599,9 @@ function userContentToOpenAI(content) {
|
|
|
604
599
|
if (parts.every((part) => part.type === "text")) return parts.map((part) => part.text).join("\n");
|
|
605
600
|
return parts;
|
|
606
601
|
}
|
|
602
|
+
function toolResultContentToText(output) {
|
|
603
|
+
return output.map((block) => block.type === "text" ? block.text : `[image:${block.source.mediaType}]`).join("\n");
|
|
604
|
+
}
|
|
607
605
|
function toolToOpenAITool(tool) {
|
|
608
606
|
return {
|
|
609
607
|
type: "function",
|
|
@@ -645,7 +643,7 @@ function* flushOpenAIToolCalls(toolCalls) {
|
|
|
645
643
|
}
|
|
646
644
|
toolCalls.clear();
|
|
647
645
|
}
|
|
648
|
-
function inferenceItemToOpenAIResponseInput(item, index
|
|
646
|
+
function inferenceItemToOpenAIResponseInput(item, index) {
|
|
649
647
|
switch (item.type) {
|
|
650
648
|
case "user_message":
|
|
651
649
|
case "user_steer": return [{
|
|
@@ -655,7 +653,6 @@ function inferenceItemToOpenAIResponseInput(item, index, options) {
|
|
|
655
653
|
case "assistant_text": return [{
|
|
656
654
|
type: "message",
|
|
657
655
|
role: "assistant",
|
|
658
|
-
...options?.replayAssistantStatus ? { status: "completed" } : {},
|
|
659
656
|
content: [{
|
|
660
657
|
type: "output_text",
|
|
661
658
|
text: item.text,
|
|
@@ -679,24 +676,11 @@ function inferenceItemToOpenAIResponseInput(item, index, options) {
|
|
|
679
676
|
}
|
|
680
677
|
case "tool_result": {
|
|
681
678
|
const { callId } = splitOpenAIResponseToolUseId(item.toolUseId);
|
|
682
|
-
|
|
679
|
+
return [{
|
|
683
680
|
type: "function_call_output",
|
|
684
681
|
call_id: callId,
|
|
685
682
|
output: toolResultContentToText(item.output)
|
|
686
683
|
}];
|
|
687
|
-
const images = item.output.filter((block) => block.type !== "text");
|
|
688
|
-
if (images.length > 0) items.push({
|
|
689
|
-
role: "user",
|
|
690
|
-
content: [{
|
|
691
|
-
type: "input_text",
|
|
692
|
-
text: `[media returned by tool call ${callId}]`
|
|
693
|
-
}, ...images.map((block) => ({
|
|
694
|
-
type: "input_image",
|
|
695
|
-
image_url: `data:${block.source.mediaType};base64,${block.source.data}`,
|
|
696
|
-
detail: "auto"
|
|
697
|
-
}))]
|
|
698
|
-
});
|
|
699
|
-
return items;
|
|
700
684
|
}
|
|
701
685
|
}
|
|
702
686
|
}
|
|
@@ -742,10 +726,9 @@ function thinkingToOpenAIReasoning(thinking) {
|
|
|
742
726
|
summary: "auto"
|
|
743
727
|
};
|
|
744
728
|
if (thinking.effort === "none") return { effort: "none" };
|
|
745
|
-
if (thinking.summary === "off") return { effort: thinking.effort };
|
|
746
729
|
return {
|
|
747
730
|
effort: thinking.effort,
|
|
748
|
-
summary: thinking.summary
|
|
731
|
+
summary: thinking.summary && thinking.summary !== "off" ? thinking.summary : "auto"
|
|
749
732
|
};
|
|
750
733
|
}
|
|
751
734
|
function splitOpenAIResponseToolUseId(toolUseId) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@demicodes/provider-openai-api",
|
|
3
3
|
"description": "OpenAI API provider adapter for Demi.",
|
|
4
|
-
"version": "0.10.
|
|
4
|
+
"version": "0.10.4",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@demicodes/core": "^0.10.
|
|
15
|
-
"@demicodes/provider": "^0.10.
|
|
16
|
-
"@demicodes/utils": "^0.10.
|
|
14
|
+
"@demicodes/core": "^0.10.3",
|
|
15
|
+
"@demicodes/provider": "^0.10.3",
|
|
16
|
+
"@demicodes/utils": "^0.10.3"
|
|
17
17
|
},
|
|
18
18
|
"license": "Apache-2.0",
|
|
19
19
|
"main": "./dist/index.mjs",
|