@demicodes/provider-openai-api 0.1.0 → 0.2.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/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Provider, ProviderModel, ProviderModelList } from "@demicodes/provider";
2
-
3
2
  //#region src/models.d.ts
4
3
  interface OpenAIApiModelOptions {
5
4
  id: string;
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { isAbortError, isRecord, normalizeBaseUrl, numberOrZero, parseJsonObject, parseJsonOrString, shortHash, stringOrNull } from "@demicodes/utils";
1
+ import { isAbortError, isRecord, normalizeBaseUrl, numberOrZero, parseJsonObject, parseJsonOrString, stringOrNull } from "@demicodes/utils";
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, withProviderId } from "@demicodes/provider";
5
+ import { authStatusFromKey, clampPromptCacheKey, defineProvider, httpRequestFailedEvent, normalizeErrorCode, providerErrorFromUnknown, toolResultContentToText, 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") {
@@ -331,10 +331,13 @@ function* mapOpenAIResponseEvent(event, state = newOpenAIResponseStreamState())
331
331
  }
332
332
  return;
333
333
  case "response.output_text.delta":
334
- if (typeof event.delta === "string") yield {
335
- type: "text_delta",
336
- text: event.delta
337
- };
334
+ if (typeof event.delta === "string") {
335
+ state.textDeltaSeen = true;
336
+ yield {
337
+ type: "text_delta",
338
+ text: event.delta
339
+ };
340
+ }
338
341
  return;
339
342
  case "response.function_call_arguments.delta": {
340
343
  const key = event.item_id ?? state.currentFunctionCall?.id;
@@ -363,11 +366,14 @@ function* mapOpenAIResponseEvent(event, state = newOpenAIResponseStreamState())
363
366
  if (state.currentReasoning === item) state.currentReasoning = null;
364
367
  state.reasoningDeltaSeen = false;
365
368
  } else if (isOpenAIResponseMessageItem(item)) {
366
- const text = openAIResponseMessageText(item);
367
- if (text) yield {
368
- type: "text_delta",
369
- text
370
- };
369
+ if (!state.textDeltaSeen) {
370
+ const text = openAIResponseMessageText(item);
371
+ if (text) yield {
372
+ type: "text_delta",
373
+ text
374
+ };
375
+ }
376
+ state.textDeltaSeen = false;
371
377
  } else if (isOpenAIResponseFunctionCallItem(item)) {
372
378
  const itemId = item.id ?? event.item_id;
373
379
  const callId = item.call_id ?? event.call_id;
@@ -583,9 +589,6 @@ function userContentToOpenAI(content) {
583
589
  if (parts.every((part) => part.type === "text")) return parts.map((part) => part.text).join("\n");
584
590
  return parts;
585
591
  }
586
- function toolResultContentToText(output) {
587
- return output.map((block) => block.type === "text" ? block.text : `[image:${block.source.mediaType}]`).join("\n");
588
- }
589
592
  function toolToOpenAITool(tool) {
590
593
  return {
591
594
  type: "function",
@@ -641,9 +644,7 @@ function inferenceItemToOpenAIResponseInput(item, index) {
641
644
  type: "output_text",
642
645
  text: item.text,
643
646
  annotations: []
644
- }],
645
- id: `msg_${shortHash(`${index}:${item.modelId}:${item.text}`)}`,
646
- status: "completed"
647
+ }]
647
648
  }];
648
649
  case "assistant_thinking": {
649
650
  const reasoning = parseOpenAIReasoningSignature(item.signature);
@@ -662,11 +663,24 @@ function inferenceItemToOpenAIResponseInput(item, index) {
662
663
  }
663
664
  case "tool_result": {
664
665
  const { callId } = splitOpenAIResponseToolUseId(item.toolUseId);
665
- return [{
666
+ const items = [{
666
667
  type: "function_call_output",
667
668
  call_id: callId,
668
669
  output: toolResultContentToText(item.output)
669
670
  }];
671
+ const images = item.output.filter((block) => block.type === "image");
672
+ if (images.length > 0) items.push({
673
+ role: "user",
674
+ content: [{
675
+ type: "input_text",
676
+ text: `[media returned by tool call ${callId}]`
677
+ }, ...images.map((block) => ({
678
+ type: "input_image",
679
+ image_url: `data:${block.source.mediaType};base64,${block.source.data}`,
680
+ detail: "auto"
681
+ }))]
682
+ });
683
+ return items;
670
684
  }
671
685
  }
672
686
  }
@@ -728,7 +742,15 @@ function parseOpenAIReasoningSignature(signature) {
728
742
  if (!signature) return null;
729
743
  try {
730
744
  const parsed = JSON.parse(signature);
731
- return isOpenAIResponseReasoningItem(parsed) ? parsed : null;
745
+ if (!isOpenAIResponseReasoningItem(parsed)) return null;
746
+ const { id, summary, content, encrypted_content } = parsed;
747
+ return {
748
+ type: "reasoning",
749
+ ...id ? { id } : {},
750
+ ...summary ? { summary } : {},
751
+ ...content ? { content } : {},
752
+ ...encrypted_content ? { encrypted_content } : {}
753
+ };
732
754
  } catch {
733
755
  return null;
734
756
  }
@@ -771,7 +793,8 @@ function newOpenAIResponseStreamState() {
771
793
  currentReasoning: null,
772
794
  currentFunctionCall: null,
773
795
  functionArguments: /* @__PURE__ */ new Map(),
774
- reasoningDeltaSeen: false
796
+ reasoningDeltaSeen: false,
797
+ textDeltaSeen: false
775
798
  };
776
799
  }
777
800
  function isOpenAIResponseReasoningItem(item) {
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.1.0",
4
+ "version": "0.2.1",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "exports": {
@@ -12,9 +12,9 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@demicodes/core": "workspace:*",
16
- "@demicodes/provider": "workspace:*",
17
- "@demicodes/utils": "workspace:*"
15
+ "@demicodes/core": "^0.2.1",
16
+ "@demicodes/provider": "^0.2.1",
17
+ "@demicodes/utils": "^0.2.1"
18
18
  },
19
19
  "license": "Apache-2.0",
20
20
  "main": "./dist/index.mjs",