@demicodes/provider-openai-api 0.10.2 → 0.10.3

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 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, toolResultContentToText, withProviderId } from "@demicodes/provider";
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, options)),
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 ? { 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, options) {
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
- const items = [{
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 ?? "auto"
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.2",
4
+ "version": "0.10.3",
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.2",
15
- "@demicodes/provider": "^0.10.2",
16
- "@demicodes/utils": "^0.10.2"
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",