@workglow/openai 0.3.24 → 0.3.26

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/ai.js CHANGED
@@ -49,6 +49,39 @@ function getModelName(model) {
49
49
  }
50
50
  return name;
51
51
  }
52
+ function getReasoningConfig(model) {
53
+ const reasoning = model?.provider_config?.reasoning;
54
+ if (!reasoning || reasoning.effort === undefined && reasoning.mode === undefined) {
55
+ return;
56
+ }
57
+ return reasoning;
58
+ }
59
+ function fnv1aHex(input) {
60
+ let hash = 2166136261;
61
+ for (let i = 0;i < input.length; i++) {
62
+ hash ^= input.charCodeAt(i);
63
+ hash = Math.imul(hash, 16777619);
64
+ }
65
+ return (hash >>> 0).toString(16).padStart(8, "0");
66
+ }
67
+ function resolvePromptCacheKey(model, params) {
68
+ const override = model?.provider_config?.prompt_cache_key;
69
+ if (override)
70
+ return override;
71
+ const material = JSON.stringify([
72
+ params.model ?? "",
73
+ params.instructions ?? "",
74
+ params.tools ?? null
75
+ ]);
76
+ return `wg-${fnv1aHex(material)}`;
77
+ }
78
+ function finalizeResponsesRequest(model, params) {
79
+ const reasoning = getReasoningConfig(model);
80
+ if (reasoning !== undefined)
81
+ params.reasoning = reasoning;
82
+ params.prompt_cache_key = resolvePromptCacheKey(model, params);
83
+ return params;
84
+ }
52
85
  // src/ai/common/OpenAI_Constants.ts
53
86
  var OPENAI = "OPENAI";
54
87
  // src/ai/common/OpenAI_ImageValidation.ts
@@ -101,6 +134,28 @@ var OpenAiModelSchema = {
101
134
  organization: {
102
135
  type: "string",
103
136
  description: "OpenAI organization ID (optional)."
137
+ },
138
+ prompt_cache_key: {
139
+ type: "string",
140
+ description: "Overrides the auto-derived Responses prompt_cache_key. Requests sharing a key share a cached prefix; leave unset to derive a stable key from the model + system instructions + tools.",
141
+ "x-ui-hidden": true
142
+ },
143
+ reasoning: {
144
+ type: "object",
145
+ description: "Reasoning controls for reasoning-capable models (e.g. the GPT-5.6 sol/terra/luna family), sent on the Responses API.",
146
+ properties: {
147
+ effort: {
148
+ type: "string",
149
+ enum: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
150
+ description: "Reasoning effort. Higher effort trades latency and cost for quality."
151
+ },
152
+ mode: {
153
+ type: "string",
154
+ enum: ["pro"],
155
+ description: "Set to 'pro' for the quality-first pro configuration on supported models."
156
+ }
157
+ },
158
+ additionalProperties: false
104
159
  }
105
160
  },
106
161
  required: ["model_name"],
@@ -133,6 +188,10 @@ import { filterLabeledModelsByQuery } from "@workglow/ai/provider-utils";
133
188
  var OPENAI_FALLBACK = [
134
189
  { label: "gpt-image-2", value: "gpt-image-2" },
135
190
  { label: "dall-e-3", value: "dall-e-3" },
191
+ { label: "gpt-5.6", value: "gpt-5.6" },
192
+ { label: "gpt-5.6-sol", value: "gpt-5.6-sol" },
193
+ { label: "gpt-5.6-terra", value: "gpt-5.6-terra" },
194
+ { label: "gpt-5.6-luna", value: "gpt-5.6-luna" },
136
195
  { label: "gpt-5.5", value: "gpt-5.5" },
137
196
  { label: "gpt-5.4-mini", value: "gpt-5.4-mini" },
138
197
  { label: "gpt-5.4-nano", value: "gpt-5.4-nano" },
@@ -550,37 +609,49 @@ var OpenAI_ModelInfo_Stream = async (input, model, _signal, emit) => {
550
609
  };
551
610
 
552
611
  // src/ai/common/OpenAI_StructuredGeneration.ts
612
+ import { isStrictCompatibleSchema } from "@workglow/ai/provider-utils";
553
613
  import { parsePartialJson } from "@workglow/util/worker";
554
614
  var OpenAI_StructuredGeneration_Stream = async (input, model, signal, emit, outputSchema) => {
555
615
  const client = await getClient(model);
556
616
  const modelName = getModelName(model);
557
617
  const schema = input.outputSchema ?? outputSchema;
558
- const stream = await client.chat.completions.create({
618
+ const params = {
559
619
  model: modelName,
560
- messages: [{ role: "user", content: input.prompt }],
561
- response_format: {
562
- type: "json_schema",
563
- json_schema: {
620
+ input: input.prompt,
621
+ text: {
622
+ format: {
623
+ type: "json_schema",
564
624
  name: "structured_output",
565
625
  schema,
566
- strict: true
626
+ strict: isStrictCompatibleSchema(schema)
567
627
  }
568
- },
569
- max_completion_tokens: input.maxTokens,
570
- temperature: input.temperature,
571
- stream: true
572
- }, { signal });
628
+ }
629
+ };
630
+ if (input.maxTokens !== undefined)
631
+ params.max_output_tokens = input.maxTokens;
632
+ if (input.temperature !== undefined)
633
+ params.temperature = input.temperature;
634
+ finalizeResponsesRequest(model, params);
635
+ const stream = await client.responses.create({ ...params, stream: true }, { signal });
573
636
  let accumulatedJson = "";
574
- for await (const chunk of stream) {
575
- const delta = chunk.choices[0]?.delta?.content ?? "";
576
- if (delta) {
577
- accumulatedJson += delta;
578
- const partial = parsePartialJson(accumulatedJson);
579
- if (partial !== undefined) {
580
- emit({ type: "object-delta", port: "object", objectDelta: partial });
637
+ let refusal = "";
638
+ for await (const event of stream) {
639
+ if (event.type === "response.output_text.delta") {
640
+ const delta = event.delta ?? "";
641
+ if (delta) {
642
+ accumulatedJson += delta;
643
+ const partial = parsePartialJson(accumulatedJson);
644
+ if (partial !== undefined) {
645
+ emit({ type: "object-delta", port: "object", objectDelta: partial });
646
+ }
581
647
  }
648
+ } else if (event.type === "response.refusal.delta") {
649
+ refusal += event.delta ?? "";
582
650
  }
583
651
  }
652
+ if (refusal) {
653
+ emit({ type: "refusal", refusal });
654
+ }
584
655
  let finalObject;
585
656
  try {
586
657
  finalObject = JSON.parse(accumulatedJson);
@@ -613,30 +684,34 @@ var OpenAI_TextEmbedding_Stream = async (input, model, signal, emit) => {
613
684
  };
614
685
 
615
686
  // src/ai/common/OpenAI_TextGeneration.ts
687
+ import { accumulateOpenAIResponsesStream, buildResponsesInput } from "@workglow/ai/provider-utils";
616
688
  import { toOpenAIMessages } from "@workglow/ai/worker";
617
689
  import { getLogger as getLogger2 } from "@workglow/util/worker";
618
- function buildChatParams(input, model) {
690
+ function buildResponsesParams(input, model) {
619
691
  const hasMessages = Array.isArray(input.messages) && input.messages.length > 0;
620
692
  const messages = hasMessages ? toOpenAIMessages({
621
693
  messages: input.messages,
622
694
  systemPrompt: input.systemPrompt,
623
695
  prompt: "",
624
696
  tools: []
625
- }) : [{ role: "user", content: input.prompt }];
697
+ }) : undefined;
698
+ const { input: responsesInput, instructions } = buildResponsesInput({
699
+ messages,
700
+ prompt: hasMessages ? undefined : input.prompt,
701
+ systemPrompt: hasMessages ? undefined : input.systemPrompt
702
+ });
626
703
  const params = {
627
704
  model: getModelName(model),
628
- messages
705
+ input: responsesInput
629
706
  };
707
+ if (instructions !== undefined)
708
+ params.instructions = instructions;
630
709
  if (input.maxTokens !== undefined)
631
- params.max_completion_tokens = input.maxTokens;
710
+ params.max_output_tokens = input.maxTokens;
632
711
  if (input.temperature !== undefined)
633
712
  params.temperature = input.temperature;
634
713
  if (input.topP !== undefined)
635
714
  params.top_p = input.topP;
636
- if (input.frequencyPenalty !== undefined)
637
- params.frequency_penalty = input.frequencyPenalty;
638
- if (input.presencePenalty !== undefined)
639
- params.presence_penalty = input.presencePenalty;
640
715
  return params;
641
716
  }
642
717
  var OpenAI_TextGeneration_Stream = async (input, model, signal, emit) => {
@@ -645,14 +720,9 @@ var OpenAI_TextGeneration_Stream = async (input, model, signal, emit) => {
645
720
  logger.time(timerLabel, { model: getModelName(model) });
646
721
  try {
647
722
  const client = await getClient(model);
648
- const params = buildChatParams(input, model);
649
- const stream = await client.chat.completions.create({ ...params, stream: true }, { signal });
650
- for await (const chunk of stream) {
651
- const delta = chunk.choices?.[0]?.delta?.content ?? "";
652
- if (delta) {
653
- emit({ type: "text-delta", port: "text", textDelta: delta });
654
- }
655
- }
723
+ const params = finalizeResponsesRequest(model, buildResponsesParams(input, model));
724
+ const stream = await client.responses.create({ ...params, stream: true }, { signal });
725
+ await accumulateOpenAIResponsesStream(stream, emit);
656
726
  emit({ type: "finish", data: {} });
657
727
  } finally {
658
728
  logger.timeEnd(timerLabel, { model: getModelName(model) });
@@ -660,70 +730,66 @@ var OpenAI_TextGeneration_Stream = async (input, model, signal, emit) => {
660
730
  };
661
731
 
662
732
  // src/ai/common/OpenAI_TextRewriter.ts
733
+ import { accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream2 } from "@workglow/ai/provider-utils";
663
734
  var OpenAI_TextRewriter_Stream = async (input, model, signal, emit) => {
664
735
  const client = await getClient(model);
665
- const modelName = getModelName(model);
666
- const stream = await client.chat.completions.create({
667
- model: modelName,
668
- messages: [
669
- { role: "system", content: input.prompt },
670
- { role: "user", content: input.text }
671
- ],
672
- stream: true
673
- }, { signal });
674
- for await (const chunk of stream) {
675
- const delta = chunk.choices[0]?.delta?.content ?? "";
676
- if (delta) {
677
- emit({ type: "text-delta", port: "text", textDelta: delta });
678
- }
679
- }
736
+ const params = {
737
+ model: getModelName(model),
738
+ instructions: input.prompt,
739
+ input: input.text
740
+ };
741
+ finalizeResponsesRequest(model, params);
742
+ const stream = await client.responses.create({ ...params, stream: true }, { signal });
743
+ await accumulateOpenAIResponsesStream2(stream, emit);
680
744
  emit({ type: "finish", data: {} });
681
745
  };
682
746
 
683
747
  // src/ai/common/OpenAI_TextSummary.ts
748
+ import { accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream3 } from "@workglow/ai/provider-utils";
684
749
  var OpenAI_TextSummary_Stream = async (input, model, signal, emit) => {
685
750
  const client = await getClient(model);
686
- const modelName = getModelName(model);
687
- const stream = await client.chat.completions.create({
688
- model: modelName,
689
- messages: [
690
- { role: "system", content: "Summarize the following text concisely." },
691
- { role: "user", content: input.text }
692
- ],
693
- stream: true
694
- }, { signal });
695
- for await (const chunk of stream) {
696
- const delta = chunk.choices[0]?.delta?.content ?? "";
697
- if (delta) {
698
- emit({ type: "text-delta", port: "text", textDelta: delta });
699
- }
700
- }
751
+ const params = {
752
+ model: getModelName(model),
753
+ instructions: "Summarize the following text concisely.",
754
+ input: input.text
755
+ };
756
+ finalizeResponsesRequest(model, params);
757
+ const stream = await client.responses.create({ ...params, stream: true }, { signal });
758
+ await accumulateOpenAIResponsesStream3(stream, emit);
701
759
  emit({ type: "finish", data: {} });
702
760
  };
703
761
 
704
762
  // src/ai/common/OpenAI_ToolCalling.ts
705
763
  import {
706
- accumulateOpenAIStream,
707
- buildOpenAITools,
708
- mapOpenAIToolChoice
764
+ accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream4,
765
+ buildResponsesInput as buildResponsesInput2,
766
+ buildResponsesTools,
767
+ mapResponsesToolChoice
709
768
  } from "@workglow/ai/provider-utils";
710
769
  import { filterValidToolCalls, toOpenAIMessages as toOpenAIMessages2 } from "@workglow/ai/worker";
711
770
  var OpenAI_ToolCalling_Stream = async (input, model, signal, emit) => {
712
771
  const client = await getClient(model);
713
772
  const modelName = getModelName(model);
714
- const tools = buildOpenAITools(input.tools);
715
- const messages = toOpenAIMessages2(input);
716
- const toolChoice = mapOpenAIToolChoice(input.toolChoice, true);
717
- const stream = await client.chat.completions.create({
773
+ const tools = buildResponsesTools(input.tools);
774
+ const { input: responsesInput, instructions } = buildResponsesInput2({
775
+ messages: toOpenAIMessages2(input)
776
+ });
777
+ const toolChoice = mapResponsesToolChoice(input.toolChoice);
778
+ const params = {
718
779
  model: modelName,
719
- messages,
720
- max_completion_tokens: input.maxTokens,
721
- temperature: input.temperature,
722
- stream: true,
780
+ input: responsesInput,
723
781
  tools,
724
782
  tool_choice: toolChoice
725
- }, { signal });
726
- await accumulateOpenAIStream(stream, (event) => {
783
+ };
784
+ if (instructions !== undefined)
785
+ params.instructions = instructions;
786
+ if (input.maxTokens !== undefined)
787
+ params.max_output_tokens = input.maxTokens;
788
+ if (input.temperature !== undefined)
789
+ params.temperature = input.temperature;
790
+ finalizeResponsesRequest(model, params);
791
+ const stream = await client.responses.create({ ...params, stream: true }, { signal });
792
+ await accumulateOpenAIResponsesStream4(stream, (event) => {
727
793
  if (event.type === "object-delta" && event.port === "toolCalls") {
728
794
  const validated = filterValidToolCalls(event.objectDelta, input.tools);
729
795
  if (validated.length > 0) {
@@ -758,7 +824,10 @@ var OPENAI_PREVIEW_TASKS = {
758
824
  var _testOnly = {
759
825
  OpenAiQueuedProvider,
760
826
  OPENAI_RUN_FN_SPECS,
761
- OPENAI_RUN_FNS
827
+ OPENAI_RUN_FNS,
828
+ getReasoningConfig,
829
+ resolvePromptCacheKey,
830
+ isStrictCompatibleSchema
762
831
  };
763
832
  export {
764
833
  registerOpenAiImageValidator,
@@ -772,4 +841,4 @@ export {
772
841
  OPENAI
773
842
  };
774
843
 
775
- //# debugId=5A2D4E4E752494BC64756E2164756E21
844
+ //# debugId=D935DEB21E5CE83764756E2164756E21