@workglow/openai 0.3.38 → 0.3.39

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.
Files changed (40) hide show
  1. package/dist/ai/OpenAiProvider.d.ts +2 -64
  2. package/dist/ai/OpenAiProvider.d.ts.map +1 -1
  3. package/dist/ai/OpenAiQueuedProvider.d.ts +2 -64
  4. package/dist/ai/OpenAiQueuedProvider.d.ts.map +1 -1
  5. package/dist/ai/common/OpenAI_CacheCheckpoint.d.ts +48 -0
  6. package/dist/ai/common/OpenAI_CacheCheckpoint.d.ts.map +1 -0
  7. package/dist/ai/common/OpenAI_Capabilities.d.ts +1 -1
  8. package/dist/ai/common/OpenAI_Capabilities.d.ts.map +1 -1
  9. package/dist/ai/common/OpenAI_CapabilitySets.d.ts +2 -1
  10. package/dist/ai/common/OpenAI_CapabilitySets.d.ts.map +1 -1
  11. package/dist/ai/common/OpenAI_Client.d.ts +34 -8
  12. package/dist/ai/common/OpenAI_Client.d.ts.map +1 -1
  13. package/dist/ai/common/OpenAI_JobRunFns.browser.d.ts.map +1 -1
  14. package/dist/ai/common/OpenAI_JobRunFns.d.ts.map +1 -1
  15. package/dist/ai/common/OpenAI_ModelInfo.d.ts +4 -3
  16. package/dist/ai/common/OpenAI_ModelInfo.d.ts.map +1 -1
  17. package/dist/ai/common/OpenAI_ModelSchema.d.ts +70 -3
  18. package/dist/ai/common/OpenAI_ModelSchema.d.ts.map +1 -1
  19. package/dist/ai/common/OpenAI_StructuredGeneration.d.ts.map +1 -1
  20. package/dist/ai/common/OpenAI_TextEmbedding.d.ts.map +1 -1
  21. package/dist/ai/common/OpenAI_TextGeneration.d.ts.map +1 -1
  22. package/dist/ai/common/OpenAI_TextRewriter.d.ts.map +1 -1
  23. package/dist/ai/common/OpenAI_TextSummary.d.ts.map +1 -1
  24. package/dist/ai/common/OpenAI_ToolCalling.d.ts +3 -2
  25. package/dist/ai/common/OpenAI_ToolCalling.d.ts.map +1 -1
  26. package/dist/ai/index.d.ts +5 -24
  27. package/dist/ai/index.d.ts.map +1 -1
  28. package/dist/ai/runtime.browser.d.ts +1 -0
  29. package/dist/ai/runtime.browser.d.ts.map +1 -1
  30. package/dist/ai/runtime.d.ts +1 -0
  31. package/dist/ai/runtime.d.ts.map +1 -1
  32. package/dist/ai-runtime.browser.js +238 -74
  33. package/dist/ai-runtime.browser.js.map +16 -15
  34. package/dist/ai-runtime.js +235 -69
  35. package/dist/ai-runtime.js.map +15 -14
  36. package/dist/ai.browser.js +31 -5
  37. package/dist/ai.browser.js.map +6 -6
  38. package/dist/ai.js +235 -72
  39. package/dist/ai.js.map +17 -16
  40. package/package.json +13 -12
@@ -2,16 +2,16 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/ai/common/OpenAI_Client.ts", "../src/ai/common/OpenAI_Constants.ts", "../src/ai/common/OpenAI_ModelSchema.ts", "../src/ai/registerOpenAi.ts", "../src/ai/OpenAiQueuedProvider.ts", "../src/ai/common/OpenAI_CapabilitySets.ts", "../src/ai/common/OpenAI_Capabilities.ts", "../src/ai/common/OpenAI_ImageValidation.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { isBrowserLike, resolveApiKey, validateProviderBaseUrl } from \"@workglow/ai/provider-utils\";\nimport type { OpenAiModelConfig } from \"./OpenAI_ModelSchema\";\n\n/**\n * Hostnames (or hostname suffixes) accepted for OpenAI `base_url` without\n * the explicit `trustedBaseUrl` opt-out. Includes Azure OpenAI tenants.\n */\nexport const OPENAI_ALLOWED_HOSTS: readonly string[] = [\"api.openai.com\", \".openai.azure.com\"];\n\ntype OpenAIClientClass = new (config: any) => any;\n\nlet _loadPromise: Promise<OpenAIClientClass> | undefined;\n\n// NOTE: we do not want to de-dup this in the provider-utils, vite wants direct import with string literals.\nexport async function loadOpenAISDK(): Promise<OpenAIClientClass> {\n _loadPromise ??= import(/* @vite-ignore */ \"openai\")\n\n .then((mod) => mod.default as OpenAIClientClass)\n .catch(() => {\n _loadPromise = undefined;\n throw new Error(\"openai is required for OpenAI tasks. Install it with: bun add openai\");\n });\n return _loadPromise;\n}\n\ninterface ResolvedProviderConfig {\n readonly credential_key?: string;\n readonly api_key?: string;\n readonly model_name?: string;\n readonly base_url?: string;\n readonly organization?: string;\n readonly prompt_cache_key?: string;\n readonly reasoning?: { readonly effort?: string; readonly mode?: string };\n /**\n * When `true`, accept the `base_url` even if its hostname is not in\n * {@link OPENAI_ALLOWED_HOSTS}. Use only for known-good custom enterprise\n * gateways. The URL still has to parse and use a safe scheme.\n */\n readonly trustedBaseUrl?: boolean;\n}\n\nexport async function getClient(model: OpenAiModelConfig | undefined) {\n const OpenAI = await loadOpenAISDK();\n const config = model?.provider_config as ResolvedProviderConfig | undefined;\n const apiKey = resolveApiKey({\n config,\n envVar: \"OPENAI_API_KEY\",\n providerLabel: \"OpenAI\",\n });\n // Throw before SDK construction on a rejected base_url so the API key is\n // never sent to an unvalidated host.\n const baseURL = validateProviderBaseUrl(config?.base_url, {\n vendor: \"openai\",\n allowHosts: OPENAI_ALLOWED_HOSTS,\n trustedBaseUrl: config?.trustedBaseUrl,\n providerLabel: \"OpenAI\",\n });\n try {\n return new OpenAI({\n apiKey,\n baseURL,\n organization: config?.organization || undefined,\n dangerouslyAllowBrowser: isBrowserLike(),\n });\n } catch (err) {\n throw new Error(\n `Failed to create OpenAI client: ${err instanceof Error ? err.message : \"unknown error\"}`\n );\n }\n}\n\nexport function getModelName(model: OpenAiModelConfig | undefined): string {\n const name = model?.provider_config?.model_name;\n if (!name) {\n throw new Error(\"Missing model name in provider_config.model_name.\");\n }\n return name;\n}\n\n/**\n * Resolves the configured `reasoning` object for reasoning-capable models\n * (the GPT-5.6 sol/terra/luna family and the o-series), sent verbatim as the\n * Responses `reasoning` parameter. Returns `undefined` when unset so\n * non-reasoning models and callers that don't opt in send no reasoning field.\n */\nexport function getReasoningConfig(\n model: OpenAiModelConfig | undefined\n): { effort?: string; mode?: string } | undefined {\n const reasoning = (model?.provider_config as ResolvedProviderConfig | undefined)?.reasoning;\n if (!reasoning || (reasoning.effort === undefined && reasoning.mode === undefined)) {\n return undefined;\n }\n return reasoning;\n}\n\n/** Deterministic 32-bit FNV-1a hash → 8-char hex. Worker-safe (no crypto import). */\nfunction fnv1aHex(input: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Resolves the Responses `prompt_cache_key`. Uses an explicit\n * `provider_config.prompt_cache_key` override when set, otherwise derives a\n * stable key from the request's cache-relevant prefix (model + system\n * instructions + tools) so requests sharing that prefix converge on one key and\n * hit the cache. GPT-5.6 bills cache writes, so a stable key (not a random one)\n * is the cost-correct default.\n */\nexport function resolvePromptCacheKey(\n model: OpenAiModelConfig | undefined,\n params: { model?: unknown; instructions?: unknown; tools?: unknown }\n): string {\n const override = (model?.provider_config as ResolvedProviderConfig | undefined)?.prompt_cache_key;\n if (override) return override;\n const material = JSON.stringify([\n params.model ?? \"\",\n params.instructions ?? \"\",\n params.tools ?? null,\n ]);\n return `wg-${fnv1aHex(material)}`;\n}\n\n/**\n * Applies the per-request Responses fields common to every OpenAI text run-fn:\n * the model's `reasoning` config (when set) and a stable `prompt_cache_key`.\n * Mutates and returns `params` so callers can inline it into the create call.\n * Call this last, after model/instructions/tools are populated, so the cache\n * key sees the full prefix.\n */\nexport function finalizeResponsesRequest(\n model: OpenAiModelConfig | undefined,\n params: Record<string, unknown>\n): Record<string, unknown> {\n const reasoning = getReasoningConfig(model);\n if (reasoning !== undefined) params.reasoning = reasoning;\n params.prompt_cache_key = resolvePromptCacheKey(model, params);\n return params;\n}\n",
5
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { isModelEffort, type ModelEffort } from \"@workglow/ai\";\nimport { isBrowserLike, resolveApiKey, validateProviderBaseUrl } from \"@workglow/ai/provider-utils\";\nimport type { OpenAiModelConfig } from \"./OpenAI_ModelSchema\";\n\n/** Maps coarse {@link ModelEffort} to OpenAI Responses `reasoning.effort`. */\nconst EFFORT_TO_OPENAI: Record<ModelEffort, string> = {\n none: \"none\",\n low: \"low\",\n medium: \"medium\",\n high: \"high\",\n extra: \"xhigh\",\n ultra: \"max\",\n};\n\n/**\n * Hostnames (or hostname suffixes) accepted for OpenAI `base_url` without\n * the explicit `trustedBaseUrl` opt-out. Includes Azure OpenAI tenants.\n */\nexport const OPENAI_ALLOWED_HOSTS: readonly string[] = [\"api.openai.com\", \".openai.azure.com\"];\n\ntype OpenAIClientClass = new (config: any) => any;\n\nlet _loadPromise: Promise<OpenAIClientClass> | undefined;\n\n// NOTE: we do not want to de-dup this in the provider-utils, vite wants direct import with string literals.\nexport async function loadOpenAISDK(): Promise<OpenAIClientClass> {\n _loadPromise ??= import(/* @vite-ignore */ \"openai\")\n\n .then((mod) => mod.default as OpenAIClientClass)\n .catch(() => {\n _loadPromise = undefined;\n throw new Error(\"openai is required for OpenAI tasks. Install it with: bun add openai\");\n });\n return _loadPromise;\n}\n\ninterface ResolvedProviderConfig {\n readonly credential_key?: string;\n readonly api_key?: string;\n readonly model_name?: string;\n readonly base_url?: string;\n readonly organization?: string;\n readonly prompt_cache_key?: string;\n readonly reasoning?: { readonly effort?: string; readonly mode?: string };\n /**\n * When `true`, accept the `base_url` even if its hostname is not in\n * {@link OPENAI_ALLOWED_HOSTS}. Use only for known-good custom enterprise\n * gateways. The URL still has to parse and use a safe scheme.\n */\n readonly trustedBaseUrl?: boolean;\n}\n\nlet _testClient: unknown;\n\n/**\n * Override the client returned by {@link getClient} so runtime tests can\n * capture the requests the OpenAI run-fns build without a live SDK, API key,\n * or network call. Pass `undefined` to restore normal SDK-backed creation.\n * This lives in the runtime module (not a `vi.mock` of `openai`) so it works\n * identically whether the provider resolves to `src` or the bundled `dist`,\n * and is immune to duplicate SDK copies across the workspace defeating\n * module-level mocks.\n */\nfunction setOpenAIClientForTests(client: unknown): void {\n _testClient = client;\n}\n\n/**\n * @internal Symbols exported only for use by `@workglow/test`. Not part of the\n * stable public API. Surfaced on the `ai-runtime` barrel (via `export *`) and\n * merged into the `/ai` barrel's `_testOnly`.\n */\nexport const _testOnly = {\n setOpenAIClientForTests,\n} as const;\n\nexport async function getClient(model: OpenAiModelConfig | undefined) {\n if (_testClient) return _testClient as InstanceType<OpenAIClientClass>;\n const OpenAI = await loadOpenAISDK();\n const config = model?.provider_config as ResolvedProviderConfig | undefined;\n const apiKey = resolveApiKey({\n config,\n envVar: \"OPENAI_API_KEY\",\n providerLabel: \"OpenAI\",\n });\n // Throw before SDK construction on a rejected base_url so the API key is\n // never sent to an unvalidated host.\n const baseURL = validateProviderBaseUrl(config?.base_url, {\n vendor: \"openai\",\n allowHosts: OPENAI_ALLOWED_HOSTS,\n trustedBaseUrl: config?.trustedBaseUrl,\n providerLabel: \"OpenAI\",\n });\n try {\n return new OpenAI({\n apiKey,\n baseURL,\n organization: config?.organization || undefined,\n dangerouslyAllowBrowser: isBrowserLike(),\n });\n } catch (err) {\n throw new Error(\n `Failed to create OpenAI client: ${err instanceof Error ? err.message : \"unknown error\"}`\n );\n }\n}\n\nexport function getModelName(model: OpenAiModelConfig | undefined): string {\n const name = model?.provider_config?.model_name;\n if (!name) {\n throw new Error(\"Missing model name in provider_config.model_name.\");\n }\n return name;\n}\n\n/**\n * Resolves the `reasoning` object for reasoning-capable models (GPT-5.6\n * sol/terra/luna and the o-series). Native `provider_config.reasoning` wins;\n * otherwise map `model.effort`. Returns `undefined` when neither is set.\n */\nexport function getReasoningConfig(\n model: OpenAiModelConfig | undefined\n): { effort?: string; mode?: string } | undefined {\n const reasoning = (model?.provider_config as ResolvedProviderConfig | undefined)?.reasoning;\n if (reasoning && (reasoning.effort !== undefined || reasoning.mode !== undefined)) {\n return reasoning;\n }\n if (isModelEffort(model?.effort)) {\n return { effort: EFFORT_TO_OPENAI[model.effort] };\n }\n return undefined;\n}\n\n/** Deterministic 32-bit FNV-1a hash → 8-char hex. Worker-safe (no crypto import). */\nfunction fnv1aHex(input: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Resolves the Responses `prompt_cache_key`. Uses an explicit\n * `provider_config.prompt_cache_key` override when set, otherwise derives a\n * stable key from the request's cache-relevant prefix (model + system\n * instructions + tools) so requests sharing that prefix converge on one key and\n * hit the cache. GPT-5.6 bills cache writes, so a stable key (not a random one)\n * is the cost-correct default.\n */\nexport function resolvePromptCacheKey(\n model: OpenAiModelConfig | undefined,\n params: { model?: unknown; instructions?: unknown; tools?: unknown }\n): string {\n const override = (model?.provider_config as ResolvedProviderConfig | undefined)?.prompt_cache_key;\n if (override) return override;\n const material = JSON.stringify([\n params.model ?? \"\",\n params.instructions ?? \"\",\n params.tools ?? null,\n ]);\n return `wg-${fnv1aHex(material)}`;\n}\n\n/**\n * Applies the per-request Responses fields common to every OpenAI text run-fn:\n * the model's `reasoning` config and a stable `prompt_cache_key`. Mutates and\n * returns `params` so callers can inline it into the create call. Call this\n * last, after model/instructions/tools/temperature are populated, so the cache\n * key sees the full prefix and the reasoning default can see the temperature.\n *\n * When the caller pinned a `temperature` but expressed no reasoning preference,\n * reasoning is forced off. The two are not independently selectable on the\n * reasoning families: `gpt-5.6-luna` answers `temperature` alone with\n * `400 Unsupported parameter: 'temperature' is not supported with this model`,\n * yet accepts `{reasoning: {effort: \"none\"}, temperature: 0}`. A caller asking\n * for a specific temperature is asking for controlled sampling, so honouring\n * that request — rather than failing it — is the useful reading. An explicit\n * `reasoning` in the model config always wins.\n */\nexport function finalizeResponsesRequest(\n model: OpenAiModelConfig | undefined,\n params: Record<string, unknown>\n): Record<string, unknown> {\n const reasoning = getReasoningConfig(model);\n if (reasoning !== undefined) params.reasoning = reasoning;\n else if (params.temperature !== undefined) params.reasoning = { effort: \"none\" };\n params.prompt_cache_key = resolvePromptCacheKey(model, params);\n return params;\n}\n",
6
6
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport const OPENAI = \"OPENAI\";\n",
7
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { ModelConfigSchema, ModelRecordSchema } from \"@workglow/ai/worker\";\nimport { DataPortSchemaObject, FromSchema } from \"@workglow/util/worker\";\nimport { OPENAI } from \"./OpenAI_Constants\";\n\nexport const OpenAiModelSchema = {\n type: \"object\",\n properties: {\n provider: {\n const: OPENAI,\n description: \"Discriminator: OpenAI cloud provider.\",\n },\n provider_config: {\n type: \"object\",\n description: \"OpenAI-specific configuration.\",\n properties: {\n model_name: {\n type: \"string\",\n description: \"The OpenAI model identifier (e.g., 'gpt-4o', 'text-embedding-3-small').\",\n },\n credential_key: {\n type: \"string\",\n format: \"credential\",\n description: \"Key to look up in the credential store for the API key.\",\n \"x-ui-hidden\": true,\n },\n base_url: {\n type: \"string\",\n description: \"Base URL for the OpenAI API. Useful for Azure OpenAI or proxy servers.\",\n default: \"https://api.openai.com/v1\",\n },\n trustedBaseUrl: {\n type: \"boolean\",\n description:\n \"When true, accept a base_url whose hostname is not in the built-in allow-list. Use only for known-good custom enterprise gateways — otherwise an attacker can exfiltrate the API key by pointing base_url at their own server.\",\n default: false,\n \"x-ui-hidden\": true,\n },\n organization: {\n type: \"string\",\n description: \"OpenAI organization ID (optional).\",\n },\n prompt_cache_key: {\n type: \"string\",\n description:\n \"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.\",\n \"x-ui-hidden\": true,\n },\n reasoning: {\n type: \"object\",\n description:\n \"Reasoning controls for reasoning-capable models (e.g. the GPT-5.6 sol/terra/luna family), sent on the Responses API.\",\n properties: {\n effort: {\n type: \"string\",\n enum: [\"none\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"],\n description: \"Reasoning effort. Higher effort trades latency and cost for quality.\",\n },\n mode: {\n type: \"string\",\n enum: [\"pro\"],\n description:\n \"Set to 'pro' for the quality-first pro configuration on supported models.\",\n },\n },\n additionalProperties: false,\n },\n },\n required: [\"model_name\"],\n additionalProperties: false,\n },\n },\n required: [\"provider\", \"provider_config\"],\n additionalProperties: true,\n} as const satisfies DataPortSchemaObject;\n\nexport const OpenAiModelRecordSchema = {\n type: \"object\",\n properties: {\n ...ModelRecordSchema.properties,\n ...OpenAiModelSchema.properties,\n },\n required: [...ModelRecordSchema.required, ...OpenAiModelSchema.required],\n additionalProperties: false,\n} as const satisfies DataPortSchemaObject;\n\nexport type OpenAiModelRecord = FromSchema<typeof OpenAiModelRecordSchema>;\n\nexport const OpenAiModelConfigSchema = {\n type: \"object\",\n properties: {\n ...ModelConfigSchema.properties,\n ...OpenAiModelSchema.properties,\n },\n required: [...ModelConfigSchema.required, ...OpenAiModelSchema.required],\n additionalProperties: false,\n} as const satisfies DataPortSchemaObject;\n\nexport type OpenAiModelConfig = FromSchema<typeof OpenAiModelConfigSchema>;\n",
7
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { WithModelPricing } from \"@workglow/ai/worker\";\nimport { ModelConfigSchema, ModelRecordSchema } from \"@workglow/ai/worker\";\nimport type { DataPortSchemaObject, FromSchema } from \"@workglow/util/worker\";\nimport { OPENAI } from \"./OpenAI_Constants\";\n\nexport const OpenAiModelSchema = {\n type: \"object\",\n properties: {\n provider: {\n const: OPENAI,\n description: \"Discriminator: OpenAI cloud provider.\",\n },\n provider_config: {\n type: \"object\",\n description: \"OpenAI-specific configuration.\",\n properties: {\n model_name: {\n type: \"string\",\n description: \"The OpenAI model identifier (e.g., 'gpt-4o', 'text-embedding-3-small').\",\n },\n credential_key: {\n type: \"string\",\n format: \"credential\",\n description: \"Key to look up in the credential store for the API key.\",\n \"x-ui-hidden\": true,\n },\n base_url: {\n type: \"string\",\n description: \"Base URL for the OpenAI API. Useful for Azure OpenAI or proxy servers.\",\n default: \"https://api.openai.com/v1\",\n },\n trustedBaseUrl: {\n type: \"boolean\",\n description:\n \"When true, accept a base_url whose hostname is not in the built-in allow-list. Use only for known-good custom enterprise gateways — otherwise an attacker can exfiltrate the API key by pointing base_url at their own server.\",\n default: false,\n \"x-ui-hidden\": true,\n },\n organization: {\n type: \"string\",\n description: \"OpenAI organization ID (optional).\",\n },\n prompt_cache_key: {\n type: \"string\",\n description:\n \"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.\",\n \"x-ui-hidden\": true,\n },\n reasoning: {\n type: \"object\",\n description:\n \"Reasoning controls for reasoning-capable models (e.g. the GPT-5.6 sol/terra/luna family), sent on the Responses API.\",\n properties: {\n effort: {\n type: \"string\",\n enum: [\"none\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"],\n description: \"Reasoning effort. Higher effort trades latency and cost for quality.\",\n },\n mode: {\n type: \"string\",\n enum: [\"pro\"],\n description:\n \"Set to 'pro' for the quality-first pro configuration on supported models.\",\n },\n },\n additionalProperties: false,\n },\n },\n required: [\"model_name\"],\n additionalProperties: false,\n },\n },\n required: [\"provider\", \"provider_config\"],\n additionalProperties: true,\n} as const satisfies DataPortSchemaObject;\n\nexport const OpenAiModelRecordSchema = {\n type: \"object\",\n properties: {\n ...ModelRecordSchema.properties,\n ...OpenAiModelSchema.properties,\n },\n required: [...ModelRecordSchema.required, ...OpenAiModelSchema.required],\n additionalProperties: false,\n} as const satisfies DataPortSchemaObject;\n\nexport type OpenAiModelRecord = WithModelPricing<FromSchema<typeof OpenAiModelRecordSchema>>;\n\nexport const OpenAiModelConfigSchema = {\n type: \"object\",\n properties: {\n ...ModelConfigSchema.properties,\n ...OpenAiModelSchema.properties,\n },\n required: [...ModelConfigSchema.required, ...OpenAiModelSchema.required],\n additionalProperties: false,\n} as const satisfies DataPortSchemaObject;\n\nexport type OpenAiModelConfig = WithModelPricing<FromSchema<typeof OpenAiModelConfigSchema>>;\n",
8
8
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { AiProviderRegisterOptions } from \"@workglow/ai\";\nimport { registerProviderWithWorker } from \"@workglow/ai/provider-utils\";\nimport { OpenAiQueuedProvider } from \"./OpenAiQueuedProvider\";\nimport { registerOpenAiImageValidator } from \"./common/OpenAI_ImageValidation\";\n\nexport async function registerOpenAi(\n options: AiProviderRegisterOptions & {\n worker: Worker | (() => Worker);\n }\n): Promise<void> {\n registerOpenAiImageValidator();\n await registerProviderWithWorker(new OpenAiQueuedProvider(), \"OpenAI\", options);\n}\n",
9
9
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Capability, ModelRecord } from \"@workglow/ai\";\nimport { AiProvider } from \"@workglow/ai\";\nimport { createCloudProviderClass } from \"@workglow/ai/provider-utils\";\nimport { inferOpenAiCapabilities, openAiWorkerRunFnSpecs } from \"./common/OpenAI_Capabilities\";\nimport { OPENAI } from \"./common/OpenAI_Constants\";\nimport type { OpenAiModelConfig } from \"./common/OpenAI_ModelSchema\";\n\n/**\n * Main-thread registration shell for OpenAI. Used both for inline mode\n * (constructed with the run-fn registrations array) and worker-backed mode\n * (constructed empty so the base class registers worker proxies). No queue\n * is created — OpenAI uses {@link DirectExecutionStrategy}.\n */\nexport class OpenAiQueuedProvider extends createCloudProviderClass<OpenAiModelConfig>(AiProvider, {\n name: OPENAI,\n displayName: \"OpenAI\",\n}) {\n override inferCapabilities(model: ModelRecord): readonly Capability[] {\n return inferOpenAiCapabilities(model);\n }\n\n protected override workerRunFnSpecs(): readonly { serves: readonly Capability[] }[] {\n return openAiWorkerRunFnSpecs();\n }\n}\n",
10
- "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Capability } from \"@workglow/ai/worker\";\n\n/**\n * Single source of truth for OpenAI's capability sets.\n *\n * Both `OPENAI_RUN_FNS` (the worker-side registration list) and\n * `workerRunFnSpecs()` (the main-thread proxy declaration) derive their\n * `serves` arrays from these named exports. SDK-free so the main thread\n * can import without paying the OpenAI client cost.\n *\n * To add a new capability set: declare a new `as const` constant here,\n * then reference it from both `OPENAI_RUN_FNS` and `OPENAI_RUN_FN_SPECS`.\n */\nexport const OPENAI_TEXT_GENERATION = [\"text.generation\"] as const satisfies Capability[];\nexport const OPENAI_TOOL_USE = [\"text.generation\", \"tool-use\"] as const satisfies Capability[];\nexport const OPENAI_JSON_MODE = [\"text.generation\", \"json-mode\"] as const satisfies Capability[];\nexport const OPENAI_TEXT_REWRITER = [\"text.rewriter\"] as const satisfies Capability[];\nexport const OPENAI_TEXT_SUMMARY = [\"text.summary\"] as const satisfies Capability[];\nexport const OPENAI_TEXT_EMBEDDING = [\"text.embedding\"] as const satisfies Capability[];\nexport const OPENAI_IMAGE_GENERATION = [\"image.generation\"] as const satisfies Capability[];\nexport const OPENAI_IMAGE_EDITING = [\"image.editing\"] as const satisfies Capability[];\nexport const OPENAI_COUNT_TOKENS = [\"model.count-tokens\"] as const satisfies Capability[];\nexport const OPENAI_MODEL_SEARCH = [\"model.search\"] as const satisfies Capability[];\nexport const OPENAI_MODEL_INFO = [\"model.info\"] as const satisfies Capability[];\n\n/** Aggregated list — for `workerRunFnSpecs()` derivation. Order MUST match `OPENAI_RUN_FNS`. */\nexport const OPENAI_CAPABILITY_SETS = [\n OPENAI_TEXT_GENERATION,\n OPENAI_TOOL_USE,\n OPENAI_JSON_MODE,\n OPENAI_TEXT_REWRITER,\n OPENAI_TEXT_SUMMARY,\n OPENAI_TEXT_EMBEDDING,\n OPENAI_IMAGE_GENERATION,\n OPENAI_IMAGE_EDITING,\n OPENAI_COUNT_TOKENS,\n OPENAI_MODEL_SEARCH,\n OPENAI_MODEL_INFO,\n] as const;\n",
11
- "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Capability, ModelRecord } from \"@workglow/ai/worker\";\nimport { OPENAI_CAPABILITY_SETS } from \"./OpenAI_CapabilitySets\";\n\n/**\n * Closed list of capability-set specs the OpenAI provider serves. Derived\n * from {@link OPENAI_CAPABILITY_SETS}. Used by the main-thread provider\n * shells when registering worker-mode proxies so the dispatcher can route\n * requests to the worker proxy.\n */\nexport const OPENAI_RUN_FN_SPECS = OPENAI_CAPABILITY_SETS.map((serves) => ({ serves }));\n\nexport function openAiWorkerRunFnSpecs(): readonly { readonly serves: readonly Capability[] }[] {\n return OPENAI_RUN_FN_SPECS;\n}\n\n/**\n * Shape used by the model-name regexes — `model_id` is required, the rest\n * is loosely-typed metadata only used to opportunistically widen the\n * inferred capability set.\n */\ntype CapabilityHints = Pick<ModelRecord, \"model_id\" | \"provider_config\" | \"capabilities\">;\n\n/**\n * Heuristic capability inference for an OpenAI {@link ModelRecord}. Pattern-\n * matches the canonical OpenAI model id strings (and the `provider_config.\n * model_name` if present) to a closed set of {@link Capability}s. Falls back\n * to the model's stored `capabilities` array (or a baseline of search +\n * info) when no pattern matches.\n *\n * Main-thread method only — workers do not run capability inference.\n */\nexport function inferOpenAiCapabilities(model: CapabilityHints): readonly Capability[] {\n const id = String(\n model.model_id ??\n (model.provider_config as { model_name?: string } | undefined)?.model_name ??\n \"\"\n );\n\n // Embedding models — text-embedding-3-{small,large}, text-embedding-ada-002.\n if (/^text-embedding/i.test(id)) {\n return [\"text.embedding\", \"model.count-tokens\", \"model.info\", \"model.search\"];\n }\n\n // Image models — DALL-E and gpt-image families.\n if (/^dall-e/i.test(id)) {\n // DALL-E 2/3 do NOT support edit consistently — gpt-image-* does. Cover\n // generation only here; the gpt-image branch below adds editing.\n return [\"image.generation\", \"model.info\", \"model.search\"];\n }\n if (/^gpt-image/i.test(id)) {\n return [\"image.generation\", \"image.editing\", \"model.info\", \"model.search\"];\n }\n\n // Chat / reasoning models — gpt-3.5/4/4o/5/...; o-series reasoning models (o1, o3, o4, future).\n // GPT-4o, gpt-4-vision-*, gpt-4-turbo, and all o-series additionally accept image inputs.\n if (/^gpt-/i.test(id) || /^o\\d/i.test(id)) {\n const caps: Capability[] = [\n \"text.generation\",\n \"text.rewriter\",\n \"text.summary\",\n \"tool-use\",\n \"json-mode\",\n \"model.count-tokens\",\n \"model.info\",\n \"model.search\",\n ];\n const supportsVision =\n /gpt-4o|gpt-4\\.1|gpt-5|gpt-4-vision|gpt-4-turbo/i.test(id) || /^o\\d/i.test(id);\n if (supportsVision) {\n caps.push(\"vision-input\");\n }\n return caps;\n }\n\n // Unknown model — fall back to whatever the record declared, or just\n // expose the meta-ops so the model can still be searched / inspected.\n const declared = (model.capabilities as readonly Capability[] | undefined) ?? [];\n if (declared.length > 0) return declared;\n return [\"model.search\", \"model.info\"];\n}\n",
10
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Capability } from \"@workglow/ai/worker\";\n\n/**\n * Single source of truth for OpenAI's capability sets.\n *\n * Both `OPENAI_RUN_FNS` (the worker-side registration list) and\n * `workerRunFnSpecs()` (the main-thread proxy declaration) derive their\n * `serves` arrays from these named exports. SDK-free so the main thread\n * can import without paying the OpenAI client cost.\n *\n * To add a new capability set: declare a new `as const` constant here,\n * then reference it from both `OPENAI_RUN_FNS` and `OPENAI_RUN_FN_SPECS`.\n */\nexport const OPENAI_TEXT_GENERATION = [\"text.generation\"] as const satisfies Capability[];\nexport const OPENAI_TOOL_USE = [\"text.generation\", \"tool-use\"] as const satisfies Capability[];\nexport const OPENAI_JSON_MODE = [\"text.generation\", \"json-mode\"] as const satisfies Capability[];\nexport const OPENAI_TEXT_REWRITER = [\"text.rewriter\"] as const satisfies Capability[];\nexport const OPENAI_TEXT_SUMMARY = [\"text.summary\"] as const satisfies Capability[];\nexport const OPENAI_TEXT_EMBEDDING = [\"text.embedding\"] as const satisfies Capability[];\nexport const OPENAI_IMAGE_GENERATION = [\"image.generation\"] as const satisfies Capability[];\nexport const OPENAI_IMAGE_EDITING = [\"image.editing\"] as const satisfies Capability[];\nexport const OPENAI_COUNT_TOKENS = [\"model.count-tokens\"] as const satisfies Capability[];\nexport const OPENAI_MODEL_SEARCH = [\"model.search\"] as const satisfies Capability[];\nexport const OPENAI_MODEL_INFO = [\"model.info\"] as const satisfies Capability[];\nexport const OPENAI_CACHE_CHECKPOINT = [\"cache.checkpoint\"] as const satisfies Capability[];\n\n/** Aggregated list — for `workerRunFnSpecs()` derivation. Order MUST match `OPENAI_RUN_FNS`. */\nexport const OPENAI_CAPABILITY_SETS = [\n OPENAI_TEXT_GENERATION,\n OPENAI_TOOL_USE,\n OPENAI_JSON_MODE,\n OPENAI_TEXT_REWRITER,\n OPENAI_TEXT_SUMMARY,\n OPENAI_TEXT_EMBEDDING,\n OPENAI_IMAGE_GENERATION,\n OPENAI_IMAGE_EDITING,\n OPENAI_COUNT_TOKENS,\n OPENAI_MODEL_SEARCH,\n OPENAI_MODEL_INFO,\n OPENAI_CACHE_CHECKPOINT,\n] as const;\n",
11
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Capability, ModelRecord } from \"@workglow/ai/worker\";\nimport { OPENAI_CAPABILITY_SETS } from \"./OpenAI_CapabilitySets\";\n\n/**\n * Closed list of capability-set specs the OpenAI provider serves. Derived\n * from {@link OPENAI_CAPABILITY_SETS}. Used by the main-thread provider\n * shells when registering worker-mode proxies so the dispatcher can route\n * requests to the worker proxy.\n */\nexport const OPENAI_RUN_FN_SPECS = OPENAI_CAPABILITY_SETS.map((serves) => ({ serves }));\n\nexport function openAiWorkerRunFnSpecs(): readonly { readonly serves: readonly Capability[] }[] {\n return OPENAI_RUN_FN_SPECS;\n}\n\n/**\n * Shape used by the model-name regexes — `model_id` is required, the rest\n * is loosely-typed metadata only used to opportunistically widen the\n * inferred capability set.\n */\ntype CapabilityHints = Pick<ModelRecord, \"model_id\" | \"provider_config\" | \"capabilities\">;\n\n/**\n * Heuristic capability inference for an OpenAI {@link ModelRecord}. Pattern-\n * matches the canonical OpenAI model id strings (and the `provider_config.\n * model_name` if present) to a closed set of {@link Capability}s. Falls back\n * to the model's stored `capabilities` array (or a baseline of search +\n * info) when no pattern matches.\n *\n * Main-thread method only — workers do not run capability inference.\n */\nexport function inferOpenAiCapabilities(model: CapabilityHints): readonly Capability[] {\n const id = String(\n model.model_id ??\n (model.provider_config as { model_name?: string } | undefined)?.model_name ??\n \"\"\n );\n\n // Embedding models — text-embedding-3-{small,large}, text-embedding-ada-002.\n if (/^text-embedding/i.test(id)) {\n return [\"text.embedding\", \"model.count-tokens\", \"model.info\", \"model.search\"];\n }\n\n // Image models — DALL-E and gpt-image families.\n if (/^dall-e/i.test(id)) {\n // DALL-E 2/3 do NOT support edit consistently — gpt-image-* does. Cover\n // generation only here; the gpt-image branch below adds editing.\n return [\"image.generation\", \"model.info\", \"model.search\"];\n }\n if (/^gpt-image/i.test(id)) {\n return [\"image.generation\", \"image.editing\", \"model.info\", \"model.search\"];\n }\n\n // Chat / reasoning models — gpt-3.5/4/4o/5/...; o-series reasoning models (o1, o3, o4, future).\n // GPT-4o, gpt-4-vision-*, gpt-4-turbo, and all o-series additionally accept image inputs.\n if (/^gpt-/i.test(id) || /^o\\d/i.test(id)) {\n const caps: Capability[] = [\n \"text.generation\",\n \"text.rewriter\",\n \"text.summary\",\n \"tool-use\",\n \"json-mode\",\n \"cache.checkpoint\",\n \"model.count-tokens\",\n \"model.info\",\n \"model.search\",\n ];\n const supportsVision =\n /gpt-4o|gpt-4\\.1|gpt-5|gpt-4-vision|gpt-4-turbo/i.test(id) || /^o\\d/i.test(id);\n if (supportsVision) {\n caps.push(\"vision-input\");\n }\n return caps;\n }\n\n // Unknown model — fall back to whatever the record declared, or just\n // expose the meta-ops so the model can still be searched / inspected.\n const declared = (model.capabilities as readonly Capability[] | undefined) ?? [];\n if (declared.length > 0) return declared;\n return [\"model.search\", \"model.info\"];\n}\n",
12
12
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { ModelConfig } from \"@workglow/ai\";\nimport { AiImageOutputTask, ProviderUnsupportedFeatureError } from \"@workglow/ai\";\n\nimport { OPENAI } from \"./OpenAI_Constants\";\n\n/**\n * Registers the OpenAI per-provider image validator. Called at provider registration time\n * (both inline and worker-backed paths) so it runs on the main thread before any dispatch.\n *\n * Currently validates:\n * - DALL-E 2 + non-empty `additionalImages` → throws (single-image edit only).\n * DALL-E 3 + ImageEditTask is rejected upstream by the model registry task-array check.\n */\nexport function registerOpenAiImageValidator(): void {\n AiImageOutputTask.registerProviderImageValidator(\n OPENAI,\n (taskType, input, model: ModelConfig) => {\n if (taskType !== \"ImageEditTask\") return;\n const modelName =\n (model.provider_config as { model_name?: string } | undefined)?.model_name ?? \"\";\n const additional = input[\"additionalImages\"] as unknown[] | undefined;\n if (modelName.startsWith(\"dall-e-2\") && Array.isArray(additional) && additional.length > 0) {\n throw new ProviderUnsupportedFeatureError(\n \"additionalImages\",\n model.model_id ?? modelName,\n \"DALL-E 2 only supports single-image edits\"\n );\n }\n }\n );\n}\n"
13
13
  ],
14
- "mappings": "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",
15
- "debugId": "C8884DFB1694D07E64756E2164756E21",
14
+ "mappings": "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",
15
+ "debugId": "63C2F7EB0BD183BC64756E2164756E21",
16
16
  "names": []
17
17
  }
package/dist/ai.js CHANGED
@@ -7,7 +7,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
7
7
  });
8
8
 
9
9
  // src/ai/common/OpenAI_Client.ts
10
+ import { isModelEffort } from "@workglow/ai";
10
11
  import { isBrowserLike, resolveApiKey, validateProviderBaseUrl } from "@workglow/ai/provider-utils";
12
+ var EFFORT_TO_OPENAI = {
13
+ none: "none",
14
+ low: "low",
15
+ medium: "medium",
16
+ high: "high",
17
+ extra: "xhigh",
18
+ ultra: "max"
19
+ };
11
20
  var OPENAI_ALLOWED_HOSTS = ["api.openai.com", ".openai.azure.com"];
12
21
  var _loadPromise;
13
22
  async function loadOpenAISDK() {
@@ -17,7 +26,16 @@ async function loadOpenAISDK() {
17
26
  });
18
27
  return _loadPromise;
19
28
  }
29
+ var _testClient;
30
+ function setOpenAIClientForTests(client) {
31
+ _testClient = client;
32
+ }
33
+ var _testOnly = {
34
+ setOpenAIClientForTests
35
+ };
20
36
  async function getClient(model) {
37
+ if (_testClient)
38
+ return _testClient;
21
39
  const OpenAI = await loadOpenAISDK();
22
40
  const config = model?.provider_config;
23
41
  const apiKey = resolveApiKey({
@@ -51,10 +69,13 @@ function getModelName(model) {
51
69
  }
52
70
  function getReasoningConfig(model) {
53
71
  const reasoning = model?.provider_config?.reasoning;
54
- if (!reasoning || reasoning.effort === undefined && reasoning.mode === undefined) {
55
- return;
72
+ if (reasoning && (reasoning.effort !== undefined || reasoning.mode !== undefined)) {
73
+ return reasoning;
56
74
  }
57
- return reasoning;
75
+ if (isModelEffort(model?.effort)) {
76
+ return { effort: EFFORT_TO_OPENAI[model.effort] };
77
+ }
78
+ return;
58
79
  }
59
80
  function fnv1aHex(input) {
60
81
  let hash = 2166136261;
@@ -79,6 +100,8 @@ function finalizeResponsesRequest(model, params) {
79
100
  const reasoning = getReasoningConfig(model);
80
101
  if (reasoning !== undefined)
81
102
  params.reasoning = reasoning;
103
+ else if (params.temperature !== undefined)
104
+ params.reasoning = { effort: "none" };
82
105
  params.prompt_cache_key = resolvePromptCacheKey(model, params);
83
106
  return params;
84
107
  }
@@ -275,6 +298,7 @@ var OPENAI_IMAGE_EDITING = ["image.editing"];
275
298
  var OPENAI_COUNT_TOKENS = ["model.count-tokens"];
276
299
  var OPENAI_MODEL_SEARCH = ["model.search"];
277
300
  var OPENAI_MODEL_INFO = ["model.info"];
301
+ var OPENAI_CACHE_CHECKPOINT = ["cache.checkpoint"];
278
302
  var OPENAI_CAPABILITY_SETS = [
279
303
  OPENAI_TEXT_GENERATION,
280
304
  OPENAI_TOOL_USE,
@@ -286,7 +310,8 @@ var OPENAI_CAPABILITY_SETS = [
286
310
  OPENAI_IMAGE_EDITING,
287
311
  OPENAI_COUNT_TOKENS,
288
312
  OPENAI_MODEL_SEARCH,
289
- OPENAI_MODEL_INFO
313
+ OPENAI_MODEL_INFO,
314
+ OPENAI_CACHE_CHECKPOINT
290
315
  ];
291
316
 
292
317
  // src/ai/common/OpenAI_Capabilities.ts
@@ -312,6 +337,7 @@ function inferOpenAiCapabilities(model) {
312
337
  "text.summary",
313
338
  "tool-use",
314
339
  "json-mode",
340
+ "cache.checkpoint",
315
341
  "model.count-tokens",
316
342
  "model.info",
317
343
  "model.search"
@@ -346,6 +372,54 @@ async function registerOpenAi(options) {
346
372
  registerOpenAiImageValidator();
347
373
  await registerProviderWithWorker(new OpenAiQueuedProvider, "OpenAI", options);
348
374
  }
375
+ // src/ai/common/OpenAI_CacheCheckpoint.ts
376
+ import {
377
+ buildResponsesInput,
378
+ buildResponsesTools,
379
+ mapOpenAIResponsesUsage
380
+ } from "@workglow/ai/provider-utils";
381
+ import { promptToTailMessages, toOpenAIMessages } from "@workglow/ai/worker";
382
+ function mergeOpenAICheckpointPrefix(session, input) {
383
+ const prefix = session?.prefix;
384
+ if (!prefix)
385
+ return;
386
+ const tail = Array.isArray(input.messages) && input.messages.length > 0 ? input.messages : promptToTailMessages(input.prompt);
387
+ return {
388
+ messages: [...prefix.messages ?? [], ...tail],
389
+ systemPrompt: input.systemPrompt || prefix.systemPrompt,
390
+ tools: input.tools && input.tools.length > 0 ? input.tools : prefix.tools
391
+ };
392
+ }
393
+ var OpenAI_CacheCheckpoint_Stream = async (_input, model, signal, emit, _outputSchema, session) => {
394
+ const prefix = session?.prefix ?? {};
395
+ const client = await getClient(model);
396
+ const messages = toOpenAIMessages({
397
+ messages: prefix.messages ?? [],
398
+ systemPrompt: prefix.systemPrompt,
399
+ prompt: ".",
400
+ tools: []
401
+ });
402
+ const { input: responsesInput, instructions } = buildResponsesInput({ messages });
403
+ const params = {
404
+ model: getModelName(model),
405
+ input: responsesInput,
406
+ max_output_tokens: 16
407
+ };
408
+ if (instructions !== undefined)
409
+ params.instructions = instructions;
410
+ if (prefix.tools && prefix.tools.length > 0) {
411
+ params.tools = buildResponsesTools(prefix.tools);
412
+ }
413
+ finalizeResponsesRequest(model, params);
414
+ const response = await client.responses.create(params, { signal });
415
+ const usage = mapOpenAIResponsesUsage(response?.usage);
416
+ emit({
417
+ type: "finish",
418
+ data: { checkpoint: session?.sessionId ?? "" },
419
+ ...usage ? { usage } : {}
420
+ });
421
+ };
422
+
349
423
  // src/ai/common/OpenAI_CountTokens.ts
350
424
  var _tiktoken;
351
425
  async function loadTiktoken() {
@@ -563,13 +637,54 @@ var OPENAI_EMBEDDING_DIMENSIONS = {
563
637
  "text-embedding-3-large": { native_dimensions: 3072, mrl: true },
564
638
  "text-embedding-ada-002": { native_dimensions: 1536, mrl: false }
565
639
  };
566
- var OpenAI_ModelInfo_Stream = async (input, model, _signal, emit) => {
640
+ function modelNameOf(model) {
641
+ const name = model?.provider_config?.model_name;
642
+ if (!name) {
643
+ throw new Error("Missing model name in provider_config.model_name.");
644
+ }
645
+ return name;
646
+ }
647
+ function isNotFoundError(err) {
648
+ if (!err || typeof err !== "object")
649
+ return false;
650
+ const status = err.status;
651
+ const code = err.code;
652
+ const statusCode = err.statusCode;
653
+ return status === 404 || statusCode === 404 || code === "model_not_found";
654
+ }
655
+ async function assertOpenAiModelExists(model, signal) {
656
+ const modelName = modelNameOf(model);
657
+ const client = await getClient(model);
658
+ try {
659
+ await client.models.retrieve(modelName, signal ? { signal } : undefined);
660
+ } catch (err) {
661
+ if (isNotFoundError(err)) {
662
+ throw new Error(`${OPENAI} model "${modelName}" was not found (provider API returned not found)`);
663
+ }
664
+ throw err;
665
+ }
666
+ return modelName;
667
+ }
668
+ function remoteInfoBase(input) {
669
+ return {
670
+ model: input.model,
671
+ is_local: false,
672
+ is_remote: true,
673
+ supports_browser: true,
674
+ supports_node: true,
675
+ is_cached: false,
676
+ is_loaded: false,
677
+ file_sizes: null
678
+ };
679
+ }
680
+ var OpenAI_ModelInfo_Stream = async (input, model, signal, emit) => {
681
+ const modelName = await assertOpenAiModelExists(model, signal);
682
+ const base = remoteInfoBase(input);
567
683
  if (input.detail === "dimensions") {
568
684
  const pc = model?.provider_config;
569
685
  let native_dimensions = typeof pc?.native_dimensions === "number" ? pc.native_dimensions : undefined;
570
686
  let mrl = typeof pc?.mrl === "boolean" ? pc.mrl : undefined;
571
687
  if (native_dimensions === undefined) {
572
- const modelName = pc?.model_name ?? "";
573
688
  const known = OPENAI_EMBEDDING_DIMENSIONS[modelName];
574
689
  if (known) {
575
690
  native_dimensions = known.native_dimensions;
@@ -579,38 +694,24 @@ var OpenAI_ModelInfo_Stream = async (input, model, _signal, emit) => {
579
694
  emit({
580
695
  type: "finish",
581
696
  data: {
582
- model: input.model,
583
- is_local: false,
584
- is_remote: true,
585
- supports_browser: true,
586
- supports_node: true,
587
- is_cached: false,
588
- is_loaded: false,
589
- file_sizes: null,
697
+ ...base,
590
698
  ...native_dimensions !== undefined ? { native_dimensions } : {},
591
699
  ...mrl !== undefined ? { mrl } : {}
592
700
  }
593
701
  });
594
702
  return;
595
703
  }
596
- emit({
597
- type: "finish",
598
- data: {
599
- model: input.model,
600
- is_local: false,
601
- is_remote: true,
602
- supports_browser: true,
603
- supports_node: true,
604
- is_cached: false,
605
- is_loaded: false,
606
- file_sizes: null
607
- }
608
- });
704
+ emit({ type: "finish", data: base });
609
705
  };
610
706
 
611
707
  // src/ai/common/OpenAI_StructuredGeneration.ts
612
- import { firstNonStrictReason, isStrictCompatibleSchema } from "@workglow/ai/provider-utils";
613
- import { parsePartialJson } from "@workglow/util/worker";
708
+ import {
709
+ createEstimatedOutputUsageReporter,
710
+ firstNonStrictReason,
711
+ isStrictCompatibleSchema,
712
+ mapOpenAIResponsesUsage as mapOpenAIResponsesUsage2
713
+ } from "@workglow/ai/provider-utils";
714
+ import { createPartialJsonStream } from "@workglow/util/worker";
614
715
 
615
716
  // src/ai/common/OpenAI_ResponsesWarnings.ts
616
717
  import { getLogger } from "@workglow/util/worker";
@@ -661,15 +762,20 @@ var OpenAI_StructuredGeneration_Stream = async (input, model, signal, emit, outp
661
762
  if (input.temperature !== undefined)
662
763
  params.temperature = input.temperature;
663
764
  finalizeResponsesRequest(model, params);
765
+ const provisionalUsage = createEstimatedOutputUsageReporter(emit);
766
+ provisionalUsage.onPrompt(typeof input.prompt === "string" ? input.prompt : "");
664
767
  const stream = await client.responses.create({ ...params, stream: true }, { signal });
665
- let accumulatedJson = "";
768
+ const json = createPartialJsonStream();
666
769
  let refusal = "";
770
+ let usage;
667
771
  for await (const event of stream) {
668
- if (event.type === "response.output_text.delta") {
772
+ if (event.type === "response.completed" || event.type === "response.incomplete" || event.type === "response.failed") {
773
+ usage = mapOpenAIResponsesUsage2(event.response?.usage) ?? usage;
774
+ } else if (event.type === "response.output_text.delta") {
669
775
  const delta = event.delta ?? "";
670
776
  if (delta) {
671
- accumulatedJson += delta;
672
- const partial = parsePartialJson(accumulatedJson);
777
+ provisionalUsage.onText(delta);
778
+ const partial = json.push(delta);
673
779
  if (partial !== undefined) {
674
780
  emit({ type: "object-delta", port: "object", objectDelta: partial });
675
781
  }
@@ -678,19 +784,19 @@ var OpenAI_StructuredGeneration_Stream = async (input, model, signal, emit, outp
678
784
  refusal += event.delta ?? "";
679
785
  }
680
786
  }
787
+ provisionalUsage.flush();
681
788
  if (refusal) {
682
789
  emit({ type: "refusal", refusal });
683
790
  }
684
- let finalObject;
685
- try {
686
- finalObject = JSON.parse(accumulatedJson);
687
- } catch {
688
- finalObject = parsePartialJson(accumulatedJson) ?? {};
689
- }
690
- emit({ type: "finish", data: { object: finalObject } });
791
+ emit({
792
+ type: "finish",
793
+ data: { object: json.finishObject() },
794
+ usage
795
+ });
691
796
  };
692
797
 
693
798
  // src/ai/common/OpenAI_TextEmbedding.ts
799
+ import { toUsageCount, usageOrUndefined } from "@workglow/ai/provider-utils";
694
800
  import { getLogger as getLogger2 } from "@workglow/util/worker";
695
801
  var OpenAI_TextEmbedding_Stream = async (input, model, signal, emit) => {
696
802
  const logger = getLogger2();
@@ -706,25 +812,41 @@ var OpenAI_TextEmbedding_Stream = async (input, model, signal, emit) => {
706
812
  const result = Array.isArray(input.text) ? {
707
813
  vector: response.data.map((item) => new Float32Array(item.embedding))
708
814
  } : { vector: new Float32Array(response.data[0].embedding) };
709
- emit({ type: "finish", data: result });
815
+ const rawUsage = response.usage;
816
+ const usage = usageOrUndefined({
817
+ input: toUsageCount(rawUsage?.prompt_tokens),
818
+ output: undefined,
819
+ cached: undefined,
820
+ cacheWrite: undefined,
821
+ reasoning: undefined,
822
+ total: toUsageCount(rawUsage?.total_tokens),
823
+ extra: undefined
824
+ });
825
+ emit({ type: "finish", data: result, usage });
710
826
  } finally {
711
827
  logger.timeEnd(timerLabel, { model: getModelName(model) });
712
828
  }
713
829
  };
714
830
 
715
831
  // src/ai/common/OpenAI_TextGeneration.ts
716
- import { accumulateOpenAIResponsesStream, buildResponsesInput } from "@workglow/ai/provider-utils";
717
- import { toOpenAIMessages } from "@workglow/ai/worker";
832
+ import {
833
+ accumulateOpenAIResponsesStream,
834
+ buildResponsesInput as buildResponsesInput2,
835
+ buildResponsesTools as buildResponsesTools2,
836
+ createEstimatedOutputUsageReporter as createEstimatedOutputUsageReporter2,
837
+ promptTextForResponsesUsageEstimate
838
+ } from "@workglow/ai/provider-utils";
839
+ import { toOpenAIMessages as toOpenAIMessages2 } from "@workglow/ai/worker";
718
840
  import { getLogger as getLogger3 } from "@workglow/util/worker";
719
841
  function buildResponsesParams(input, model) {
720
842
  const hasMessages = Array.isArray(input.messages) && input.messages.length > 0;
721
- const messages = hasMessages ? toOpenAIMessages({
843
+ const messages = hasMessages ? toOpenAIMessages2({
722
844
  messages: input.messages,
723
845
  systemPrompt: input.systemPrompt,
724
846
  prompt: "",
725
847
  tools: []
726
848
  }) : undefined;
727
- const { input: responsesInput, instructions } = buildResponsesInput({
849
+ const { input: responsesInput, instructions } = buildResponsesInput2({
728
850
  messages,
729
851
  prompt: hasMessages ? undefined : input.prompt,
730
852
  systemPrompt: hasMessages ? undefined : input.systemPrompt
@@ -750,23 +872,38 @@ function buildResponsesParams(input, model) {
750
872
  }
751
873
  return params;
752
874
  }
753
- var OpenAI_TextGeneration_Stream = async (input, model, signal, emit) => {
875
+ var OpenAI_TextGeneration_Stream = async (input, model, signal, emit, _outputSchema, sessionContext) => {
754
876
  const logger = getLogger3();
755
877
  const timerLabel = `openai:TextGeneration:${getModelName(model)}`;
756
878
  logger.time(timerLabel, { model: getModelName(model) });
757
879
  try {
758
880
  const client = await getClient(model);
759
- const params = finalizeResponsesRequest(model, buildResponsesParams(input, model));
881
+ const unified = input;
882
+ const merged = mergeOpenAICheckpointPrefix(sessionContext, unified);
883
+ const effective = merged ? { ...unified, messages: merged.messages, systemPrompt: merged.systemPrompt, prompt: "" } : unified;
884
+ const params = buildResponsesParams(effective, model);
885
+ if (merged?.tools && merged.tools.length > 0) {
886
+ params.tools = buildResponsesTools2(merged.tools);
887
+ }
888
+ finalizeResponsesRequest(model, params);
889
+ const promptText = promptTextForResponsesUsageEstimate(params);
890
+ createEstimatedOutputUsageReporter2(emit).onPrompt(promptText);
760
891
  const stream = await client.responses.create({ ...params, stream: true }, { signal });
761
- await accumulateOpenAIResponsesStream(stream, emit);
762
- emit({ type: "finish", data: {} });
892
+ const usage = await accumulateOpenAIResponsesStream(stream, emit, {
893
+ promptText
894
+ });
895
+ emit({ type: "finish", data: {}, usage });
763
896
  } finally {
764
897
  logger.timeEnd(timerLabel, { model: getModelName(model) });
765
898
  }
766
899
  };
767
900
 
768
901
  // src/ai/common/OpenAI_TextRewriter.ts
769
- import { accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream2 } from "@workglow/ai/provider-utils";
902
+ import {
903
+ accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream2,
904
+ createEstimatedOutputUsageReporter as createEstimatedOutputUsageReporter3,
905
+ promptTextForResponsesUsageEstimate as promptTextForResponsesUsageEstimate2
906
+ } from "@workglow/ai/provider-utils";
770
907
  var OpenAI_TextRewriter_Stream = async (input, model, signal, emit) => {
771
908
  const client = await getClient(model);
772
909
  const params = {
@@ -775,13 +912,21 @@ var OpenAI_TextRewriter_Stream = async (input, model, signal, emit) => {
775
912
  input: input.text
776
913
  };
777
914
  finalizeResponsesRequest(model, params);
915
+ const promptText = promptTextForResponsesUsageEstimate2(params);
916
+ createEstimatedOutputUsageReporter3(emit).onPrompt(promptText);
778
917
  const stream = await client.responses.create({ ...params, stream: true }, { signal });
779
- await accumulateOpenAIResponsesStream2(stream, emit);
780
- emit({ type: "finish", data: {} });
918
+ const usage = await accumulateOpenAIResponsesStream2(stream, emit, {
919
+ promptText
920
+ });
921
+ emit({ type: "finish", data: {}, usage });
781
922
  };
782
923
 
783
924
  // src/ai/common/OpenAI_TextSummary.ts
784
- import { accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream3 } from "@workglow/ai/provider-utils";
925
+ import {
926
+ accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream3,
927
+ createEstimatedOutputUsageReporter as createEstimatedOutputUsageReporter4,
928
+ promptTextForResponsesUsageEstimate as promptTextForResponsesUsageEstimate3
929
+ } from "@workglow/ai/provider-utils";
785
930
  var OpenAI_TextSummary_Stream = async (input, model, signal, emit) => {
786
931
  const client = await getClient(model);
787
932
  const params = {
@@ -790,25 +935,38 @@ var OpenAI_TextSummary_Stream = async (input, model, signal, emit) => {
790
935
  input: input.text
791
936
  };
792
937
  finalizeResponsesRequest(model, params);
938
+ const promptText = promptTextForResponsesUsageEstimate3(params);
939
+ createEstimatedOutputUsageReporter4(emit).onPrompt(promptText);
793
940
  const stream = await client.responses.create({ ...params, stream: true }, { signal });
794
- await accumulateOpenAIResponsesStream3(stream, emit);
795
- emit({ type: "finish", data: {} });
941
+ const usage = await accumulateOpenAIResponsesStream3(stream, emit, {
942
+ promptText
943
+ });
944
+ emit({ type: "finish", data: {}, usage });
796
945
  };
797
946
 
798
947
  // src/ai/common/OpenAI_ToolCalling.ts
799
948
  import {
800
949
  accumulateOpenAIResponsesStream as accumulateOpenAIResponsesStream4,
801
- buildResponsesInput as buildResponsesInput2,
802
- buildResponsesTools,
803
- mapResponsesToolChoice
950
+ buildResponsesInput as buildResponsesInput3,
951
+ buildResponsesTools as buildResponsesTools3,
952
+ createEstimatedOutputUsageReporter as createEstimatedOutputUsageReporter5,
953
+ mapResponsesToolChoice,
954
+ promptTextForResponsesUsageEstimate as promptTextForResponsesUsageEstimate4
804
955
  } from "@workglow/ai/provider-utils";
805
- import { filterValidToolCalls, toOpenAIMessages as toOpenAIMessages2 } from "@workglow/ai/worker";
806
- var OpenAI_ToolCalling_Stream = async (input, model, signal, emit) => {
956
+ import { filterValidToolCalls, toOpenAIMessages as toOpenAIMessages3 } from "@workglow/ai/worker";
957
+ var OpenAI_ToolCalling_Stream = async (input, model, signal, emit, _outputSchema, sessionContext) => {
807
958
  const client = await getClient(model);
808
959
  const modelName = getModelName(model);
809
- const tools = buildResponsesTools(input.tools);
810
- const { input: responsesInput, instructions } = buildResponsesInput2({
811
- messages: toOpenAIMessages2(input)
960
+ const merged = mergeOpenAICheckpointPrefix(sessionContext, input);
961
+ const toolDefinitions = merged?.tools ?? input.tools;
962
+ const tools = buildResponsesTools3(toolDefinitions);
963
+ const { input: responsesInput, instructions } = buildResponsesInput3({
964
+ messages: toOpenAIMessages3(merged ? {
965
+ ...input,
966
+ messages: merged.messages,
967
+ systemPrompt: merged.systemPrompt,
968
+ prompt: ""
969
+ } : input)
812
970
  });
813
971
  const toolChoice = mapResponsesToolChoice(input.toolChoice);
814
972
  const params = {
@@ -824,18 +982,20 @@ var OpenAI_ToolCalling_Stream = async (input, model, signal, emit) => {
824
982
  if (input.temperature !== undefined)
825
983
  params.temperature = input.temperature;
826
984
  finalizeResponsesRequest(model, params);
985
+ const promptText = promptTextForResponsesUsageEstimate4(params);
986
+ createEstimatedOutputUsageReporter5(emit).onPrompt(promptText);
827
987
  const stream = await client.responses.create({ ...params, stream: true }, { signal });
828
- await accumulateOpenAIResponsesStream4(stream, (event) => {
988
+ const usage = await accumulateOpenAIResponsesStream4(stream, (event) => {
829
989
  if (event.type === "object-delta" && event.port === "toolCalls") {
830
- const validated = filterValidToolCalls(event.objectDelta, input.tools);
990
+ const validated = filterValidToolCalls(event.objectDelta, toolDefinitions);
831
991
  if (validated.length > 0) {
832
992
  emit({ type: "object-delta", port: "toolCalls", objectDelta: validated });
833
993
  }
834
994
  return;
835
995
  }
836
996
  emit(event);
837
- });
838
- emit({ type: "finish", data: { text: "", toolCalls: [] } });
997
+ }, { promptText });
998
+ emit({ type: "finish", data: { text: "", toolCalls: [] }, usage });
839
999
  };
840
1000
 
841
1001
  // src/ai/common/OpenAI_JobRunFns.ts
@@ -850,28 +1010,31 @@ var OPENAI_RUN_FNS = [
850
1010
  { serves: OPENAI_IMAGE_EDITING, runFn: OpenAI_ImageEdit_Stream },
851
1011
  { serves: OPENAI_COUNT_TOKENS, runFn: OpenAI_CountTokens_Stream },
852
1012
  { serves: OPENAI_MODEL_SEARCH, runFn: OpenAI_ModelSearch_Stream },
853
- { serves: OPENAI_MODEL_INFO, runFn: OpenAI_ModelInfo_Stream }
1013
+ { serves: OPENAI_MODEL_INFO, runFn: OpenAI_ModelInfo_Stream },
1014
+ { serves: OPENAI_CACHE_CHECKPOINT, runFn: OpenAI_CacheCheckpoint_Stream }
854
1015
  ];
855
1016
  var OPENAI_PREVIEW_TASKS = {
856
1017
  CountTokensTask: OpenAI_CountTokens_Preview
857
1018
  };
858
1019
 
859
1020
  // src/ai/index.ts
860
- var _testOnly = {
1021
+ var _testOnly2 = {
861
1022
  OpenAiQueuedProvider,
862
1023
  OPENAI_RUN_FN_SPECS,
863
1024
  OPENAI_RUN_FNS,
1025
+ finalizeResponsesRequest,
864
1026
  getReasoningConfig,
865
1027
  resolvePromptCacheKey,
866
1028
  isStrictCompatibleSchema,
867
1029
  warnPenaltyDroppedOnce,
868
1030
  warnStrictDowngradedOnce,
869
- _resetOpenAIResponsesWarnings
1031
+ _resetOpenAIResponsesWarnings,
1032
+ setOpenAIClientForTests: _testOnly.setOpenAIClientForTests
870
1033
  };
871
1034
  export {
872
1035
  registerOpenAiImageValidator,
873
1036
  registerOpenAi,
874
- _testOnly,
1037
+ _testOnly2 as _testOnly,
875
1038
  OpenAiModelSchema,
876
1039
  OpenAiModelRecordSchema,
877
1040
  OpenAiModelConfigSchema,
@@ -880,4 +1043,4 @@ export {
880
1043
  OPENAI
881
1044
  };
882
1045
 
883
- //# debugId=5C3FAFC1792E85A564756E2164756E21
1046
+ //# debugId=9552B65D8C18B6CE64756E2164756E21