@robota-sdk/agent-provider-openai 3.0.0-beta.86 → 3.0.0-beta.87
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/CHANGELOG.md +22 -0
- package/README.md +6 -6
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +5 -3
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +5 -3
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/package.json +11 -9
- package/src/openai/__tests__/durable-operation-wire.test.ts +38 -0
- package/src/openai/__tests__/mixed-tool-content.test.ts +103 -0
- package/src/openai/loggers/file-payload-logger.test.ts +1 -1
- package/src/openai/provider-definition.ts +3 -2
- package/src/openai/provider.ts +11 -6
- package/src/openai/responses-converter.ts +12 -2
- package/src/openai/responses-types.ts +1 -1
- package/src/openai/types.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @robota-sdk/agent-provider-openai
|
|
2
2
|
|
|
3
|
+
## 3.0.0-beta.87
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Release the migrated Robota product with its public SDK namespace, robota command, compatible SDK exports, internal product configuration, and verified CLI startup and delivery corrections.
|
|
8
|
+
- 7d9cc66: Add owner-hosted organization control and OpenAI-wire gateway composition with anchored authority, mandatory verified audit, durable effect reservations, provider inventory cleanup and private content receipts. OpenAI profiles can opt into operation identities preserved across SDK retries.
|
|
9
|
+
- 7d9cc66: Retain typed text and image observations alongside structured tool data through runtime settlement, history, and recovery. Deliver tool images as native content in OpenAI Responses and Anthropic requests, retain structured error receipts, include media in bounded result admission, and reject malformed MCP image observations with reconciliation state intact.
|
|
10
|
+
- 7d9cc66: Preserve admitted tool text and source attribution on Chat Completions requests and transmit tool images as call-linked native vision observations.
|
|
11
|
+
- 7d9cc66: Retain typed resource and audio observations alongside structured tool results through history, durable receipts, recovery, size admission, and session persistence. Preserve opaque resource references without fetching them, project embedded text and explicit unsupported binary/audio diagnostics into provider requests and compaction transcripts, and validate persisted observation shapes on reload.
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
- Updated dependencies [66af868]
|
|
14
|
+
- Updated dependencies [7d9cc66]
|
|
15
|
+
- Updated dependencies [7d9cc66]
|
|
16
|
+
- Updated dependencies [7d9cc66]
|
|
17
|
+
- Updated dependencies [7d9cc66]
|
|
18
|
+
- Updated dependencies [7d9cc66]
|
|
19
|
+
- Updated dependencies [7d9cc66]
|
|
20
|
+
- Updated dependencies [7d9cc66]
|
|
21
|
+
- Updated dependencies [7d9cc66]
|
|
22
|
+
- @robota-sdk/agent-core@3.0.0-beta.87
|
|
23
|
+
- @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.87
|
|
24
|
+
|
|
3
25
|
## 3.0.0-beta.86
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @robota-sdk/agent-provider-openai
|
|
2
2
|
|
|
3
3
|
OpenAI provider for the Robota SDK, built on the official `openai` SDK. `OpenAIProvider` implements
|
|
4
|
-
the `@robota-sdk/agent-core` provider contract, so a `
|
|
4
|
+
the `@robota-sdk/agent-core` provider contract, so a `ConversationAgent` agent can run on OpenAI models with
|
|
5
5
|
streaming and tool calling. It is a protocol client rather than a vendor lock: set `baseURL` and the
|
|
6
6
|
same provider talks to any OpenAI-compatible endpoint (AI gateways such as Vercel AI Gateway,
|
|
7
7
|
LiteLLM or OpenRouter, Azure OpenAI, vLLM, Ollama, LM Studio), with model ids passed through
|
|
@@ -16,12 +16,12 @@ npm install @robota-sdk/agent-provider-openai @robota-sdk/agent-core
|
|
|
16
16
|
## Usage
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
|
-
import {
|
|
19
|
+
import { ConversationAgent } from '@robota-sdk/agent-core';
|
|
20
20
|
import { OpenAIProvider } from '@robota-sdk/agent-provider-openai';
|
|
21
21
|
|
|
22
22
|
const provider = new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY });
|
|
23
23
|
|
|
24
|
-
const agent = new
|
|
24
|
+
const agent = new ConversationAgent({
|
|
25
25
|
name: 'MyAgent',
|
|
26
26
|
aiProviders: [provider],
|
|
27
27
|
defaultModel: { provider: 'openai', model: 'gpt-4o' },
|
|
@@ -66,7 +66,7 @@ OpenAI-compatible endpoint that rejects the `strict` field needs `strictTools` l
|
|
|
66
66
|
|
|
67
67
|
### Reasoning effort and web tools
|
|
68
68
|
|
|
69
|
-
A reasoning-effort selection (`defaultModel.effort` on a `
|
|
69
|
+
A reasoning-effort selection (`defaultModel.effort` on a `ConversationAgent` agent, or `effort` on a chat call)
|
|
70
70
|
is sent as `reasoning.effort` only on the official Responses API (no `baseURL`) and only for models
|
|
71
71
|
in the provider's verified effort table. On Chat Completions, behind a custom `baseURL`, or for other
|
|
72
72
|
models, the effort is reported as not applied and no native field is sent. When a call selects an
|
|
@@ -121,7 +121,7 @@ unchanged. See [Provider failures](../../content/guide/error-handling.md#provide
|
|
|
121
121
|
|
|
122
122
|
## Related packages
|
|
123
123
|
|
|
124
|
-
- [`@robota-sdk/agent-core`](../agent-core/README.md): the `
|
|
124
|
+
- [`@robota-sdk/agent-core`](../agent-core/README.md): the `ConversationAgent` agent and the provider contract.
|
|
125
125
|
- [`@robota-sdk/agent-provider-openai-compatible`](../agent-provider-openai-compatible/README.md):
|
|
126
126
|
DeepSeek, Qwen and Gemma providers, plus the shared OpenAI-compatible protocol code this package
|
|
127
127
|
uses.
|
|
@@ -132,4 +132,4 @@ See [docs/SPEC.md](docs/SPEC.md) for the package contract.
|
|
|
132
132
|
|
|
133
133
|
## License
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
This package is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a [commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
|
package/dist/node/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-CMqjfN_6.cjs");let t=require("@robota-sdk/agent-core"),n=require("openai");n=e.t(n,1);let r=require("@robota-sdk/agent-provider-openai-compatible/shared"),i=require("node:crypto");function a(e){return(0,r.convertToOpenAICompatibleMessages)(e)}function o(e,t){return(0,r.convertToOpenAICompatibleTools)(e,{strict:t===!0})}function s(e,t){return t?.type===void 0?e:t.type===`json_schema`?{...e,responseFormat:`json_schema`,jsonSchema:{name:t.name??`structured_output`,schema:t.schema}}:{...e,responseFormat:t.type}}function c(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{type:`json_object`};let t=u(e);return{type:`json_schema`,json_schema:{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function l(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{format:{type:`json_object`}};let t=u(e);return{format:{type:`json_schema`,name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function u(e){let t=e.jsonSchema;if(e.responseFormat!==`json_schema`)throw Error(`Unsupported OpenAI response format: ${e.responseFormat}`);if(!t?.schema)throw Error(`OpenAI jsonSchema.schema is required when responseFormat is json_schema`);return{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}async function d(e){if(typeof e.withResponse==`function`){let{data:t,request_id:n}=await e.withResponse();return{data:t,...typeof n==`string`&&n.length>0&&{providerRequestId:n}}}return{data:await e}}function f(e){let t=e?._request_id;return typeof t==`string`&&t.length>0?t:void 0}function p(e,t){return t===void 0?e:{...e,metadata:{...e.metadata,providerRequestId:t}}}function m(e,t){let n=t!==void 0&&Object.keys(t).length>0;if(!(!e&&!n))return{...e?{signal:e}:{},...n?{headers:{...t}}:{}}}async function ee(e){let n=v(e.client);try{let t=g(e);if(e.chatOptions?.onTextDelta??e.onTextDelta)return await ne(n,e,{...t,stream:!0,...h(e)});await _(e,t,`chat`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:t});let r=m(e.chatOptions?.signal,e.requestHeaders),i=r?await n.chat.completions.create(t,r):await n.chat.completions.create(t);return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`response`,payload:i}),p(e.responseParser.parseResponse(i),f(i))}catch(e){throw(0,t.toProviderError)(e,`openai`,`OpenAI chat failed`)}}async function*te(e){let n=v(e.client);try{let t={...g(e),stream:!0,...h(e)};await _(e,t,`stream`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:t});let{data:i,providerRequestId:a}=await d(n.chat.completions.create(t,m(e.chatOptions?.signal,e.requestHeaders)));for await(let t of(0,r.observeProviderNativeRawPayloadStream)(i,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload})){let n=e.responseParser.parseStreamingChunk(t);n&&(yield p(n,a))}}catch(e){throw(0,t.toProviderError)(e,`openai`,`OpenAI stream failed`)}}function h(e){return e.providerOptions.includeStreamUsage===!1?{}:{stream_options:{include_usage:!0}}}function g(e){let t=a(e.messages),n=e.chatOptions?.model??e.providerOptions.defaultModel;if(!n)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let i=c(s(e.providerOptions,e.chatOptions?.responseFormat));return{model:n,messages:t,...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_tokens:e.chatOptions.maxTokens},...e.chatOptions?.tools&&{tools:o(e.chatOptions.tools,e.providerOptions.strictTools),tool_choice:(0,r.toOpenAICompatibleToolChoice)(e.chatOptions.toolChoice)},...i!==void 0&&{response_format:i}}}async function ne(e,n,i){try{await _(n,i,`stream`),n.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:i});let{data:t,providerRequestId:a}=await d(e.chat.completions.create(i,m(n.chatOptions?.signal,n.requestHeaders)));return p(await(0,r.assembleOpenAICompatibleStream)({stream:(0,r.observeProviderNativeRawPayloadStream)(t,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:n.chatOptions?.onProviderNativeRawPayload}),onTextDelta:n.chatOptions?.onTextDelta??n.onTextDelta,signal:n.chatOptions?.signal}),a)}catch(e){throw(0,t.toProviderError)(e,`openai`,`OpenAI stream failed`)}}async function _(e,t,n){if(!e.payloadLogger?.isEnabled())return;let r={model:t.model,messagesCount:t.messages.length,hasTools:!!t.tools,temperature:t.temperature??void 0,maxTokens:t.max_tokens??void 0,timestamp:new Date().toISOString()};await e.payloadLogger.logPayload(r,n)}function v(e){if(!e)throw Error(`OpenAI client not available. Either provide a client/apiKey or use an executor.`);return e}const y={verifiedAt:`2026-09-11`,sourceUrl:`https://platform.openai.com/docs/api-reference/responses`,models:{"gpt-5.1":{supportedEfforts:[`none`,`low`,`medium`,`high`],defaultEffort:`none`,nativeControlId:`responses.reasoning.effort`}}};var b=class{parser;constructor(e){this.parser=new r.OpenAICompatibleResponseParser({logger:e})}parseResponse(e){try{return this.parser.parseResponse(e)}catch(e){let t=x(e instanceof Error?e.message:`OpenAI response parsing failed`);throw Error(`OpenAI response parsing failed: ${t}`)}}parseStreamingChunk(e){try{return this.parser.parseStreamingChunk(e)}catch(e){let t=x(e instanceof Error?e.message:`OpenAI chunk parsing failed`);throw Error(`OpenAI chunk parsing failed: ${t}`)}}};function x(e){return e.replace(/^OpenAI-compatible response parsing failed: /,``).replace(/^OpenAI-compatible chunk parsing failed: /,``).replace(`OpenAI-compatible response`,`OpenAI response`)}function S(e){return e}function C(e,t){if(t===void 0)return e;if(t.effective===null||t.disposition===`model-default`){if(e?.effort!==void 0)throw Error(`Static reasoning.effort ${e.effort} conflicts with ${t.disposition===`model-default`?`provider-default selection`:`an effort resolution that does not apply a native control`}.`);return e}let n=S(t.effective);if(e?.effort!==void 0&&e.effort!==n)throw Error(`Resolved effort ${n} conflicts with static reasoning.effort ${e.effort}.`);return{...e,effort:n}}function w(e){return e.flatMap(e=>re(e))}function T(e,t){let n=t??!1,r=e?.map(e=>({type:`function`,name:e.name,description:e.description,parameters:e.parameters,strict:n}))??[];return r.length>0?r:void 0}function re(e){if(e.role===`user`)return[E(`user`,ae(e.content,e.parts))];if(e.role===`system`)return[E(`system`,e.content)];if(e.role===`tool`){if(!e.toolCallId||e.toolCallId.trim().length===0)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return[{type:`function_call_output`,call_id:e.toolCallId,output:e.content||``}]}return ie(e)}function ie(e){let t=[];e.content&&e.content.length>0&&t.push(E(`assistant`,e.content));for(let n of e.toolCalls??[])t.push({type:`function_call`,call_id:n.id,name:n.function.name,arguments:n.function.arguments});return t.length===0&&t.push(E(`assistant`,``)),t}function ae(e,t){if(!t||t.length===0)return e;let n=t.map(e=>oe(e));return e.length>0&&!t.some(e=>e.type===`text`)?[{type:`input_text`,text:e},...n]:n}function oe(e){return e.type===`text`?{type:`input_text`,text:e.text}:e.type===`image_uri`?{type:`input_image`,image_url:e.uri}:{type:`input_image`,image_url:`data:${e.mimeType};base64,${e.data}`}}function E(e,t){return{role:e,content:t}}async function*se(e,t){let n=e[Symbol.asyncIterator]();try{for(;!t?.aborted;){let e=await ce(n,t);if(e.done||t?.aborted)break;yield e.value}}finally{t?.aborted&&await n.return?.()}}async function ce(e,t){if(!t)return e.next();if(t.aborted)return{done:!0,value:void 0};let n,r=new Promise(e=>{n=()=>e({done:!0,value:void 0}),t.addEventListener(`abort`,n,{once:!0})});try{return await Promise.race([e.next(),r])}finally{n&&t.removeEventListener(`abort`,n)}}function le(e){G(e);let t=e.output??[];return j({content:e.output_text??L(t),toolCalls:P(t),response:e,reasoning:B(t)})}async function D(e){let t={textParts:[],toolCalls:[],reasoning:H()};for await(let n of se(e.stream,e.signal))O(t,n,e.onTextDelta);return t.completedResponse===void 0?j({content:t.textParts.join(``),toolCalls:t.toolCalls,reasoning:t.reasoning}):A(t)}function O(e,t,n){if(t.type===`response.output_text.delta`){e.textParts.push(t.delta),n?.(t.delta);return}if(t.type===`response.completed`){e.completedResponse=t.response,U(e.reasoning,B(t.response.output??[]));return}if(t.type===`response.output_item.done`){k(e,t.item);return}if(t.type===`response.error`||t.type===`response.failed`||t.type===`response.incomplete`)throw Error(`OpenAI Responses API failed: ${ue(t)}`)}function k(e,t){if(F(t)){e.toolCalls.push(I(t));return}V(t)&&U(e.reasoning,B([t]))}function A(e){let t=e.completedResponse;if(t===void 0)throw Error(`OpenAI Responses stream completed without response metadata`);G(t);let n=t.output??[],r=P(n),i=e.textParts.length>0?e.textParts.join(``):t.output_text??L(n),a=B(n);return U(a,e.reasoning),j({content:i,toolCalls:r.length>0?r:e.toolCalls,response:t,reasoning:a})}function j(e){return{id:(0,i.randomUUID)(),role:`assistant`,content:e.content,state:`complete`,timestamp:new Date,...e.toolCalls.length>0&&{toolCalls:e.toolCalls},...e.response?.usage!==void 0&&{usage:N(e.response.usage)},metadata:{...M(e.response,e.reasoning),...e.response?.usage!==void 0&&{usageProvenance:e.response.usage.input_tokens!==void 0&&e.response.usage.output_tokens!==void 0&&e.response.usage.total_tokens!==void 0?`complete`:`partial`}}}}function M(e,t){return{providerApiSurface:`responses`,...e?.id!==void 0&&{responseId:e.id},...e?.model!==void 0&&{model:e.model},...e?.status!==void 0&&{finishReason:e.status},...t.reasoningSummaryCount>0&&{reasoningSummaryCount:t.reasoningSummaryCount,reasoningSummaries:t.reasoningSummaries},...t.hasEncryptedReasoning&&{hasEncryptedReasoning:!0}}}function N(e){let t=e.input_tokens_details?.cached_tokens;return{promptTokens:e.input_tokens??0,completionTokens:e.output_tokens??0,...e.total_tokens!==void 0&&{totalTokens:e.total_tokens},...typeof t==`number`&&{cacheReadTokens:t}}}function P(e){return e.filter(F).map(e=>I(e))}function F(e){return e.type===`function_call`&&`call_id`in e&&`name`in e&&`arguments`in e}function I(e){return{id:e.call_id,type:`function`,function:{name:e.name,arguments:e.arguments}}}function L(e){return e.filter(z).flatMap(e=>e.content).map(R).join(``)}function R(e){return e.type===`refusal`?e.refusal:e.text}function z(e){return e.type===`message`&&`content`in e&&Array.isArray(e.content)}function B(e){let t=H();for(let n of e){if(!V(n))continue;let e=n.summary?.map(e=>e.text).filter(W)??[];t.reasoningSummaryCount+=e.length,t.reasoningSummaries.push(...e),t.hasEncryptedReasoning=t.hasEncryptedReasoning||!!n.encrypted_content}return t}function V(e){return e.type===`reasoning`}function H(){return{reasoningSummaryCount:0,reasoningSummaries:[],hasEncryptedReasoning:!1}}function U(e,t){e.reasoningSummaryCount+=t.reasoningSummaryCount,e.reasoningSummaries.push(...t.reasoningSummaries),e.hasEncryptedReasoning=e.hasEncryptedReasoning||t.hasEncryptedReasoning}function W(e){return e!==void 0}function G(e){if(e.status===`failed`||e.status===`incomplete`)throw Error(`OpenAI Responses API failed: ${e.error?.message??e.status}`)}function ue(e){return e.message??e.error?.message??e.response?.error?.message??`unknown error`}async function de(e){let n=e.chatOptions?.onTextDelta??e.onTextDelta;if(n)return K({...e,chatOptions:{...e.chatOptions,onTextDelta:n}});if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=q(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let n=await e.client.responses.create(t,m(e.chatOptions?.signal,e.requestHeaders));return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`response`,payload:n}),p(le(n),f(n))}catch(e){throw(0,t.toProviderError)(e,`openai`,`OpenAI responses failed`)}}async function*fe(e){let t={deltas:[]},n=e.chatOptions?.onTextDelta??e.onTextDelta,r=K({...e,chatOptions:{...e.chatOptions,onTextDelta:e=>{n?.(e),ge(t,me(e))}}}).then(e=>_e(t,e)).catch(e=>ve(t,xe(e)));yield*he(t),await r}async function K(e){if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=pe(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let{data:n,providerRequestId:i}=await d(e.client.responses.create(t,m(e.chatOptions?.signal,e.requestHeaders)));return p(await D({stream:(0,r.observeProviderNativeRawPayloadStream)(n,{provider:`openai`,apiSurface:`responses`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload}),onTextDelta:e.chatOptions?.onTextDelta,signal:e.chatOptions?.signal}),i)}catch(e){throw(0,t.toProviderError)(e,`openai`,`OpenAI responses stream failed`)}}function q(e){let t=e.chatOptions?.model??e.providerOptions.defaultModel;if(!t)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let n=T(e.chatOptions?.tools,e.providerOptions.strictTools),i=l(e.providerOptions),a=C(e.providerOptions.reasoning,e.chatOptions?.effortResolution);return{model:t,input:w(e.messages),...n!==void 0&&{tools:n,tool_choice:(0,r.toOpenAIResponsesToolChoice)(e.chatOptions?.toolChoice)},...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_output_tokens:e.chatOptions.maxTokens},...i!==void 0&&{text:i},...a!==void 0&&{reasoning:a},...e.providerOptions.includeEncryptedReasoning===!0&&{include:[`reasoning.encrypted_content`]},...e.providerOptions.store!==void 0&&{store:e.providerOptions.store}}}function pe(e){return{...q(e),stream:!0}}function me(e){return{id:(0,i.randomUUID)(),role:`assistant`,content:e,state:`complete`,timestamp:new Date,metadata:{providerApiSurface:`responses`,isStreamChunk:!0,isComplete:!1}}}async function*he(e){for(;;){let t=e.deltas.shift();if(t!==void 0){yield t;continue}if(e.error!==void 0)throw e.error;if(e.finalMessage!==void 0){yield be(e.finalMessage);return}await ye(e)}}function ge(e,t){e.deltas.push(t),J(e)}function _e(e,t){e.finalMessage=t,J(e)}function ve(e,t){e.error=t,J(e)}function ye(e){return new Promise(t=>{e.wake=t})}function J(e){e.wake?.(),e.wake=void 0}function be(e){return{...e,content:``,metadata:{...e.metadata,isStreamChunk:!0,isComplete:!0}}}function xe(e){return e instanceof Error?e:Error(String(e))}var Y=class extends t.AbstractAIProvider{name=`openai`;version=`1.0.0`;client;options;apiSurface;payloadLogger;responseParser;onTextDelta;constructor(e){if(super(e.logger||t.SilentLogger),this.options=e,this.apiSurface=Se(e),Ce(this.apiSurface,e.nativeWebTools),e.executor&&(this.executor=e.executor),!this.executor)if(e.client)this.client=e.client;else if(e.apiKey)this.client=new n.default({apiKey:e.apiKey,...e.organization&&{organization:e.organization},...e.timeout&&{timeout:e.timeout},...e.baseURL&&{baseURL:e.baseURL}});else throw Error(`Either OpenAI client, apiKey, or executor is required`);this.responseParser=new b(this.logger),this.payloadLogger=e.payloadLogger}async chat(e,t){this.validateMessages(e),this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=await this.executeViaExecutorOrDirect(e,n);return t.modelEffortOutcome===void 0&&this.publishModelEffortOutcome(n,`opaque-executor`),t.message}catch(e){throw this.logger.error(`OpenAI Provider executor chat error:`,e instanceof Error?e.message:String(e)),e}if(this.apiSurface===`responses`){let t=await de({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),t}let r=await ee({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),r}async*chatStream(e,t){this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=!1;for await(let r of this.executeStreamViaExecutorOrDirect(e,n))r.kind===`message`?yield r.message:t=r.modelEffortOutcome!==void 0;t||this.publishModelEffortOutcome(n,`opaque-executor`);return}catch(e){throw this.logger.error(`OpenAI Provider executor stream error:`,e instanceof Error?e.message:String(e)),e}yield*this.streamDirect(e,n)}async*streamDirect(e,t){if(this.apiSurface===`responses`){yield*fe({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t);return}yield*te({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t)}endpointIsVendorDefault(){return this.options.baseURL===void 0}canPropagateTraceContext(){return!this.executor&&this.effectiveBaseUrl()!==void 0}effectiveBaseUrl(){let e=this.client?.baseURL;return typeof e==`string`&&e.length>0?e:void 0}traceRequestHeaders(e){return this.canPropagateTraceContext()?(0,t.traceHeadersFor)(this.effectiveBaseUrl(),e?.outboundTraceContext):{}}effortTable(){return this.endpointIsVendorDefault()&&this.apiSurface===`responses`?y:void 0}resolveEffortOptions(e){if(e?.effort===void 0||e.effortResolution!==void 0)return e;let n=e.model??this.options.defaultModel;return n===void 0?e:{...e,effortResolution:(0,t.resolveModelEffort)(this.effortTable(),n,e.effort)}}projectionProfile(){return this.options.strictTools?{...t.STRICT_TOOL_SCHEMA_PROFILE,providerName:`openai`}:{...t.PERMISSIVE_TOOL_SCHEMA_PROFILE,providerName:`openai`}}projectChatOptions(e){if(!e?.tools)return e;let t=e.model??this.options.defaultModel??``,n=this.projectTools(e.tools,t);return{...e,tools:n&&n.length>0?n:void 0}}publishModelEffortOutcome(e,n){let r=e?.effortResolution,i=e?.onModelEffortOutcome;if(r===void 0||i===void 0)return;let a=n===void 0?r.effective!==null&&r.disposition!==`model-default`?{state:`sent`,id:`responses.reasoning.effort`}:{state:`omitted`,reason:r.disposition===`model-default`?`provider-default-selection`:`model-effort-not-applied`}:{state:`omitted`,reason:n},o=n===void 0?{state:`sent`}:{state:`not-dispatched`,reason:n};try{i((0,t.createModelEffortOutcome)(r,{nativeControl:a,providerDispatch:o}))}catch(e){this.logger.warn(`Model-effort outcome observer failed`,{error:e instanceof Error?e.message:String(e)})}}supportsTools(){return!0}getCapabilities(){let e=this.apiSurface===`chat-completions`?`openai-compatible-chat-completions`:`openai-responses`;return{functionCalling:{supported:!0},nativeWebTools:{webSearch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`search`)},webFetch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`fetch`)}}}}validateConfig(){return!!this.client&&!!this.options}async dispose(){}validateMessages(e){super.validateMessages(e);for(let t of e)if(t.role===`assistant`){let e=t;if(e.toolCalls&&e.toolCalls.length>0&&e.content===``)continue}}};function Se(e){return e.apiSurface===void 0?e.baseURL?`chat-completions`:`responses`:e.apiSurface}function X(e,t){return e===`chat-completions`?`OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${t}.`:`OpenAI Responses native web ${t} is not wired in this Robota provider version.`}function Ce(e,t){if(t?.webSearch===!0||t?.webFetch===!0)throw Error(`Provider openai native web search/fetch is not supported for apiSurface ${e} in this Robota provider version.`)}var we=class{static filterMessagesForOpenAI(e){return e.filter(e=>e.role===`user`||e.role===`assistant`||e.role===`system`||e.role===`tool`&&!!(e.toolCallId&&e.toolCallId.trim()!==``&&e.toolCallId!==`unknown`))}static toOpenAIFormat(e){return this.filterMessagesForOpenAI(e).map(e=>this.convertMessage(e))}static convertMessage(e){let t=e.role;if(t===`user`)return{role:`user`,content:e.content};if(t===`assistant`){let t=e;return t.toolCalls&&t.toolCalls.length>0?{role:`assistant`,content:t.content===``?null:t.content||null,tool_calls:t.toolCalls.map(e=>({id:e.id,type:`function`,function:{name:e.function.name,arguments:e.function.arguments}}))}:{role:`assistant`,content:t.content===null||t.content===``?null:t.content||``}}if(t===`system`)return{role:`system`,content:e.content};if(t===`tool`){if(!e.toolCallId||e.toolCallId.trim()===``)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return{role:`tool`,content:e.content,tool_call_id:e.toolCallId}}throw Error(`Unsupported message role: ${t}`)}static addSystemPromptIfNeeded(e,t){return!t||e.some(e=>e.role===`system`)?e:[{role:`system`,content:t},...e]}};const Z=`$ENV:OPENAI_API_KEY`,Te=[{kind:`api-key`,label:`OpenAI API keys`,url:`https://platform.openai.com/api-keys`,sourceUrl:`https://developers.openai.com/api/reference/overview#authentication`,lastVerifiedAt:`2026-05-08`}];function Ee(){return{type:`openai`,displayName:`OpenAI`,description:`GPT series — general-purpose assistant. API key required.`,category:`cloud-paid`,costPerTokenUsd:.001,defaults:{apiKey:Z},endpoint:{host:`api.openai.com`,port:443},modelCatalog:{status:`unavailable`,sourceUrl:`https://platform.openai.com/docs/api-reference/models/list`,message:`OpenAI model availability should be discovered live from GET /v1/models.`},setupHelpLinks:Te,setupSteps:[{key:`model`,title:`OpenAI model`,required:!0},{key:`apiKey`,title:`OpenAI API key`,defaultValue:Z,masked:!0}],requiresApiKey:!0,probeProfile:r.probeOpenAICompatibleProfile,destinationEnvironment:[`OPENAI_BASE_URL`,`OPENAI_ORG_ID`,`OPENAI_PROJECT_ID`],createProvider:e=>{let t=Q(e.options),n=Oe(e.options);return ke(e.baseURL,t,n),new Y({apiKey:De(e.apiKey),...e.baseURL!==void 0&&{baseURL:e.baseURL},...e.timeout!==void 0&&{timeout:e.timeout},...t!==void 0&&{apiSurface:t},...n!==void 0&&{nativeWebTools:n},defaultModel:e.model})}}}function De(e){if(!e)throw Error(`Provider openai requires apiKey`);return e}function Q(e){let t=e?.apiSurface;if(t===`responses`||t===`chat-completions`)return t}function Oe(e){let t=$(e?.nativeWebTools)??$(e?.builtInWebTools);if(t!==void 0)return t}function $(e){if(e==null||e instanceof Date||Array.isArray(e)||typeof e!=`object`)return;let t=e.webSearch,n=e.webFetch;return{...typeof t==`boolean`&&{webSearch:t},...typeof n==`boolean`&&{webFetch:n}}}function ke(e,t,n){if(n?.webSearch===!0||n?.webFetch===!0)throw Error(e!==void 0||t===`chat-completions`?`Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use Robota local WebSearch/WebFetch tools or a provider with documented hosted web support.`:`Provider openai native web search/fetch is not wired in this Robota provider version. Use Robota local WebSearch/WebFetch tools or a provider with documented hosted web support.`)}exports.DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE=Z,exports.DEFAULT_OPENAI_PROVIDER_MODEL=void 0,exports.OpenAIConversationAdapter=we,exports.OpenAIProvider=Y,exports.createOpenAIProviderDefinition=Ee;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-CMqjfN_6.cjs");let t=require("node:crypto"),n=require("@robota-sdk/agent-core"),r=require("openai");r=e.t(r,1);let i=require("@robota-sdk/agent-provider-openai-compatible/shared");function a(e){return(0,i.convertToOpenAICompatibleMessages)(e)}function o(e,t){return(0,i.convertToOpenAICompatibleTools)(e,{strict:t===!0})}function s(e,t){return t?.type===void 0?e:t.type===`json_schema`?{...e,responseFormat:`json_schema`,jsonSchema:{name:t.name??`structured_output`,schema:t.schema}}:{...e,responseFormat:t.type}}function c(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{type:`json_object`};let t=u(e);return{type:`json_schema`,json_schema:{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function l(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{format:{type:`json_object`}};let t=u(e);return{format:{type:`json_schema`,name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function u(e){let t=e.jsonSchema;if(e.responseFormat!==`json_schema`)throw Error(`Unsupported OpenAI response format: ${e.responseFormat}`);if(!t?.schema)throw Error(`OpenAI jsonSchema.schema is required when responseFormat is json_schema`);return{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}async function d(e){if(typeof e.withResponse==`function`){let{data:t,request_id:n}=await e.withResponse();return{data:t,...typeof n==`string`&&n.length>0&&{providerRequestId:n}}}return{data:await e}}function f(e){let t=e?._request_id;return typeof t==`string`&&t.length>0?t:void 0}function p(e,t){return t===void 0?e:{...e,metadata:{...e.metadata,providerRequestId:t}}}function m(e,t){let n=t!==void 0&&Object.keys(t).length>0;if(!(!e&&!n))return{...e?{signal:e}:{},...n?{headers:{...t}}:{}}}async function ee(e){let t=v(e.client);try{let n=g(e);if(e.chatOptions?.onTextDelta??e.onTextDelta)return await ne(t,e,{...n,stream:!0,...h(e)});await _(e,n,`chat`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let r=m(e.chatOptions?.signal,e.requestHeaders),i=r?await t.chat.completions.create(n,r):await t.chat.completions.create(n);return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`response`,payload:i}),p(e.responseParser.parseResponse(i),f(i))}catch(e){throw(0,n.toProviderError)(e,`openai`,`OpenAI chat failed`)}}async function*te(e){let t=v(e.client);try{let n={...g(e),stream:!0,...h(e)};await _(e,n,`stream`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let{data:r,providerRequestId:a}=await d(t.chat.completions.create(n,m(e.chatOptions?.signal,e.requestHeaders)));for await(let t of(0,i.observeProviderNativeRawPayloadStream)(r,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload})){let n=e.responseParser.parseStreamingChunk(t);n&&(yield p(n,a))}}catch(e){throw(0,n.toProviderError)(e,`openai`,`OpenAI stream failed`)}}function h(e){return e.providerOptions.includeStreamUsage===!1?{}:{stream_options:{include_usage:!0}}}function g(e){let t=a(e.messages),n=e.chatOptions?.model??e.providerOptions.defaultModel;if(!n)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let r=c(s(e.providerOptions,e.chatOptions?.responseFormat));return{model:n,messages:t,...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_tokens:e.chatOptions.maxTokens},...e.chatOptions?.tools&&{tools:o(e.chatOptions.tools,e.providerOptions.strictTools),tool_choice:(0,i.toOpenAICompatibleToolChoice)(e.chatOptions.toolChoice)},...r!==void 0&&{response_format:r}}}async function ne(e,t,r){try{await _(t,r,`stream`),t.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:r});let{data:n,providerRequestId:a}=await d(e.chat.completions.create(r,m(t.chatOptions?.signal,t.requestHeaders)));return p(await(0,i.assembleOpenAICompatibleStream)({stream:(0,i.observeProviderNativeRawPayloadStream)(n,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:t.chatOptions?.onProviderNativeRawPayload}),onTextDelta:t.chatOptions?.onTextDelta??t.onTextDelta,signal:t.chatOptions?.signal}),a)}catch(e){throw(0,n.toProviderError)(e,`openai`,`OpenAI stream failed`)}}async function _(e,t,n){if(!e.payloadLogger?.isEnabled())return;let r={model:t.model,messagesCount:t.messages.length,hasTools:!!t.tools,temperature:t.temperature??void 0,maxTokens:t.max_tokens??void 0,timestamp:new Date().toISOString()};await e.payloadLogger.logPayload(r,n)}function v(e){if(!e)throw Error(`OpenAI client not available. Either provide a client/apiKey or use an executor.`);return e}const re={verifiedAt:`2026-09-11`,sourceUrl:`https://platform.openai.com/docs/api-reference/responses`,models:{"gpt-5.1":{supportedEfforts:[`none`,`low`,`medium`,`high`],defaultEffort:`none`,nativeControlId:`responses.reasoning.effort`}}};var y=class{parser;constructor(e){this.parser=new i.OpenAICompatibleResponseParser({logger:e})}parseResponse(e){try{return this.parser.parseResponse(e)}catch(e){let t=b(e instanceof Error?e.message:`OpenAI response parsing failed`);throw Error(`OpenAI response parsing failed: ${t}`)}}parseStreamingChunk(e){try{return this.parser.parseStreamingChunk(e)}catch(e){let t=b(e instanceof Error?e.message:`OpenAI chunk parsing failed`);throw Error(`OpenAI chunk parsing failed: ${t}`)}}};function b(e){return e.replace(/^OpenAI-compatible response parsing failed: /,``).replace(/^OpenAI-compatible chunk parsing failed: /,``).replace(`OpenAI-compatible response`,`OpenAI response`)}function x(e){return e}function S(e,t){if(t===void 0)return e;if(t.effective===null||t.disposition===`model-default`){if(e?.effort!==void 0)throw Error(`Static reasoning.effort ${e.effort} conflicts with ${t.disposition===`model-default`?`provider-default selection`:`an effort resolution that does not apply a native control`}.`);return e}let n=x(t.effective);if(e?.effort!==void 0&&e.effort!==n)throw Error(`Resolved effort ${n} conflicts with static reasoning.effort ${e.effort}.`);return{...e,effort:n}}function C(e){return e.flatMap(e=>T(e))}function w(e,t){let n=t??!1,r=e?.map(e=>({type:`function`,name:e.name,description:e.description,parameters:e.parameters,strict:n}))??[];return r.length>0?r:void 0}function T(e){if(e.role===`user`)return[D(`user`,ae(e.content,e.parts))];if(e.role===`system`)return[D(`system`,e.content)];if(e.role===`tool`){if(!e.toolCallId||e.toolCallId.trim().length===0)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return[{type:`function_call_output`,call_id:e.toolCallId,output:e.parts?.length?[...e.content&&!e.parts.some(t=>t.type===`text`&&t.text===e.content)?[{type:`input_text`,text:e.content}]:[],...e.parts.map(E)]:e.content||``}]}return ie(e)}function ie(e){let t=[];e.content&&e.content.length>0&&t.push(D(`assistant`,e.content));for(let n of e.toolCalls??[])t.push({type:`function_call`,call_id:n.id,name:n.function.name,arguments:n.function.arguments});return t.length===0&&t.push(D(`assistant`,``)),t}function ae(e,t){if(!t||t.length===0)return e;let n=t.map(e=>E(e));return e.length>0&&!t.some(e=>e.type===`text`)?[{type:`input_text`,text:e},...n]:n}function E(e){return e.type===`text`?{type:`input_text`,text:e.text}:e.type===`image_uri`?{type:`input_image`,image_url:e.uri}:e.type===`image_inline`?{type:`input_image`,image_url:`data:${e.mimeType};base64,${e.data}`}:{type:`input_text`,text:(0,n.nonVisualObservationText)(e)??`Unsupported observation`}}function D(e,t){return{role:e,content:t}}async function*oe(e,t){let n=e[Symbol.asyncIterator]();try{for(;!t?.aborted;){let e=await se(n,t);if(e.done||t?.aborted)break;yield e.value}}finally{t?.aborted&&await n.return?.()}}async function se(e,t){if(!t)return e.next();if(t.aborted)return{done:!0,value:void 0};let n,r=new Promise(e=>{n=()=>e({done:!0,value:void 0}),t.addEventListener(`abort`,n,{once:!0})});try{return await Promise.race([e.next(),r])}finally{n&&t.removeEventListener(`abort`,n)}}function ce(e){G(e);let t=e.output??[];return j({content:e.output_text??L(t),toolCalls:P(t),response:e,reasoning:B(t)})}async function le(e){let t={textParts:[],toolCalls:[],reasoning:H()};for await(let n of oe(e.stream,e.signal))O(t,n,e.onTextDelta);return t.completedResponse===void 0?j({content:t.textParts.join(``),toolCalls:t.toolCalls,reasoning:t.reasoning}):A(t)}function O(e,t,n){if(t.type===`response.output_text.delta`){e.textParts.push(t.delta),n?.(t.delta);return}if(t.type===`response.completed`){e.completedResponse=t.response,U(e.reasoning,B(t.response.output??[]));return}if(t.type===`response.output_item.done`){k(e,t.item);return}if(t.type===`response.error`||t.type===`response.failed`||t.type===`response.incomplete`)throw Error(`OpenAI Responses API failed: ${ue(t)}`)}function k(e,t){if(F(t)){e.toolCalls.push(I(t));return}V(t)&&U(e.reasoning,B([t]))}function A(e){let t=e.completedResponse;if(t===void 0)throw Error(`OpenAI Responses stream completed without response metadata`);G(t);let n=t.output??[],r=P(n),i=e.textParts.length>0?e.textParts.join(``):t.output_text??L(n),a=B(n);return U(a,e.reasoning),j({content:i,toolCalls:r.length>0?r:e.toolCalls,response:t,reasoning:a})}function j(e){return{id:(0,t.randomUUID)(),role:`assistant`,content:e.content,state:`complete`,timestamp:new Date,...e.toolCalls.length>0&&{toolCalls:e.toolCalls},...e.response?.usage!==void 0&&{usage:N(e.response.usage)},metadata:{...M(e.response,e.reasoning),...e.response?.usage!==void 0&&{usageProvenance:e.response.usage.input_tokens!==void 0&&e.response.usage.output_tokens!==void 0&&e.response.usage.total_tokens!==void 0?`complete`:`partial`}}}}function M(e,t){return{providerApiSurface:`responses`,...e?.id!==void 0&&{responseId:e.id},...e?.model!==void 0&&{model:e.model},...e?.status!==void 0&&{finishReason:e.status},...t.reasoningSummaryCount>0&&{reasoningSummaryCount:t.reasoningSummaryCount,reasoningSummaries:t.reasoningSummaries},...t.hasEncryptedReasoning&&{hasEncryptedReasoning:!0}}}function N(e){let t=e.input_tokens_details?.cached_tokens;return{promptTokens:e.input_tokens??0,completionTokens:e.output_tokens??0,...e.total_tokens!==void 0&&{totalTokens:e.total_tokens},...typeof t==`number`&&{cacheReadTokens:t}}}function P(e){return e.filter(F).map(e=>I(e))}function F(e){return e.type===`function_call`&&`call_id`in e&&`name`in e&&`arguments`in e}function I(e){return{id:e.call_id,type:`function`,function:{name:e.name,arguments:e.arguments}}}function L(e){return e.filter(z).flatMap(e=>e.content).map(R).join(``)}function R(e){return e.type===`refusal`?e.refusal:e.text}function z(e){return e.type===`message`&&`content`in e&&Array.isArray(e.content)}function B(e){let t=H();for(let n of e){if(!V(n))continue;let e=n.summary?.map(e=>e.text).filter(W)??[];t.reasoningSummaryCount+=e.length,t.reasoningSummaries.push(...e),t.hasEncryptedReasoning=t.hasEncryptedReasoning||!!n.encrypted_content}return t}function V(e){return e.type===`reasoning`}function H(){return{reasoningSummaryCount:0,reasoningSummaries:[],hasEncryptedReasoning:!1}}function U(e,t){e.reasoningSummaryCount+=t.reasoningSummaryCount,e.reasoningSummaries.push(...t.reasoningSummaries),e.hasEncryptedReasoning=e.hasEncryptedReasoning||t.hasEncryptedReasoning}function W(e){return e!==void 0}function G(e){if(e.status===`failed`||e.status===`incomplete`)throw Error(`OpenAI Responses API failed: ${e.error?.message??e.status}`)}function ue(e){return e.message??e.error?.message??e.response?.error?.message??`unknown error`}async function de(e){let t=e.chatOptions?.onTextDelta??e.onTextDelta;if(t)return K({...e,chatOptions:{...e.chatOptions,onTextDelta:t}});if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=q(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let n=await e.client.responses.create(t,m(e.chatOptions?.signal,e.requestHeaders));return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`response`,payload:n}),p(ce(n),f(n))}catch(e){throw(0,n.toProviderError)(e,`openai`,`OpenAI responses failed`)}}async function*fe(e){let t={deltas:[]},n=e.chatOptions?.onTextDelta??e.onTextDelta,r=K({...e,chatOptions:{...e.chatOptions,onTextDelta:e=>{n?.(e),ge(t,me(e))}}}).then(e=>_e(t,e)).catch(e=>ve(t,xe(e)));yield*he(t),await r}async function K(e){if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=pe(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let{data:n,providerRequestId:r}=await d(e.client.responses.create(t,m(e.chatOptions?.signal,e.requestHeaders)));return p(await le({stream:(0,i.observeProviderNativeRawPayloadStream)(n,{provider:`openai`,apiSurface:`responses`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload}),onTextDelta:e.chatOptions?.onTextDelta,signal:e.chatOptions?.signal}),r)}catch(e){throw(0,n.toProviderError)(e,`openai`,`OpenAI responses stream failed`)}}function q(e){let t=e.chatOptions?.model??e.providerOptions.defaultModel;if(!t)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let n=w(e.chatOptions?.tools,e.providerOptions.strictTools),r=l(e.providerOptions),a=S(e.providerOptions.reasoning,e.chatOptions?.effortResolution);return{model:t,input:C(e.messages),...n!==void 0&&{tools:n,tool_choice:(0,i.toOpenAIResponsesToolChoice)(e.chatOptions?.toolChoice)},...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_output_tokens:e.chatOptions.maxTokens},...r!==void 0&&{text:r},...a!==void 0&&{reasoning:a},...e.providerOptions.includeEncryptedReasoning===!0&&{include:[`reasoning.encrypted_content`]},...e.providerOptions.store!==void 0&&{store:e.providerOptions.store}}}function pe(e){return{...q(e),stream:!0}}function me(e){return{id:(0,t.randomUUID)(),role:`assistant`,content:e,state:`complete`,timestamp:new Date,metadata:{providerApiSurface:`responses`,isStreamChunk:!0,isComplete:!1}}}async function*he(e){for(;;){let t=e.deltas.shift();if(t!==void 0){yield t;continue}if(e.error!==void 0)throw e.error;if(e.finalMessage!==void 0){yield be(e.finalMessage);return}await ye(e)}}function ge(e,t){e.deltas.push(t),J(e)}function _e(e,t){e.finalMessage=t,J(e)}function ve(e,t){e.error=t,J(e)}function ye(e){return new Promise(t=>{e.wake=t})}function J(e){e.wake?.(),e.wake=void 0}function be(e){return{...e,content:``,metadata:{...e.metadata,isStreamChunk:!0,isComplete:!0}}}function xe(e){return e instanceof Error?e:Error(String(e))}var Y=class extends n.AbstractAIProvider{name=`openai`;version=`1.0.0`;client;options;apiSurface;payloadLogger;responseParser;onTextDelta;constructor(e){if(super(e.logger||n.SilentLogger),this.options=e,this.apiSurface=Se(e),Ce(this.apiSurface,e.nativeWebTools),e.executor&&(this.executor=e.executor),!this.executor)if(e.client)this.client=e.client;else if(e.apiKey)this.client=new r.default({apiKey:e.apiKey,...e.organization&&{organization:e.organization},...e.timeout&&{timeout:e.timeout},...e.baseURL&&{baseURL:e.baseURL}});else throw Error(`Either OpenAI client, apiKey, or executor is required`);this.responseParser=new y(this.logger),this.payloadLogger=e.payloadLogger}async chat(e,t){this.validateMessages(e),this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=await this.executeViaExecutorOrDirect(e,n);return t.modelEffortOutcome===void 0&&this.publishModelEffortOutcome(n,`opaque-executor`),t.message}catch(e){throw this.logger.error(`OpenAI Provider executor chat error:`,e instanceof Error?e.message:String(e)),e}if(this.apiSurface===`responses`){let t=await de({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),t}let r=await ee({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),r}async*chatStream(e,t){this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=!1;for await(let r of this.executeStreamViaExecutorOrDirect(e,n))r.kind===`message`?yield r.message:t=r.modelEffortOutcome!==void 0;t||this.publishModelEffortOutcome(n,`opaque-executor`);return}catch(e){throw this.logger.error(`OpenAI Provider executor stream error:`,e instanceof Error?e.message:String(e)),e}yield*this.streamDirect(e,n)}async*streamDirect(e,t){if(this.apiSurface===`responses`){yield*fe({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t);return}yield*te({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t)}endpointIsVendorDefault(){return this.options.baseURL===void 0}canPropagateTraceContext(){return!this.executor&&this.effectiveBaseUrl()!==void 0}effectiveBaseUrl(){let e=this.client?.baseURL;return typeof e==`string`&&e.length>0?e:void 0}traceRequestHeaders(e){return{...this.canPropagateTraceContext()?(0,n.traceHeadersFor)(this.effectiveBaseUrl(),e?.outboundTraceContext):{},...this.options.durableOperations===!0?{"Idempotency-Key":(0,t.randomUUID)()}:{}}}effortTable(){return this.endpointIsVendorDefault()&&this.apiSurface===`responses`?re:void 0}resolveEffortOptions(e){if(e?.effort===void 0||e.effortResolution!==void 0)return e;let t=e.model??this.options.defaultModel;return t===void 0?e:{...e,effortResolution:(0,n.resolveModelEffort)(this.effortTable(),t,e.effort)}}projectionProfile(){return this.options.strictTools?{...n.STRICT_TOOL_SCHEMA_PROFILE,providerName:`openai`}:{...n.PERMISSIVE_TOOL_SCHEMA_PROFILE,providerName:`openai`}}projectChatOptions(e){if(!e?.tools)return e;let t=e.model??this.options.defaultModel??``,n=this.projectTools(e.tools,t);return{...e,tools:n&&n.length>0?n:void 0}}publishModelEffortOutcome(e,t){let r=e?.effortResolution,i=e?.onModelEffortOutcome;if(r===void 0||i===void 0)return;let a=t===void 0?r.effective!==null&&r.disposition!==`model-default`?{state:`sent`,id:`responses.reasoning.effort`}:{state:`omitted`,reason:r.disposition===`model-default`?`provider-default-selection`:`model-effort-not-applied`}:{state:`omitted`,reason:t},o=t===void 0?{state:`sent`}:{state:`not-dispatched`,reason:t};try{i((0,n.createModelEffortOutcome)(r,{nativeControl:a,providerDispatch:o}))}catch(e){this.logger.warn(`Model-effort outcome observer failed`,{error:e instanceof Error?e.message:String(e)})}}supportsTools(){return!0}getCapabilities(){let e=this.apiSurface===`chat-completions`?`openai-compatible-chat-completions`:`openai-responses`;return{functionCalling:{supported:!0},nativeWebTools:{webSearch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`search`)},webFetch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`fetch`)}}}}validateConfig(){return!!this.client&&!!this.options}async dispose(){}validateMessages(e){super.validateMessages(e);for(let t of e)if(t.role===`assistant`){let e=t;if(e.toolCalls&&e.toolCalls.length>0&&e.content===``)continue}}};function Se(e){return e.apiSurface===void 0?e.baseURL?`chat-completions`:`responses`:e.apiSurface}function X(e,t){return e===`chat-completions`?`OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${t}.`:`OpenAI Responses native web ${t} is not wired in this provider version.`}function Ce(e,t){if(t?.webSearch===!0||t?.webFetch===!0)throw Error(`Provider openai native web search/fetch is not supported for apiSurface ${e} in this provider version.`)}var we=class{static filterMessagesForOpenAI(e){return e.filter(e=>e.role===`user`||e.role===`assistant`||e.role===`system`||e.role===`tool`&&!!(e.toolCallId&&e.toolCallId.trim()!==``&&e.toolCallId!==`unknown`))}static toOpenAIFormat(e){return this.filterMessagesForOpenAI(e).map(e=>this.convertMessage(e))}static convertMessage(e){let t=e.role;if(t===`user`)return{role:`user`,content:e.content};if(t===`assistant`){let t=e;return t.toolCalls&&t.toolCalls.length>0?{role:`assistant`,content:t.content===``?null:t.content||null,tool_calls:t.toolCalls.map(e=>({id:e.id,type:`function`,function:{name:e.function.name,arguments:e.function.arguments}}))}:{role:`assistant`,content:t.content===null||t.content===``?null:t.content||``}}if(t===`system`)return{role:`system`,content:e.content};if(t===`tool`){if(!e.toolCallId||e.toolCallId.trim()===``)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return{role:`tool`,content:e.content,tool_call_id:e.toolCallId}}throw Error(`Unsupported message role: ${t}`)}static addSystemPromptIfNeeded(e,t){return!t||e.some(e=>e.role===`system`)?e:[{role:`system`,content:t},...e]}};const Z=`$ENV:OPENAI_API_KEY`,Te=[{kind:`api-key`,label:`OpenAI API keys`,url:`https://platform.openai.com/api-keys`,sourceUrl:`https://developers.openai.com/api/reference/overview#authentication`,lastVerifiedAt:`2026-05-08`}];function Ee(){return{type:`openai`,displayName:`OpenAI`,description:`GPT series — general-purpose assistant. API key required.`,category:`cloud-paid`,costPerTokenUsd:.001,defaults:{apiKey:Z},endpoint:{host:`api.openai.com`,port:443},modelCatalog:{status:`unavailable`,sourceUrl:`https://platform.openai.com/docs/api-reference/models/list`,message:`OpenAI model availability should be discovered live from GET /v1/models.`},setupHelpLinks:Te,setupSteps:[{key:`model`,title:`OpenAI model`,required:!0},{key:`apiKey`,title:`OpenAI API key`,defaultValue:Z,masked:!0}],requiresApiKey:!0,probeProfile:i.probeOpenAICompatibleProfile,destinationEnvironment:[`OPENAI_BASE_URL`,`OPENAI_ORG_ID`,`OPENAI_PROJECT_ID`],createProvider:e=>{let t=Q(e.options),n=Oe(e.options);return ke(e.baseURL,t,n),new Y({apiKey:De(e.apiKey),...e.baseURL!==void 0&&{baseURL:e.baseURL},...e.timeout!==void 0&&{timeout:e.timeout},...t!==void 0&&{apiSurface:t},...n!==void 0&&{nativeWebTools:n},...e.options?.durableOperations===!0&&{durableOperations:!0},defaultModel:e.model})}}}function De(e){if(!e)throw Error(`Provider openai requires apiKey`);return e}function Q(e){let t=e?.apiSurface;if(t===`responses`||t===`chat-completions`)return t}function Oe(e){let t=$(e?.nativeWebTools)??$(e?.builtInWebTools);if(t!==void 0)return t}function $(e){if(e==null||e instanceof Date||Array.isArray(e)||typeof e!=`object`)return;let t=e.webSearch,n=e.webFetch;return{...typeof t==`boolean`&&{webSearch:t},...typeof n==`boolean`&&{webFetch:n}}}function ke(e,t,n){if(n?.webSearch===!0||n?.webFetch===!0)throw Error(e!==void 0||t===`chat-completions`?`Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.`:`Provider openai native web search/fetch is not wired in this provider version. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.`)}exports.DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE=Z,exports.DEFAULT_OPENAI_PROVIDER_MODEL=void 0,exports.OpenAIConversationAdapter=we,exports.OpenAIProvider=Y,exports.createOpenAIProviderDefinition=Ee;
|
package/dist/node/index.d.cts
CHANGED
|
@@ -27,6 +27,8 @@ type TOpenAIProviderOptionValue = string | number | boolean | undefined | null |
|
|
|
27
27
|
* OpenAI provider options
|
|
28
28
|
*/
|
|
29
29
|
interface IOpenAIProviderOptions {
|
|
30
|
+
/** Emit one operation ID per model request, preserved by SDK retries, for durable company gateways. */
|
|
31
|
+
durableOperations?: boolean;
|
|
30
32
|
/**
|
|
31
33
|
* Additional provider-specific options
|
|
32
34
|
*/
|
|
@@ -133,7 +135,7 @@ interface IOpenAIProviderOptions {
|
|
|
133
135
|
/**
|
|
134
136
|
* Provider-native hosted web tool request from provider profile options.
|
|
135
137
|
*
|
|
136
|
-
* OpenAI-compatible Chat Completions endpoints do not support this
|
|
138
|
+
* OpenAI-compatible Chat Completions endpoints do not support this ConversationAgent
|
|
137
139
|
* native web contract. The provider rejects unsupported configurations before
|
|
138
140
|
* any model request is sent.
|
|
139
141
|
*/
|
|
@@ -197,9 +199,9 @@ interface IOpenAIProviderOptions {
|
|
|
197
199
|
//#endregion
|
|
198
200
|
//#region src/openai/provider.d.ts
|
|
199
201
|
/**
|
|
200
|
-
* OpenAI provider implementation for
|
|
202
|
+
* OpenAI provider implementation for ConversationAgent
|
|
201
203
|
*
|
|
202
|
-
* Provides integration with OpenAI models through the
|
|
204
|
+
* Provides integration with OpenAI models through the ConversationAgent provider contract.
|
|
203
205
|
* Uses OpenAI SDK native types internally for optimal performance and feature support.
|
|
204
206
|
*
|
|
205
207
|
* @public
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/openai/types.ts","../../src/openai/provider.ts","../../src/openai/adapter.ts","../../src/openai/provider-definition.ts"],"mappings":";;;;KAIY;UAEK;EACf;EACA;EACA,SAAS,eAAe;EACxB;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;;;;KAMU,4EAMR,8BACA,+BACA,mCACA,SACA,iBACA,UACA,YACA,2BACA;GACG,cAAc;;;;;UAKJ;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/openai/types.ts","../../src/openai/provider.ts","../../src/openai/adapter.ts","../../src/openai/provider-definition.ts"],"mappings":";;;;KAIY;UAEK;EACf;EACA;EACA,SAAS,eAAe;EACxB;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;;;;KAMU,4EAMR,8BACA,+BACA,mCACA,SACA,iBACA,UACA,YACA,2BACA;GACG,cAAc;;;;;UAKJ;;EAEf;;;;GAIC,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA;;;;;;;;;;;;;;;;;EAkBA;;;;;;;;EASA,iBAAiB;;;;EAKjB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BT,gBAAgB;;;;;;;;;;;;;;;;;;EAmBhB,WAAW;;;;;EAMX,SAAS;;;;;;;;;;;;cCnME,uBAAuB;WAChB;WACA;mBAED;mBACA;mBACA;mBACA;mBACA;;;;;;;EAQjB,cAAc;EAEF,YAAA,SAAS;EA6BN,KACb,UAAU,qBACV,UAAU,eACT,QAAQ;EAgDK,WACd,UAAU,qBACV,UAAU,eACT,cAAc;UAiCF;;;;;;;;;;EAuCf;;;;;;EASA;UAIQ;UAKA;EASC,eAAe;UAMhB;;;;;YAcW,qBAAqB;;;;;;;;UAahC;UAYA;EAiCC;EAIA,mBAAmB;EAwBnB;EAIM,WAAW;YAIP,iBAAiB,UAAU;;;;;;;;;;;;cCpVnC;;;;;;;;;SASJ,wBAAwB,UAAU,sBAAsB;;;;;SAqBxD,eAAe,UAAU,sBAAsB,OAAO,KAAK;;;;;SAU3D,eAAe,KAAK,oBAAoB,OAAO,KAAK;;;;SA2EpD,wBACL,UAAU,OAAO,KAAK,8BACtB,wBACC,OAAO,KAAK;;;;cC1HJ;cACA;iBAeG,kCAAkC"}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ type TOpenAIProviderOptionValue = string | number | boolean | undefined | null |
|
|
|
27
27
|
* OpenAI provider options
|
|
28
28
|
*/
|
|
29
29
|
interface IOpenAIProviderOptions {
|
|
30
|
+
/** Emit one operation ID per model request, preserved by SDK retries, for durable company gateways. */
|
|
31
|
+
durableOperations?: boolean;
|
|
30
32
|
/**
|
|
31
33
|
* Additional provider-specific options
|
|
32
34
|
*/
|
|
@@ -133,7 +135,7 @@ interface IOpenAIProviderOptions {
|
|
|
133
135
|
/**
|
|
134
136
|
* Provider-native hosted web tool request from provider profile options.
|
|
135
137
|
*
|
|
136
|
-
* OpenAI-compatible Chat Completions endpoints do not support this
|
|
138
|
+
* OpenAI-compatible Chat Completions endpoints do not support this ConversationAgent
|
|
137
139
|
* native web contract. The provider rejects unsupported configurations before
|
|
138
140
|
* any model request is sent.
|
|
139
141
|
*/
|
|
@@ -197,9 +199,9 @@ interface IOpenAIProviderOptions {
|
|
|
197
199
|
//#endregion
|
|
198
200
|
//#region src/openai/provider.d.ts
|
|
199
201
|
/**
|
|
200
|
-
* OpenAI provider implementation for
|
|
202
|
+
* OpenAI provider implementation for ConversationAgent
|
|
201
203
|
*
|
|
202
|
-
* Provides integration with OpenAI models through the
|
|
204
|
+
* Provides integration with OpenAI models through the ConversationAgent provider contract.
|
|
203
205
|
* Uses OpenAI SDK native types internally for optimal performance and feature support.
|
|
204
206
|
*
|
|
205
207
|
* @public
|
package/dist/node/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/openai/types.ts","../../src/openai/provider.ts","../../src/openai/adapter.ts","../../src/openai/provider-definition.ts"],"mappings":";;;;KAIY;UAEK;EACf;EACA;EACA,SAAS,eAAe;EACxB;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;;;;KAMU,4EAMR,8BACA,+BACA,mCACA,SACA,iBACA,UACA,YACA,2BACA;GACG,cAAc;;;;;UAKJ;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/openai/types.ts","../../src/openai/provider.ts","../../src/openai/adapter.ts","../../src/openai/provider-definition.ts"],"mappings":";;;;KAIY;UAEK;EACf;EACA;EACA,SAAS,eAAe;EACxB;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;;;;KAMU,4EAMR,8BACA,+BACA,mCACA,SACA,iBACA,UACA,YACA,2BACA;GACG,cAAc;;;;;UAKJ;;EAEf;;;;GAIC,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA;;;;;;;;;;;;;;;;;EAkBA;;;;;;;;EASA,iBAAiB;;;;EAKjB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BT,gBAAgB;;;;;;;;;;;;;;;;;;EAmBhB,WAAW;;;;;EAMX,SAAS;;;;;;;;;;;;cCnME,uBAAuB;WAChB;WACA;mBAED;mBACA;mBACA;mBACA;mBACA;;;;;;;EAQjB,cAAc;EAEF,YAAA,SAAS;EA6BN,KACb,UAAU,qBACV,UAAU,eACT,QAAQ;EAgDK,WACd,UAAU,qBACV,UAAU,eACT,cAAc;UAiCF;;;;;;;;;;EAuCf;;;;;;EASA;UAIQ;UAKA;EASC,eAAe;UAMhB;;;;;YAcW,qBAAqB;;;;;;;;UAahC;UAYA;EAiCC;EAIA,mBAAmB;EAwBnB;EAIM,WAAW;YAIP,iBAAiB,UAAU;;;;;;;;;;;;cCpVnC;;;;;;;;;SASJ,wBAAwB,UAAU,sBAAsB;;;;;SAqBxD,eAAe,UAAU,sBAAsB,OAAO,KAAK;;;;;SAU3D,eAAe,KAAK,oBAAoB,OAAO,KAAK;;;;SA2EpD,wBACL,UAAU,OAAO,KAAK,8BACtB,wBACC,OAAO,KAAK;;;;cC1HJ;cACA;iBAeG,kCAAkC"}
|
package/dist/node/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AbstractAIProvider as e,PERMISSIVE_TOOL_SCHEMA_PROFILE as t,STRICT_TOOL_SCHEMA_PROFILE as n,SilentLogger as r,createModelEffortOutcome as i,resolveModelEffort as a,toProviderError as o,traceHeadersFor as ee}from"@robota-sdk/agent-core";import te from"openai";import{OpenAICompatibleResponseParser as ne,assembleOpenAICompatibleStream as re,convertToOpenAICompatibleMessages as ie,convertToOpenAICompatibleTools as ae,observeProviderNativeRawPayloadStream as s,probeOpenAICompatibleProfile as oe,toOpenAICompatibleToolChoice as se,toOpenAIResponsesToolChoice as ce}from"@robota-sdk/agent-provider-openai-compatible/shared";import{randomUUID as c}from"node:crypto";function le(e){return ie(e)}function l(e,t){return ae(e,{strict:t===!0})}function u(e,t){return t?.type===void 0?e:t.type===`json_schema`?{...e,responseFormat:`json_schema`,jsonSchema:{name:t.name??`structured_output`,schema:t.schema}}:{...e,responseFormat:t.type}}function ue(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{type:`json_object`};let t=d(e);return{type:`json_schema`,json_schema:{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function de(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{format:{type:`json_object`}};let t=d(e);return{format:{type:`json_schema`,name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function d(e){let t=e.jsonSchema;if(e.responseFormat!==`json_schema`)throw Error(`Unsupported OpenAI response format: ${e.responseFormat}`);if(!t?.schema)throw Error(`OpenAI jsonSchema.schema is required when responseFormat is json_schema`);return{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}async function f(e){if(typeof e.withResponse==`function`){let{data:t,request_id:n}=await e.withResponse();return{data:t,...typeof n==`string`&&n.length>0&&{providerRequestId:n}}}return{data:await e}}function p(e){let t=e?._request_id;return typeof t==`string`&&t.length>0?t:void 0}function m(e,t){return t===void 0?e:{...e,metadata:{...e.metadata,providerRequestId:t}}}function h(e,t){let n=t!==void 0&&Object.keys(t).length>0;if(!(!e&&!n))return{...e?{signal:e}:{},...n?{headers:{...t}}:{}}}async function fe(e){let t=y(e.client);try{let n=_(e);if(e.chatOptions?.onTextDelta??e.onTextDelta)return await me(t,e,{...n,stream:!0,...g(e)});await v(e,n,`chat`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let r=h(e.chatOptions?.signal,e.requestHeaders),i=r?await t.chat.completions.create(n,r):await t.chat.completions.create(n);return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`response`,payload:i}),m(e.responseParser.parseResponse(i),p(i))}catch(e){throw o(e,`openai`,`OpenAI chat failed`)}}async function*pe(e){let t=y(e.client);try{let n={..._(e),stream:!0,...g(e)};await v(e,n,`stream`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let{data:r,providerRequestId:i}=await f(t.chat.completions.create(n,h(e.chatOptions?.signal,e.requestHeaders)));for await(let t of s(r,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload})){let n=e.responseParser.parseStreamingChunk(t);n&&(yield m(n,i))}}catch(e){throw o(e,`openai`,`OpenAI stream failed`)}}function g(e){return e.providerOptions.includeStreamUsage===!1?{}:{stream_options:{include_usage:!0}}}function _(e){let t=le(e.messages),n=e.chatOptions?.model??e.providerOptions.defaultModel;if(!n)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let r=ue(u(e.providerOptions,e.chatOptions?.responseFormat));return{model:n,messages:t,...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_tokens:e.chatOptions.maxTokens},...e.chatOptions?.tools&&{tools:l(e.chatOptions.tools,e.providerOptions.strictTools),tool_choice:se(e.chatOptions.toolChoice)},...r!==void 0&&{response_format:r}}}async function me(e,t,n){try{await v(t,n,`stream`),t.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let{data:r,providerRequestId:i}=await f(e.chat.completions.create(n,h(t.chatOptions?.signal,t.requestHeaders)));return m(await re({stream:s(r,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:t.chatOptions?.onProviderNativeRawPayload}),onTextDelta:t.chatOptions?.onTextDelta??t.onTextDelta,signal:t.chatOptions?.signal}),i)}catch(e){throw o(e,`openai`,`OpenAI stream failed`)}}async function v(e,t,n){if(!e.payloadLogger?.isEnabled())return;let r={model:t.model,messagesCount:t.messages.length,hasTools:!!t.tools,temperature:t.temperature??void 0,maxTokens:t.max_tokens??void 0,timestamp:new Date().toISOString()};await e.payloadLogger.logPayload(r,n)}function y(e){if(!e)throw Error(`OpenAI client not available. Either provide a client/apiKey or use an executor.`);return e}const he={verifiedAt:`2026-09-11`,sourceUrl:`https://platform.openai.com/docs/api-reference/responses`,models:{"gpt-5.1":{supportedEfforts:[`none`,`low`,`medium`,`high`],defaultEffort:`none`,nativeControlId:`responses.reasoning.effort`}}};var ge=class{parser;constructor(e){this.parser=new ne({logger:e})}parseResponse(e){try{return this.parser.parseResponse(e)}catch(e){let t=b(e instanceof Error?e.message:`OpenAI response parsing failed`);throw Error(`OpenAI response parsing failed: ${t}`)}}parseStreamingChunk(e){try{return this.parser.parseStreamingChunk(e)}catch(e){let t=b(e instanceof Error?e.message:`OpenAI chunk parsing failed`);throw Error(`OpenAI chunk parsing failed: ${t}`)}}};function b(e){return e.replace(/^OpenAI-compatible response parsing failed: /,``).replace(/^OpenAI-compatible chunk parsing failed: /,``).replace(`OpenAI-compatible response`,`OpenAI response`)}function _e(e){return e}function x(e,t){if(t===void 0)return e;if(t.effective===null||t.disposition===`model-default`){if(e?.effort!==void 0)throw Error(`Static reasoning.effort ${e.effort} conflicts with ${t.disposition===`model-default`?`provider-default selection`:`an effort resolution that does not apply a native control`}.`);return e}let n=_e(t.effective);if(e?.effort!==void 0&&e.effort!==n)throw Error(`Resolved effort ${n} conflicts with static reasoning.effort ${e.effort}.`);return{...e,effort:n}}function S(e){return e.flatMap(e=>w(e))}function C(e,t){let n=t??!1,r=e?.map(e=>({type:`function`,name:e.name,description:e.description,parameters:e.parameters,strict:n}))??[];return r.length>0?r:void 0}function w(e){if(e.role===`user`)return[O(`user`,E(e.content,e.parts))];if(e.role===`system`)return[O(`system`,e.content)];if(e.role===`tool`){if(!e.toolCallId||e.toolCallId.trim().length===0)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return[{type:`function_call_output`,call_id:e.toolCallId,output:e.content||``}]}return T(e)}function T(e){let t=[];e.content&&e.content.length>0&&t.push(O(`assistant`,e.content));for(let n of e.toolCalls??[])t.push({type:`function_call`,call_id:n.id,name:n.function.name,arguments:n.function.arguments});return t.length===0&&t.push(O(`assistant`,``)),t}function E(e,t){if(!t||t.length===0)return e;let n=t.map(e=>D(e));return e.length>0&&!t.some(e=>e.type===`text`)?[{type:`input_text`,text:e},...n]:n}function D(e){return e.type===`text`?{type:`input_text`,text:e.text}:e.type===`image_uri`?{type:`input_image`,image_url:e.uri}:{type:`input_image`,image_url:`data:${e.mimeType};base64,${e.data}`}}function O(e,t){return{role:e,content:t}}async function*k(e,t){let n=e[Symbol.asyncIterator]();try{for(;!t?.aborted;){let e=await A(n,t);if(e.done||t?.aborted)break;yield e.value}}finally{t?.aborted&&await n.return?.()}}async function A(e,t){if(!t)return e.next();if(t.aborted)return{done:!0,value:void 0};let n,r=new Promise(e=>{n=()=>e({done:!0,value:void 0}),t.addEventListener(`abort`,n,{once:!0})});try{return await Promise.race([e.next(),r])}finally{n&&t.removeEventListener(`abort`,n)}}function j(e){G(e);let t=e.output??[];return I({content:e.output_text??B(t),toolCalls:L(t),response:e,reasoning:V(t)})}async function M(e){let t={textParts:[],toolCalls:[],reasoning:U()};for await(let n of k(e.stream,e.signal))N(t,n,e.onTextDelta);return t.completedResponse===void 0?I({content:t.textParts.join(``),toolCalls:t.toolCalls,reasoning:t.reasoning}):F(t)}function N(e,t,n){if(t.type===`response.output_text.delta`){e.textParts.push(t.delta),n?.(t.delta);return}if(t.type===`response.completed`){e.completedResponse=t.response,W(e.reasoning,V(t.response.output??[]));return}if(t.type===`response.output_item.done`){P(e,t.item);return}if(t.type===`response.error`||t.type===`response.failed`||t.type===`response.incomplete`)throw Error(`OpenAI Responses API failed: ${Ce(t)}`)}function P(e,t){if(R(t)){e.toolCalls.push(z(t));return}H(t)&&W(e.reasoning,V([t]))}function F(e){let t=e.completedResponse;if(t===void 0)throw Error(`OpenAI Responses stream completed without response metadata`);G(t);let n=t.output??[],r=L(n),i=e.textParts.length>0?e.textParts.join(``):t.output_text??B(n),a=V(n);return W(a,e.reasoning),I({content:i,toolCalls:r.length>0?r:e.toolCalls,response:t,reasoning:a})}function I(e){return{id:c(),role:`assistant`,content:e.content,state:`complete`,timestamp:new Date,...e.toolCalls.length>0&&{toolCalls:e.toolCalls},...e.response?.usage!==void 0&&{usage:ye(e.response.usage)},metadata:{...ve(e.response,e.reasoning),...e.response?.usage!==void 0&&{usageProvenance:e.response.usage.input_tokens!==void 0&&e.response.usage.output_tokens!==void 0&&e.response.usage.total_tokens!==void 0?`complete`:`partial`}}}}function ve(e,t){return{providerApiSurface:`responses`,...e?.id!==void 0&&{responseId:e.id},...e?.model!==void 0&&{model:e.model},...e?.status!==void 0&&{finishReason:e.status},...t.reasoningSummaryCount>0&&{reasoningSummaryCount:t.reasoningSummaryCount,reasoningSummaries:t.reasoningSummaries},...t.hasEncryptedReasoning&&{hasEncryptedReasoning:!0}}}function ye(e){let t=e.input_tokens_details?.cached_tokens;return{promptTokens:e.input_tokens??0,completionTokens:e.output_tokens??0,...e.total_tokens!==void 0&&{totalTokens:e.total_tokens},...typeof t==`number`&&{cacheReadTokens:t}}}function L(e){return e.filter(R).map(e=>z(e))}function R(e){return e.type===`function_call`&&`call_id`in e&&`name`in e&&`arguments`in e}function z(e){return{id:e.call_id,type:`function`,function:{name:e.name,arguments:e.arguments}}}function B(e){return e.filter(xe).flatMap(e=>e.content).map(be).join(``)}function be(e){return e.type===`refusal`?e.refusal:e.text}function xe(e){return e.type===`message`&&`content`in e&&Array.isArray(e.content)}function V(e){let t=U();for(let n of e){if(!H(n))continue;let e=n.summary?.map(e=>e.text).filter(Se)??[];t.reasoningSummaryCount+=e.length,t.reasoningSummaries.push(...e),t.hasEncryptedReasoning=t.hasEncryptedReasoning||!!n.encrypted_content}return t}function H(e){return e.type===`reasoning`}function U(){return{reasoningSummaryCount:0,reasoningSummaries:[],hasEncryptedReasoning:!1}}function W(e,t){e.reasoningSummaryCount+=t.reasoningSummaryCount,e.reasoningSummaries.push(...t.reasoningSummaries),e.hasEncryptedReasoning=e.hasEncryptedReasoning||t.hasEncryptedReasoning}function Se(e){return e!==void 0}function G(e){if(e.status===`failed`||e.status===`incomplete`)throw Error(`OpenAI Responses API failed: ${e.error?.message??e.status}`)}function Ce(e){return e.message??e.error?.message??e.response?.error?.message??`unknown error`}async function we(e){let t=e.chatOptions?.onTextDelta??e.onTextDelta;if(t)return K({...e,chatOptions:{...e.chatOptions,onTextDelta:t}});if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=q(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let n=await e.client.responses.create(t,h(e.chatOptions?.signal,e.requestHeaders));return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`response`,payload:n}),m(j(n),p(n))}catch(e){throw o(e,`openai`,`OpenAI responses failed`)}}async function*Te(e){let t={deltas:[]},n=e.chatOptions?.onTextDelta??e.onTextDelta,r=K({...e,chatOptions:{...e.chatOptions,onTextDelta:e=>{n?.(e),ke(t,De(e))}}}).then(e=>Ae(t,e)).catch(e=>je(t,Pe(e)));yield*Oe(t),await r}async function K(e){if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=Ee(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let{data:n,providerRequestId:r}=await f(e.client.responses.create(t,h(e.chatOptions?.signal,e.requestHeaders)));return m(await M({stream:s(n,{provider:`openai`,apiSurface:`responses`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload}),onTextDelta:e.chatOptions?.onTextDelta,signal:e.chatOptions?.signal}),r)}catch(e){throw o(e,`openai`,`OpenAI responses stream failed`)}}function q(e){let t=e.chatOptions?.model??e.providerOptions.defaultModel;if(!t)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let n=C(e.chatOptions?.tools,e.providerOptions.strictTools),r=de(e.providerOptions),i=x(e.providerOptions.reasoning,e.chatOptions?.effortResolution);return{model:t,input:S(e.messages),...n!==void 0&&{tools:n,tool_choice:ce(e.chatOptions?.toolChoice)},...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_output_tokens:e.chatOptions.maxTokens},...r!==void 0&&{text:r},...i!==void 0&&{reasoning:i},...e.providerOptions.includeEncryptedReasoning===!0&&{include:[`reasoning.encrypted_content`]},...e.providerOptions.store!==void 0&&{store:e.providerOptions.store}}}function Ee(e){return{...q(e),stream:!0}}function De(e){return{id:c(),role:`assistant`,content:e,state:`complete`,timestamp:new Date,metadata:{providerApiSurface:`responses`,isStreamChunk:!0,isComplete:!1}}}async function*Oe(e){for(;;){let t=e.deltas.shift();if(t!==void 0){yield t;continue}if(e.error!==void 0)throw e.error;if(e.finalMessage!==void 0){yield Ne(e.finalMessage);return}await Me(e)}}function ke(e,t){e.deltas.push(t),J(e)}function Ae(e,t){e.finalMessage=t,J(e)}function je(e,t){e.error=t,J(e)}function Me(e){return new Promise(t=>{e.wake=t})}function J(e){e.wake?.(),e.wake=void 0}function Ne(e){return{...e,content:``,metadata:{...e.metadata,isStreamChunk:!0,isComplete:!0}}}function Pe(e){return e instanceof Error?e:Error(String(e))}var Y=class extends e{name=`openai`;version=`1.0.0`;client;options;apiSurface;payloadLogger;responseParser;onTextDelta;constructor(e){if(super(e.logger||r),this.options=e,this.apiSurface=Fe(e),Ie(this.apiSurface,e.nativeWebTools),e.executor&&(this.executor=e.executor),!this.executor)if(e.client)this.client=e.client;else if(e.apiKey)this.client=new te({apiKey:e.apiKey,...e.organization&&{organization:e.organization},...e.timeout&&{timeout:e.timeout},...e.baseURL&&{baseURL:e.baseURL}});else throw Error(`Either OpenAI client, apiKey, or executor is required`);this.responseParser=new ge(this.logger),this.payloadLogger=e.payloadLogger}async chat(e,t){this.validateMessages(e),this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=await this.executeViaExecutorOrDirect(e,n);return t.modelEffortOutcome===void 0&&this.publishModelEffortOutcome(n,`opaque-executor`),t.message}catch(e){throw this.logger.error(`OpenAI Provider executor chat error:`,e instanceof Error?e.message:String(e)),e}if(this.apiSurface===`responses`){let t=await we({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),t}let r=await fe({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),r}async*chatStream(e,t){this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=!1;for await(let r of this.executeStreamViaExecutorOrDirect(e,n))r.kind===`message`?yield r.message:t=r.modelEffortOutcome!==void 0;t||this.publishModelEffortOutcome(n,`opaque-executor`);return}catch(e){throw this.logger.error(`OpenAI Provider executor stream error:`,e instanceof Error?e.message:String(e)),e}yield*this.streamDirect(e,n)}async*streamDirect(e,t){if(this.apiSurface===`responses`){yield*Te({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t);return}yield*pe({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t)}endpointIsVendorDefault(){return this.options.baseURL===void 0}canPropagateTraceContext(){return!this.executor&&this.effectiveBaseUrl()!==void 0}effectiveBaseUrl(){let e=this.client?.baseURL;return typeof e==`string`&&e.length>0?e:void 0}traceRequestHeaders(e){return this.canPropagateTraceContext()?ee(this.effectiveBaseUrl(),e?.outboundTraceContext):{}}effortTable(){return this.endpointIsVendorDefault()&&this.apiSurface===`responses`?he:void 0}resolveEffortOptions(e){if(e?.effort===void 0||e.effortResolution!==void 0)return e;let t=e.model??this.options.defaultModel;return t===void 0?e:{...e,effortResolution:a(this.effortTable(),t,e.effort)}}projectionProfile(){return this.options.strictTools?{...n,providerName:`openai`}:{...t,providerName:`openai`}}projectChatOptions(e){if(!e?.tools)return e;let t=e.model??this.options.defaultModel??``,n=this.projectTools(e.tools,t);return{...e,tools:n&&n.length>0?n:void 0}}publishModelEffortOutcome(e,t){let n=e?.effortResolution,r=e?.onModelEffortOutcome;if(n===void 0||r===void 0)return;let a=t===void 0?n.effective!==null&&n.disposition!==`model-default`?{state:`sent`,id:`responses.reasoning.effort`}:{state:`omitted`,reason:n.disposition===`model-default`?`provider-default-selection`:`model-effort-not-applied`}:{state:`omitted`,reason:t},o=t===void 0?{state:`sent`}:{state:`not-dispatched`,reason:t};try{r(i(n,{nativeControl:a,providerDispatch:o}))}catch(e){this.logger.warn(`Model-effort outcome observer failed`,{error:e instanceof Error?e.message:String(e)})}}supportsTools(){return!0}getCapabilities(){let e=this.apiSurface===`chat-completions`?`openai-compatible-chat-completions`:`openai-responses`;return{functionCalling:{supported:!0},nativeWebTools:{webSearch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`search`)},webFetch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`fetch`)}}}}validateConfig(){return!!this.client&&!!this.options}async dispose(){}validateMessages(e){super.validateMessages(e);for(let t of e)if(t.role===`assistant`){let e=t;if(e.toolCalls&&e.toolCalls.length>0&&e.content===``)continue}}};function Fe(e){return e.apiSurface===void 0?e.baseURL?`chat-completions`:`responses`:e.apiSurface}function X(e,t){return e===`chat-completions`?`OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${t}.`:`OpenAI Responses native web ${t} is not wired in this Robota provider version.`}function Ie(e,t){if(t?.webSearch===!0||t?.webFetch===!0)throw Error(`Provider openai native web search/fetch is not supported for apiSurface ${e} in this Robota provider version.`)}var Le=class{static filterMessagesForOpenAI(e){return e.filter(e=>e.role===`user`||e.role===`assistant`||e.role===`system`||e.role===`tool`&&!!(e.toolCallId&&e.toolCallId.trim()!==``&&e.toolCallId!==`unknown`))}static toOpenAIFormat(e){return this.filterMessagesForOpenAI(e).map(e=>this.convertMessage(e))}static convertMessage(e){let t=e.role;if(t===`user`)return{role:`user`,content:e.content};if(t===`assistant`){let t=e;return t.toolCalls&&t.toolCalls.length>0?{role:`assistant`,content:t.content===``?null:t.content||null,tool_calls:t.toolCalls.map(e=>({id:e.id,type:`function`,function:{name:e.function.name,arguments:e.function.arguments}}))}:{role:`assistant`,content:t.content===null||t.content===``?null:t.content||``}}if(t===`system`)return{role:`system`,content:e.content};if(t===`tool`){if(!e.toolCallId||e.toolCallId.trim()===``)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return{role:`tool`,content:e.content,tool_call_id:e.toolCallId}}throw Error(`Unsupported message role: ${t}`)}static addSystemPromptIfNeeded(e,t){return!t||e.some(e=>e.role===`system`)?e:[{role:`system`,content:t},...e]}};const Re=void 0,Z=`$ENV:OPENAI_API_KEY`,Q=[{kind:`api-key`,label:`OpenAI API keys`,url:`https://platform.openai.com/api-keys`,sourceUrl:`https://developers.openai.com/api/reference/overview#authentication`,lastVerifiedAt:`2026-05-08`}];function ze(){return{type:`openai`,displayName:`OpenAI`,description:`GPT series — general-purpose assistant. API key required.`,category:`cloud-paid`,costPerTokenUsd:.001,defaults:{apiKey:Z},endpoint:{host:`api.openai.com`,port:443},modelCatalog:{status:`unavailable`,sourceUrl:`https://platform.openai.com/docs/api-reference/models/list`,message:`OpenAI model availability should be discovered live from GET /v1/models.`},setupHelpLinks:Q,setupSteps:[{key:`model`,title:`OpenAI model`,required:!0},{key:`apiKey`,title:`OpenAI API key`,defaultValue:Z,masked:!0}],requiresApiKey:!0,probeProfile:oe,destinationEnvironment:[`OPENAI_BASE_URL`,`OPENAI_ORG_ID`,`OPENAI_PROJECT_ID`],createProvider:e=>{let t=Ve(e.options),n=He(e.options);return Ue(e.baseURL,t,n),new Y({apiKey:Be(e.apiKey),...e.baseURL!==void 0&&{baseURL:e.baseURL},...e.timeout!==void 0&&{timeout:e.timeout},...t!==void 0&&{apiSurface:t},...n!==void 0&&{nativeWebTools:n},defaultModel:e.model})}}}function Be(e){if(!e)throw Error(`Provider openai requires apiKey`);return e}function Ve(e){let t=e?.apiSurface;if(t===`responses`||t===`chat-completions`)return t}function He(e){let t=$(e?.nativeWebTools)??$(e?.builtInWebTools);if(t!==void 0)return t}function $(e){if(e==null||e instanceof Date||Array.isArray(e)||typeof e!=`object`)return;let t=e.webSearch,n=e.webFetch;return{...typeof t==`boolean`&&{webSearch:t},...typeof n==`boolean`&&{webFetch:n}}}function Ue(e,t,n){if(n?.webSearch===!0||n?.webFetch===!0)throw Error(e!==void 0||t===`chat-completions`?`Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use Robota local WebSearch/WebFetch tools or a provider with documented hosted web support.`:`Provider openai native web search/fetch is not wired in this Robota provider version. Use Robota local WebSearch/WebFetch tools or a provider with documented hosted web support.`)}export{Z as DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,Re as DEFAULT_OPENAI_PROVIDER_MODEL,Le as OpenAIConversationAdapter,Y as OpenAIProvider,ze as createOpenAIProviderDefinition};
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{AbstractAIProvider as t,PERMISSIVE_TOOL_SCHEMA_PROFILE as n,STRICT_TOOL_SCHEMA_PROFILE as r,SilentLogger as i,createModelEffortOutcome as a,nonVisualObservationText as o,resolveModelEffort as ee,toProviderError as s,traceHeadersFor as te}from"@robota-sdk/agent-core";import ne from"openai";import{OpenAICompatibleResponseParser as re,assembleOpenAICompatibleStream as ie,convertToOpenAICompatibleMessages as ae,convertToOpenAICompatibleTools as oe,observeProviderNativeRawPayloadStream as c,probeOpenAICompatibleProfile as se,toOpenAICompatibleToolChoice as ce,toOpenAIResponsesToolChoice as le}from"@robota-sdk/agent-provider-openai-compatible/shared";function l(e){return ae(e)}function u(e,t){return oe(e,{strict:t===!0})}function ue(e,t){return t?.type===void 0?e:t.type===`json_schema`?{...e,responseFormat:`json_schema`,jsonSchema:{name:t.name??`structured_output`,schema:t.schema}}:{...e,responseFormat:t.type}}function de(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{type:`json_object`};let t=d(e);return{type:`json_schema`,json_schema:{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function fe(e){if(e.responseFormat===void 0||e.responseFormat===`text`)return;if(e.responseFormat===`json_object`)return{format:{type:`json_object`}};let t=d(e);return{format:{type:`json_schema`,name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}}function d(e){let t=e.jsonSchema;if(e.responseFormat!==`json_schema`)throw Error(`Unsupported OpenAI response format: ${e.responseFormat}`);if(!t?.schema)throw Error(`OpenAI jsonSchema.schema is required when responseFormat is json_schema`);return{name:t.name,schema:t.schema,...t.description!==void 0&&{description:t.description},...t.strict!==void 0&&{strict:t.strict}}}async function f(e){if(typeof e.withResponse==`function`){let{data:t,request_id:n}=await e.withResponse();return{data:t,...typeof n==`string`&&n.length>0&&{providerRequestId:n}}}return{data:await e}}function p(e){let t=e?._request_id;return typeof t==`string`&&t.length>0?t:void 0}function m(e,t){return t===void 0?e:{...e,metadata:{...e.metadata,providerRequestId:t}}}function h(e,t){let n=t!==void 0&&Object.keys(t).length>0;if(!(!e&&!n))return{...e?{signal:e}:{},...n?{headers:{...t}}:{}}}async function pe(e){let t=y(e.client);try{let n=_(e);if(e.chatOptions?.onTextDelta??e.onTextDelta)return await he(t,e,{...n,stream:!0,...g(e)});await v(e,n,`chat`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let r=h(e.chatOptions?.signal,e.requestHeaders),i=r?await t.chat.completions.create(n,r):await t.chat.completions.create(n);return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`response`,payload:i}),m(e.responseParser.parseResponse(i),p(i))}catch(e){throw s(e,`openai`,`OpenAI chat failed`)}}async function*me(e){let t=y(e.client);try{let n={..._(e),stream:!0,...g(e)};await v(e,n,`stream`),e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let{data:r,providerRequestId:i}=await f(t.chat.completions.create(n,h(e.chatOptions?.signal,e.requestHeaders)));for await(let t of c(r,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload})){let n=e.responseParser.parseStreamingChunk(t);n&&(yield m(n,i))}}catch(e){throw s(e,`openai`,`OpenAI stream failed`)}}function g(e){return e.providerOptions.includeStreamUsage===!1?{}:{stream_options:{include_usage:!0}}}function _(e){let t=l(e.messages),n=e.chatOptions?.model??e.providerOptions.defaultModel;if(!n)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let r=de(ue(e.providerOptions,e.chatOptions?.responseFormat));return{model:n,messages:t,...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_tokens:e.chatOptions.maxTokens},...e.chatOptions?.tools&&{tools:u(e.chatOptions.tools,e.providerOptions.strictTools),tool_choice:ce(e.chatOptions.toolChoice)},...r!==void 0&&{response_format:r}}}async function he(e,t,n){try{await v(t,n,`stream`),t.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`chat-completions`,payloadKind:`request`,payload:n});let{data:r,providerRequestId:i}=await f(e.chat.completions.create(n,h(t.chatOptions?.signal,t.requestHeaders)));return m(await ie({stream:c(r,{provider:`openai`,apiSurface:`chat-completions`,onProviderNativeRawPayload:t.chatOptions?.onProviderNativeRawPayload}),onTextDelta:t.chatOptions?.onTextDelta??t.onTextDelta,signal:t.chatOptions?.signal}),i)}catch(e){throw s(e,`openai`,`OpenAI stream failed`)}}async function v(e,t,n){if(!e.payloadLogger?.isEnabled())return;let r={model:t.model,messagesCount:t.messages.length,hasTools:!!t.tools,temperature:t.temperature??void 0,maxTokens:t.max_tokens??void 0,timestamp:new Date().toISOString()};await e.payloadLogger.logPayload(r,n)}function y(e){if(!e)throw Error(`OpenAI client not available. Either provide a client/apiKey or use an executor.`);return e}const ge={verifiedAt:`2026-09-11`,sourceUrl:`https://platform.openai.com/docs/api-reference/responses`,models:{"gpt-5.1":{supportedEfforts:[`none`,`low`,`medium`,`high`],defaultEffort:`none`,nativeControlId:`responses.reasoning.effort`}}};var _e=class{parser;constructor(e){this.parser=new re({logger:e})}parseResponse(e){try{return this.parser.parseResponse(e)}catch(e){let t=b(e instanceof Error?e.message:`OpenAI response parsing failed`);throw Error(`OpenAI response parsing failed: ${t}`)}}parseStreamingChunk(e){try{return this.parser.parseStreamingChunk(e)}catch(e){let t=b(e instanceof Error?e.message:`OpenAI chunk parsing failed`);throw Error(`OpenAI chunk parsing failed: ${t}`)}}};function b(e){return e.replace(/^OpenAI-compatible response parsing failed: /,``).replace(/^OpenAI-compatible chunk parsing failed: /,``).replace(`OpenAI-compatible response`,`OpenAI response`)}function ve(e){return e}function x(e,t){if(t===void 0)return e;if(t.effective===null||t.disposition===`model-default`){if(e?.effort!==void 0)throw Error(`Static reasoning.effort ${e.effort} conflicts with ${t.disposition===`model-default`?`provider-default selection`:`an effort resolution that does not apply a native control`}.`);return e}let n=ve(t.effective);if(e?.effort!==void 0&&e.effort!==n)throw Error(`Resolved effort ${n} conflicts with static reasoning.effort ${e.effort}.`);return{...e,effort:n}}function S(e){return e.flatMap(e=>w(e))}function C(e,t){let n=t??!1,r=e?.map(e=>({type:`function`,name:e.name,description:e.description,parameters:e.parameters,strict:n}))??[];return r.length>0?r:void 0}function w(e){if(e.role===`user`)return[O(`user`,E(e.content,e.parts))];if(e.role===`system`)return[O(`system`,e.content)];if(e.role===`tool`){if(!e.toolCallId||e.toolCallId.trim().length===0)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return[{type:`function_call_output`,call_id:e.toolCallId,output:e.parts?.length?[...e.content&&!e.parts.some(t=>t.type===`text`&&t.text===e.content)?[{type:`input_text`,text:e.content}]:[],...e.parts.map(D)]:e.content||``}]}return T(e)}function T(e){let t=[];e.content&&e.content.length>0&&t.push(O(`assistant`,e.content));for(let n of e.toolCalls??[])t.push({type:`function_call`,call_id:n.id,name:n.function.name,arguments:n.function.arguments});return t.length===0&&t.push(O(`assistant`,``)),t}function E(e,t){if(!t||t.length===0)return e;let n=t.map(e=>D(e));return e.length>0&&!t.some(e=>e.type===`text`)?[{type:`input_text`,text:e},...n]:n}function D(e){return e.type===`text`?{type:`input_text`,text:e.text}:e.type===`image_uri`?{type:`input_image`,image_url:e.uri}:e.type===`image_inline`?{type:`input_image`,image_url:`data:${e.mimeType};base64,${e.data}`}:{type:`input_text`,text:o(e)??`Unsupported observation`}}function O(e,t){return{role:e,content:t}}async function*k(e,t){let n=e[Symbol.asyncIterator]();try{for(;!t?.aborted;){let e=await A(n,t);if(e.done||t?.aborted)break;yield e.value}}finally{t?.aborted&&await n.return?.()}}async function A(e,t){if(!t)return e.next();if(t.aborted)return{done:!0,value:void 0};let n,r=new Promise(e=>{n=()=>e({done:!0,value:void 0}),t.addEventListener(`abort`,n,{once:!0})});try{return await Promise.race([e.next(),r])}finally{n&&t.removeEventListener(`abort`,n)}}function j(e){G(e);let t=e.output??[];return I({content:e.output_text??B(t),toolCalls:L(t),response:e,reasoning:V(t)})}async function M(e){let t={textParts:[],toolCalls:[],reasoning:U()};for await(let n of k(e.stream,e.signal))N(t,n,e.onTextDelta);return t.completedResponse===void 0?I({content:t.textParts.join(``),toolCalls:t.toolCalls,reasoning:t.reasoning}):F(t)}function N(e,t,n){if(t.type===`response.output_text.delta`){e.textParts.push(t.delta),n?.(t.delta);return}if(t.type===`response.completed`){e.completedResponse=t.response,W(e.reasoning,V(t.response.output??[]));return}if(t.type===`response.output_item.done`){P(e,t.item);return}if(t.type===`response.error`||t.type===`response.failed`||t.type===`response.incomplete`)throw Error(`OpenAI Responses API failed: ${we(t)}`)}function P(e,t){if(R(t)){e.toolCalls.push(z(t));return}H(t)&&W(e.reasoning,V([t]))}function F(e){let t=e.completedResponse;if(t===void 0)throw Error(`OpenAI Responses stream completed without response metadata`);G(t);let n=t.output??[],r=L(n),i=e.textParts.length>0?e.textParts.join(``):t.output_text??B(n),a=V(n);return W(a,e.reasoning),I({content:i,toolCalls:r.length>0?r:e.toolCalls,response:t,reasoning:a})}function I(t){return{id:e(),role:`assistant`,content:t.content,state:`complete`,timestamp:new Date,...t.toolCalls.length>0&&{toolCalls:t.toolCalls},...t.response?.usage!==void 0&&{usage:be(t.response.usage)},metadata:{...ye(t.response,t.reasoning),...t.response?.usage!==void 0&&{usageProvenance:t.response.usage.input_tokens!==void 0&&t.response.usage.output_tokens!==void 0&&t.response.usage.total_tokens!==void 0?`complete`:`partial`}}}}function ye(e,t){return{providerApiSurface:`responses`,...e?.id!==void 0&&{responseId:e.id},...e?.model!==void 0&&{model:e.model},...e?.status!==void 0&&{finishReason:e.status},...t.reasoningSummaryCount>0&&{reasoningSummaryCount:t.reasoningSummaryCount,reasoningSummaries:t.reasoningSummaries},...t.hasEncryptedReasoning&&{hasEncryptedReasoning:!0}}}function be(e){let t=e.input_tokens_details?.cached_tokens;return{promptTokens:e.input_tokens??0,completionTokens:e.output_tokens??0,...e.total_tokens!==void 0&&{totalTokens:e.total_tokens},...typeof t==`number`&&{cacheReadTokens:t}}}function L(e){return e.filter(R).map(e=>z(e))}function R(e){return e.type===`function_call`&&`call_id`in e&&`name`in e&&`arguments`in e}function z(e){return{id:e.call_id,type:`function`,function:{name:e.name,arguments:e.arguments}}}function B(e){return e.filter(Se).flatMap(e=>e.content).map(xe).join(``)}function xe(e){return e.type===`refusal`?e.refusal:e.text}function Se(e){return e.type===`message`&&`content`in e&&Array.isArray(e.content)}function V(e){let t=U();for(let n of e){if(!H(n))continue;let e=n.summary?.map(e=>e.text).filter(Ce)??[];t.reasoningSummaryCount+=e.length,t.reasoningSummaries.push(...e),t.hasEncryptedReasoning=t.hasEncryptedReasoning||!!n.encrypted_content}return t}function H(e){return e.type===`reasoning`}function U(){return{reasoningSummaryCount:0,reasoningSummaries:[],hasEncryptedReasoning:!1}}function W(e,t){e.reasoningSummaryCount+=t.reasoningSummaryCount,e.reasoningSummaries.push(...t.reasoningSummaries),e.hasEncryptedReasoning=e.hasEncryptedReasoning||t.hasEncryptedReasoning}function Ce(e){return e!==void 0}function G(e){if(e.status===`failed`||e.status===`incomplete`)throw Error(`OpenAI Responses API failed: ${e.error?.message??e.status}`)}function we(e){return e.message??e.error?.message??e.response?.error?.message??`unknown error`}async function Te(e){let t=e.chatOptions?.onTextDelta??e.onTextDelta;if(t)return K({...e,chatOptions:{...e.chatOptions,onTextDelta:t}});if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=q(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let n=await e.client.responses.create(t,h(e.chatOptions?.signal,e.requestHeaders));return e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`response`,payload:n}),m(j(n),p(n))}catch(e){throw s(e,`openai`,`OpenAI responses failed`)}}async function*Ee(e){let t={deltas:[]},n=e.chatOptions?.onTextDelta??e.onTextDelta,r=K({...e,chatOptions:{...e.chatOptions,onTextDelta:e=>{n?.(e),Ae(t,Oe(e))}}}).then(e=>je(t,e)).catch(e=>Me(t,Fe(e)));yield*ke(t),await r}async function K(e){if(!e.client)throw Error(`OpenAI Responses client not available.`);try{let t=De(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:`openai`,apiSurface:`responses`,payloadKind:`request`,payload:t});let{data:n,providerRequestId:r}=await f(e.client.responses.create(t,h(e.chatOptions?.signal,e.requestHeaders)));return m(await M({stream:c(n,{provider:`openai`,apiSurface:`responses`,onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload}),onTextDelta:e.chatOptions?.onTextDelta,signal:e.chatOptions?.signal}),r)}catch(e){throw s(e,`openai`,`OpenAI responses stream failed`)}}function q(e){let t=e.chatOptions?.model??e.providerOptions.defaultModel;if(!t)throw Error(`Model is required in chat options. Please specify a model in defaultModel configuration.`);let n=C(e.chatOptions?.tools,e.providerOptions.strictTools),r=fe(e.providerOptions),i=x(e.providerOptions.reasoning,e.chatOptions?.effortResolution);return{model:t,input:S(e.messages),...n!==void 0&&{tools:n,tool_choice:le(e.chatOptions?.toolChoice)},...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_output_tokens:e.chatOptions.maxTokens},...r!==void 0&&{text:r},...i!==void 0&&{reasoning:i},...e.providerOptions.includeEncryptedReasoning===!0&&{include:[`reasoning.encrypted_content`]},...e.providerOptions.store!==void 0&&{store:e.providerOptions.store}}}function De(e){return{...q(e),stream:!0}}function Oe(t){return{id:e(),role:`assistant`,content:t,state:`complete`,timestamp:new Date,metadata:{providerApiSurface:`responses`,isStreamChunk:!0,isComplete:!1}}}async function*ke(e){for(;;){let t=e.deltas.shift();if(t!==void 0){yield t;continue}if(e.error!==void 0)throw e.error;if(e.finalMessage!==void 0){yield Pe(e.finalMessage);return}await Ne(e)}}function Ae(e,t){e.deltas.push(t),J(e)}function je(e,t){e.finalMessage=t,J(e)}function Me(e,t){e.error=t,J(e)}function Ne(e){return new Promise(t=>{e.wake=t})}function J(e){e.wake?.(),e.wake=void 0}function Pe(e){return{...e,content:``,metadata:{...e.metadata,isStreamChunk:!0,isComplete:!0}}}function Fe(e){return e instanceof Error?e:Error(String(e))}var Y=class extends t{name=`openai`;version=`1.0.0`;client;options;apiSurface;payloadLogger;responseParser;onTextDelta;constructor(e){if(super(e.logger||i),this.options=e,this.apiSurface=Ie(e),Z(this.apiSurface,e.nativeWebTools),e.executor&&(this.executor=e.executor),!this.executor)if(e.client)this.client=e.client;else if(e.apiKey)this.client=new ne({apiKey:e.apiKey,...e.organization&&{organization:e.organization},...e.timeout&&{timeout:e.timeout},...e.baseURL&&{baseURL:e.baseURL}});else throw Error(`Either OpenAI client, apiKey, or executor is required`);this.responseParser=new _e(this.logger),this.payloadLogger=e.payloadLogger}async chat(e,t){this.validateMessages(e),this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=await this.executeViaExecutorOrDirect(e,n);return t.modelEffortOutcome===void 0&&this.publishModelEffortOutcome(n,`opaque-executor`),t.message}catch(e){throw this.logger.error(`OpenAI Provider executor chat error:`,e instanceof Error?e.message:String(e)),e}if(this.apiSurface===`responses`){let t=await Te({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),t}let r=await pe({client:this.client,messages:e,chatOptions:this.projectChatOptions(n),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(n)});return this.publishModelEffortOutcome(n),r}async*chatStream(e,t){this.validateNativeWebTools(t?.nativeWebTools);let n=this.resolveEffortOptions(t);if(this.executor)try{let t=!1;for await(let r of this.executeStreamViaExecutorOrDirect(e,n))r.kind===`message`?yield r.message:t=r.modelEffortOutcome!==void 0;t||this.publishModelEffortOutcome(n,`opaque-executor`);return}catch(e){throw this.logger.error(`OpenAI Provider executor stream error:`,e instanceof Error?e.message:String(e)),e}yield*this.streamDirect(e,n)}async*streamDirect(e,t){if(this.apiSurface===`responses`){yield*Ee({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t);return}yield*me({client:this.client,messages:e,chatOptions:this.projectChatOptions(t),providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta,requestHeaders:this.traceRequestHeaders(t)}),this.publishModelEffortOutcome(t)}endpointIsVendorDefault(){return this.options.baseURL===void 0}canPropagateTraceContext(){return!this.executor&&this.effectiveBaseUrl()!==void 0}effectiveBaseUrl(){let e=this.client?.baseURL;return typeof e==`string`&&e.length>0?e:void 0}traceRequestHeaders(t){return{...this.canPropagateTraceContext()?te(this.effectiveBaseUrl(),t?.outboundTraceContext):{},...this.options.durableOperations===!0?{"Idempotency-Key":e()}:{}}}effortTable(){return this.endpointIsVendorDefault()&&this.apiSurface===`responses`?ge:void 0}resolveEffortOptions(e){if(e?.effort===void 0||e.effortResolution!==void 0)return e;let t=e.model??this.options.defaultModel;return t===void 0?e:{...e,effortResolution:ee(this.effortTable(),t,e.effort)}}projectionProfile(){return this.options.strictTools?{...r,providerName:`openai`}:{...n,providerName:`openai`}}projectChatOptions(e){if(!e?.tools)return e;let t=e.model??this.options.defaultModel??``,n=this.projectTools(e.tools,t);return{...e,tools:n&&n.length>0?n:void 0}}publishModelEffortOutcome(e,t){let n=e?.effortResolution,r=e?.onModelEffortOutcome;if(n===void 0||r===void 0)return;let i=t===void 0?n.effective!==null&&n.disposition!==`model-default`?{state:`sent`,id:`responses.reasoning.effort`}:{state:`omitted`,reason:n.disposition===`model-default`?`provider-default-selection`:`model-effort-not-applied`}:{state:`omitted`,reason:t},o=t===void 0?{state:`sent`}:{state:`not-dispatched`,reason:t};try{r(a(n,{nativeControl:i,providerDispatch:o}))}catch(e){this.logger.warn(`Model-effort outcome observer failed`,{error:e instanceof Error?e.message:String(e)})}}supportsTools(){return!0}getCapabilities(){let e=this.apiSurface===`chat-completions`?`openai-compatible-chat-completions`:`openai-responses`;return{functionCalling:{supported:!0},nativeWebTools:{webSearch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`search`)},webFetch:{supported:!1,enabled:!1,source:e,reason:X(this.apiSurface,`fetch`)}}}}validateConfig(){return!!this.client&&!!this.options}async dispose(){}validateMessages(e){super.validateMessages(e);for(let t of e)if(t.role===`assistant`){let e=t;if(e.toolCalls&&e.toolCalls.length>0&&e.content===``)continue}}};function Ie(e){return e.apiSurface===void 0?e.baseURL?`chat-completions`:`responses`:e.apiSurface}function X(e,t){return e===`chat-completions`?`OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${t}.`:`OpenAI Responses native web ${t} is not wired in this provider version.`}function Z(e,t){if(t?.webSearch===!0||t?.webFetch===!0)throw Error(`Provider openai native web search/fetch is not supported for apiSurface ${e} in this provider version.`)}var Le=class{static filterMessagesForOpenAI(e){return e.filter(e=>e.role===`user`||e.role===`assistant`||e.role===`system`||e.role===`tool`&&!!(e.toolCallId&&e.toolCallId.trim()!==``&&e.toolCallId!==`unknown`))}static toOpenAIFormat(e){return this.filterMessagesForOpenAI(e).map(e=>this.convertMessage(e))}static convertMessage(e){let t=e.role;if(t===`user`)return{role:`user`,content:e.content};if(t===`assistant`){let t=e;return t.toolCalls&&t.toolCalls.length>0?{role:`assistant`,content:t.content===``?null:t.content||null,tool_calls:t.toolCalls.map(e=>({id:e.id,type:`function`,function:{name:e.function.name,arguments:e.function.arguments}}))}:{role:`assistant`,content:t.content===null||t.content===``?null:t.content||``}}if(t===`system`)return{role:`system`,content:e.content};if(t===`tool`){if(!e.toolCallId||e.toolCallId.trim()===``)throw Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return{role:`tool`,content:e.content,tool_call_id:e.toolCallId}}throw Error(`Unsupported message role: ${t}`)}static addSystemPromptIfNeeded(e,t){return!t||e.some(e=>e.role===`system`)?e:[{role:`system`,content:t},...e]}};const Re=void 0,Q=`$ENV:OPENAI_API_KEY`,ze=[{kind:`api-key`,label:`OpenAI API keys`,url:`https://platform.openai.com/api-keys`,sourceUrl:`https://developers.openai.com/api/reference/overview#authentication`,lastVerifiedAt:`2026-05-08`}];function Be(){return{type:`openai`,displayName:`OpenAI`,description:`GPT series — general-purpose assistant. API key required.`,category:`cloud-paid`,costPerTokenUsd:.001,defaults:{apiKey:Q},endpoint:{host:`api.openai.com`,port:443},modelCatalog:{status:`unavailable`,sourceUrl:`https://platform.openai.com/docs/api-reference/models/list`,message:`OpenAI model availability should be discovered live from GET /v1/models.`},setupHelpLinks:ze,setupSteps:[{key:`model`,title:`OpenAI model`,required:!0},{key:`apiKey`,title:`OpenAI API key`,defaultValue:Q,masked:!0}],requiresApiKey:!0,probeProfile:se,destinationEnvironment:[`OPENAI_BASE_URL`,`OPENAI_ORG_ID`,`OPENAI_PROJECT_ID`],createProvider:e=>{let t=He(e.options),n=Ue(e.options);return We(e.baseURL,t,n),new Y({apiKey:Ve(e.apiKey),...e.baseURL!==void 0&&{baseURL:e.baseURL},...e.timeout!==void 0&&{timeout:e.timeout},...t!==void 0&&{apiSurface:t},...n!==void 0&&{nativeWebTools:n},...e.options?.durableOperations===!0&&{durableOperations:!0},defaultModel:e.model})}}}function Ve(e){if(!e)throw Error(`Provider openai requires apiKey`);return e}function He(e){let t=e?.apiSurface;if(t===`responses`||t===`chat-completions`)return t}function Ue(e){let t=$(e?.nativeWebTools)??$(e?.builtInWebTools);if(t!==void 0)return t}function $(e){if(e==null||e instanceof Date||Array.isArray(e)||typeof e!=`object`)return;let t=e.webSearch,n=e.webFetch;return{...typeof t==`boolean`&&{webSearch:t},...typeof n==`boolean`&&{webFetch:n}}}function We(e,t,n){if(n?.webSearch===!0||n?.webFetch===!0)throw Error(e!==void 0||t===`chat-completions`?`Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.`:`Provider openai native web search/fetch is not wired in this provider version. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.`)}export{Q as DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,Re as DEFAULT_OPENAI_PROVIDER_MODEL,Le as OpenAIConversationAdapter,Y as OpenAIProvider,Be as createOpenAIProviderDefinition};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["assembleOpenAIStream","exhaustive"],"sources":["../../src/openai/message-converter.ts","../../src/openai/openai-request-format.ts","../../src/openai/request-id.ts","../../src/openai/request-options.ts","../../src/openai/chat-completions-chat.ts","../../src/openai/model-effort-table.ts","../../src/openai/parsers/response-parser.ts","../../src/openai/reasoning-effort.ts","../../src/openai/responses-converter.ts","../../src/openai/responses-stream-utils.ts","../../src/openai/responses-parser.ts","../../src/openai/responses-chat.ts","../../src/openai/provider.ts","../../src/openai/adapter.ts","../../src/openai/provider-definition.ts"],"sourcesContent":["import {\n convertToOpenAICompatibleMessages,\n convertToOpenAICompatibleTools,\n} from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport type { IToolSchema, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\n/**\n * Convert TUniversalMessage array to OpenAI chat completion message format.\n */\nexport function convertToOpenAIMessages(\n messages: TUniversalMessage[],\n): OpenAI.Chat.ChatCompletionMessageParam[] {\n return convertToOpenAICompatibleMessages(messages);\n}\n\n/**\n * Convert tool schemas to OpenAI function tool format. With `strictTools` each function is declared\n * `strict: true`, as the Responses surface does, so strict mode is requested on both surfaces.\n */\nexport function convertToOpenAITools(\n tools: IToolSchema[],\n strictTools?: boolean,\n): OpenAI.Chat.ChatCompletionTool[] {\n return convertToOpenAICompatibleTools(tools, { strict: strictTools === true });\n}\n","import type {\n IOpenAIResponsesTextConfig,\n IOpenAIResponsesTextFormatJsonSchema,\n} from './responses-types';\nimport type { IOpenAIProviderOptions, TOpenAIProviderOptionValue } from './types';\nimport type { IChatOptions } from '@robota-sdk/agent-core';\n\nexport interface IOpenAIChatTextFormatText {\n type: 'text';\n}\n\nexport interface IOpenAIChatTextFormatJsonObject {\n type: 'json_object';\n}\n\nexport interface IOpenAIChatTextFormatJsonSchema {\n type: 'json_schema';\n json_schema: {\n name: string;\n schema: Record<string, TOpenAIProviderOptionValue>;\n description?: string;\n strict?: boolean;\n };\n}\n\nexport type TOpenAIChatResponseFormat =\n IOpenAIChatTextFormatText | IOpenAIChatTextFormatJsonObject | IOpenAIChatTextFormatJsonSchema;\n\n/**\n * Merge a per-call `IChatOptions.responseFormat` onto the provider options (CORE-015).\n * A `json_schema` chat option carries its schema payload into `jsonSchema`; the\n * provider-level `jsonSchema` option remains as-is for `text`/`json_object`.\n */\nexport function mergeChatResponseFormat(\n providerOptions: IOpenAIProviderOptions,\n responseFormat: IChatOptions['responseFormat'],\n): IOpenAIProviderOptions {\n if (responseFormat?.type === undefined) {\n return providerOptions;\n }\n if (responseFormat.type === 'json_schema') {\n return {\n ...providerOptions,\n responseFormat: 'json_schema',\n jsonSchema: {\n name: responseFormat.name ?? 'structured_output',\n schema: responseFormat.schema as Record<string, TOpenAIProviderOptionValue>,\n },\n };\n }\n return { ...providerOptions, responseFormat: responseFormat.type };\n}\n\nexport function buildOpenAIChatResponseFormat(\n options: IOpenAIProviderOptions,\n): TOpenAIChatResponseFormat | undefined {\n if (options.responseFormat === undefined || options.responseFormat === 'text') {\n return undefined;\n }\n if (options.responseFormat === 'json_object') {\n return { type: 'json_object' };\n }\n\n const schema = requireJsonSchema(options);\n return {\n type: 'json_schema',\n json_schema: {\n name: schema.name,\n schema: schema.schema,\n ...(schema.description !== undefined && { description: schema.description }),\n ...(schema.strict !== undefined && { strict: schema.strict }),\n },\n };\n}\n\nexport function buildOpenAIResponsesTextConfig(\n options: IOpenAIProviderOptions,\n): IOpenAIResponsesTextConfig | undefined {\n if (options.responseFormat === undefined || options.responseFormat === 'text') {\n return undefined;\n }\n if (options.responseFormat === 'json_object') {\n return { format: { type: 'json_object' } };\n }\n\n const schema = requireJsonSchema(options);\n const format: IOpenAIResponsesTextFormatJsonSchema = {\n type: 'json_schema',\n name: schema.name,\n schema: schema.schema,\n ...(schema.description !== undefined && { description: schema.description }),\n ...(schema.strict !== undefined && { strict: schema.strict }),\n };\n return { format };\n}\n\nfunction requireJsonSchema(input: IOpenAIProviderOptions): {\n name: string;\n schema: Record<string, TOpenAIProviderOptionValue>;\n description?: string;\n strict?: boolean;\n} {\n const schema = input.jsonSchema;\n if (input.responseFormat !== 'json_schema') {\n throw new Error(`Unsupported OpenAI response format: ${input.responseFormat}`);\n }\n if (!schema?.schema) {\n throw new Error('OpenAI jsonSchema.schema is required when responseFormat is json_schema');\n }\n return {\n name: schema.name,\n schema: schema.schema,\n ...(schema.description !== undefined && { description: schema.description }),\n ...(schema.strict !== undefined && { strict: schema.strict }),\n };\n}\n","import type { TUniversalMessage } from '@robota-sdk/agent-core';\n\n/** The subset of the OpenAI SDK's `APIPromise` this module depends on. */\ninterface IWithResponseCapable<T> {\n withResponse?: () => Promise<{ data: T; request_id?: string | null }>;\n}\n\n/**\n * Await an OpenAI `create()` call, reading the server's own request ID off `.withResponse()` when\n * the client exposes it. A test double or older client that resolves to a plain value has no\n * `withResponse`, so this falls back to the awaited value with no ID — never a fabricated one.\n */\nexport async function awaitWithProviderRequestId<T>(\n call: PromiseLike<T> & IWithResponseCapable<T>,\n): Promise<{ data: T; providerRequestId?: string }> {\n if (typeof call.withResponse === 'function') {\n const { data, request_id } = await call.withResponse();\n return {\n data,\n ...(typeof request_id === 'string' && request_id.length > 0 && { providerRequestId: request_id }),\n };\n }\n return { data: await call };\n}\n\n/** The non-stream response shape the SDK attaches its own request ID to directly. */\nexport function readOpenAIRequestId(response: unknown): string | undefined {\n const id = (response as { _request_id?: string | null } | null | undefined)?._request_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/** Merge a provider-returned request ID into a message's metadata; a no-op when there isn't one. */\nexport function withProviderRequestId<T extends TUniversalMessage>(\n message: T,\n providerRequestId: string | undefined,\n): T {\n if (providerRequestId === undefined) return message;\n return { ...message, metadata: { ...message.metadata, providerRequestId } };\n}\n","import type OpenAI from 'openai';\n\n/**\n * Per-request SDK options, or none at all when there is neither a signal nor a header to send, so\n * a call without either keeps the exact shape it always had.\n */\nexport function openAIRequestOptions(\n signal: AbortSignal | undefined,\n headers: Readonly<Record<string, string>> | undefined,\n): OpenAI.RequestOptions | undefined {\n const hasHeaders = headers !== undefined && Object.keys(headers).length > 0;\n if (!signal && !hasHeaders) return undefined;\n return { ...(signal ? { signal } : {}), ...(hasHeaders ? { headers: { ...headers } } : {}) };\n}\n","import { toProviderError } from '@robota-sdk/agent-core';\nimport {\n observeProviderNativeRawPayloadStream,\n toOpenAICompatibleToolChoice,\n} from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport { convertToOpenAIMessages, convertToOpenAITools } from './message-converter';\nimport { buildOpenAIChatResponseFormat, mergeChatResponseFormat } from './openai-request-format';\nimport {\n awaitWithProviderRequestId,\n readOpenAIRequestId,\n withProviderRequestId,\n} from './request-id';\nimport { openAIRequestOptions } from './request-options';\nimport { assembleOpenAIStream } from './streaming/stream-assembler';\n\nimport type { IPayloadLogger } from './interfaces/payload-logger';\nimport type { OpenAIResponseParser } from './parsers/response-parser';\nimport type { IOpenAIProviderOptions } from './types';\nimport type { IOpenAILogData } from './types/api-types';\nimport type { IChatOptions, TTextDeltaCallback, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\nexport interface IOpenAIChatCompletionsOptions {\n client?: OpenAI;\n messages: TUniversalMessage[];\n chatOptions?: IChatOptions;\n providerOptions: IOpenAIProviderOptions;\n payloadLogger?: IPayloadLogger;\n responseParser: OpenAIResponseParser;\n onTextDelta?: TTextDeltaCallback;\n /** Per-request headers (trusted `traceparent`), sent after the raw request payload is captured. */\n requestHeaders?: Readonly<Record<string, string>>;\n}\n\nexport async function chatWithOpenAIChatCompletions(\n input: IOpenAIChatCompletionsOptions,\n): Promise<TUniversalMessage> {\n const client = requireClient(input.client);\n\n try {\n const requestParams = buildChatRequestParams(input);\n const textDeltaCb = input.chatOptions?.onTextDelta ?? input.onTextDelta;\n if (textDeltaCb) {\n return await chatWithStreamingAssembly(client, input, {\n ...requestParams,\n stream: true,\n ...buildStreamOptions(input),\n });\n }\n\n await logPayload(input, requestParams, 'chat');\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'request',\n payload: requestParams,\n });\n const requestOptions = openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders);\n const response = requestOptions\n ? await client.chat.completions.create(requestParams, requestOptions)\n : await client.chat.completions.create(requestParams);\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'response',\n payload: response,\n });\n return withProviderRequestId(\n input.responseParser.parseResponse(response),\n readOpenAIRequestId(response),\n );\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI chat failed');\n }\n}\n\nexport async function* chatStreamWithOpenAIChatCompletions(\n input: IOpenAIChatCompletionsOptions,\n): AsyncIterable<TUniversalMessage> {\n const client = requireClient(input.client);\n\n try {\n const requestParams: OpenAI.Chat.ChatCompletionCreateParamsStreaming = {\n ...buildChatRequestParams(input),\n stream: true,\n ...buildStreamOptions(input),\n };\n\n await logPayload(input, requestParams, 'stream');\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'request',\n payload: requestParams,\n });\n const { data: stream, providerRequestId } = await awaitWithProviderRequestId(\n client.chat.completions.create(\n requestParams,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n ),\n );\n\n for await (const chunk of observeProviderNativeRawPayloadStream(stream, {\n provider: 'openai',\n apiSurface: 'chat-completions',\n onProviderNativeRawPayload: input.chatOptions?.onProviderNativeRawPayload,\n })) {\n const universalMessage = input.responseParser.parseStreamingChunk(chunk);\n if (universalMessage) {\n yield withProviderRequestId(universalMessage, providerRequestId);\n }\n }\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI stream failed');\n }\n}\n\n/**\n * Streaming requests opt into token usage via `stream_options: { include_usage: true }`\n * unless the provider sets `includeStreamUsage: false`. Only ever sent on streaming requests.\n */\nfunction buildStreamOptions(\n input: IOpenAIChatCompletionsOptions,\n): { stream_options: { include_usage: true } } | Record<string, never> {\n if (input.providerOptions.includeStreamUsage === false) {\n return {};\n }\n return { stream_options: { include_usage: true } };\n}\n\nfunction buildChatRequestParams(\n input: IOpenAIChatCompletionsOptions,\n): OpenAI.Chat.ChatCompletionCreateParamsNonStreaming {\n const openaiMessages = convertToOpenAIMessages(input.messages);\n const model = input.chatOptions?.model ?? input.providerOptions.defaultModel;\n if (!model) {\n throw new Error(\n 'Model is required in chat options. Please specify a model in defaultModel configuration.',\n );\n }\n\n const responseFormat = buildOpenAIChatResponseFormat(\n mergeChatResponseFormat(input.providerOptions, input.chatOptions?.responseFormat),\n );\n return {\n model,\n messages: openaiMessages,\n ...(input.chatOptions?.temperature !== undefined && {\n temperature: input.chatOptions.temperature,\n }),\n ...(input.chatOptions?.maxTokens !== undefined && { max_tokens: input.chatOptions.maxTokens }),\n ...(input.chatOptions?.tools && {\n tools: convertToOpenAITools(input.chatOptions.tools, input.providerOptions.strictTools),\n tool_choice: toOpenAICompatibleToolChoice(input.chatOptions.toolChoice),\n }),\n ...(responseFormat !== undefined && { response_format: responseFormat }),\n } as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming;\n}\n\nasync function chatWithStreamingAssembly(\n client: OpenAI,\n input: IOpenAIChatCompletionsOptions,\n requestParams: OpenAI.Chat.ChatCompletionCreateParamsStreaming,\n): Promise<TUniversalMessage> {\n try {\n await logPayload(input, requestParams, 'stream');\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'request',\n payload: requestParams,\n });\n const { data: stream, providerRequestId } = await awaitWithProviderRequestId(\n client.chat.completions.create(\n requestParams,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n ),\n );\n\n const assembled = await assembleOpenAIStream({\n stream: observeProviderNativeRawPayloadStream(stream, {\n provider: 'openai',\n apiSurface: 'chat-completions',\n onProviderNativeRawPayload: input.chatOptions?.onProviderNativeRawPayload,\n }),\n onTextDelta: input.chatOptions?.onTextDelta ?? input.onTextDelta,\n signal: input.chatOptions?.signal,\n });\n return withProviderRequestId(assembled, providerRequestId);\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI stream failed');\n }\n}\n\nasync function logPayload(\n input: IOpenAIChatCompletionsOptions,\n requestParams:\n | OpenAI.Chat.ChatCompletionCreateParamsNonStreaming\n | OpenAI.Chat.ChatCompletionCreateParamsStreaming,\n type: 'chat' | 'stream',\n): Promise<void> {\n if (!input.payloadLogger?.isEnabled()) {\n return;\n }\n\n const logData: IOpenAILogData = {\n model: requestParams.model,\n messagesCount: requestParams.messages.length,\n hasTools: !!requestParams.tools,\n temperature: requestParams.temperature ?? undefined,\n maxTokens: requestParams.max_tokens ?? undefined,\n timestamp: new Date().toISOString(),\n };\n await input.payloadLogger.logPayload(logData, type);\n}\n\nfunction requireClient(client: OpenAI | undefined): OpenAI {\n if (!client) {\n throw new Error(\n 'OpenAI client not available. Either provide a client/apiKey or use an executor.',\n );\n }\n return client;\n}\n","import type { IProviderModelEffortTable } from '@robota-sdk/agent-core';\n\n/**\n * Exact model facts verified against OpenAI's Responses reference on 2026-09-11.\n *\n * The adapter deliberately declares no prefix or vendor-wide fallback. A different model id must\n * remain `not-applied` until its documented controls and default are added here.\n */\nexport const OPENAI_MODEL_EFFORT_TABLE: IProviderModelEffortTable = {\n verifiedAt: '2026-09-11',\n sourceUrl: 'https://platform.openai.com/docs/api-reference/responses',\n models: {\n 'gpt-5.1': {\n supportedEfforts: ['none', 'low', 'medium', 'high'],\n defaultEffort: 'none',\n nativeControlId: 'responses.reasoning.effort',\n },\n },\n};\n","import { OpenAICompatibleResponseParser } from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport type { ILogger, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\n/**\n * OpenAI response parser compatibility wrapper.\n *\n * The implementation delegates to the shared OpenAI-compatible parser while\n * preserving the OpenAI-branded error messages that are part of this package's\n * current test contract.\n */\nexport class OpenAIResponseParser {\n private readonly parser: OpenAICompatibleResponseParser;\n\n constructor(logger?: ILogger) {\n this.parser = new OpenAICompatibleResponseParser({ logger });\n }\n\n parseResponse(response: OpenAI.Chat.ChatCompletion): TUniversalMessage {\n try {\n return this.parser.parseResponse(response);\n } catch (error) {\n const message = normalizeParserMessage(\n error instanceof Error ? error.message : 'OpenAI response parsing failed',\n );\n throw new Error(`OpenAI response parsing failed: ${message}`);\n }\n }\n\n parseStreamingChunk(chunk: OpenAI.Chat.ChatCompletionChunk): TUniversalMessage | null {\n try {\n return this.parser.parseStreamingChunk(chunk);\n } catch (error) {\n const message = normalizeParserMessage(\n error instanceof Error ? error.message : 'OpenAI chunk parsing failed',\n );\n throw new Error(`OpenAI chunk parsing failed: ${message}`);\n }\n }\n}\n\nfunction normalizeParserMessage(message: string): string {\n return message\n .replace(/^OpenAI-compatible response parsing failed: /, '')\n .replace(/^OpenAI-compatible chunk parsing failed: /, '')\n .replace('OpenAI-compatible response', 'OpenAI response');\n}\n","import type { IOpenAIResponsesReasoningOptions } from './types';\nimport type { IModelEffortResolution, TModelEffort } from '@robota-sdk/agent-core';\n\n/**\n * Map the framework's per-call reasoning-effort dial onto the OpenAI Responses API\n * `reasoning.effort` parameter.\n *\n * Per-model support and downward clamping are resolved by the Core table before this boundary.\n * This function only serializes the verified concrete value, without reinterpreting it.\n */\nexport function mapEffortToOpenAIReasoningEffort(\n effort: TModelEffort,\n): IOpenAIResponsesReasoningOptions['effort'] {\n return effort;\n}\n\n/**\n * Merge the per-call effort dial into the provider's static reasoning options.\n *\n * A verified concrete resolution takes precedence over static native control; a conflicting static\n * control is rejected rather than silently overwritten. `auto` and `not-applied` resolutions leave\n * the provider default untouched and never manufacture a native effort field.\n */\nexport function resolveOpenAIReasoningOptions(\n staticReasoning: IOpenAIResponsesReasoningOptions | undefined,\n resolution: IModelEffortResolution | undefined,\n): IOpenAIResponsesReasoningOptions | undefined {\n if (resolution === undefined) {\n return staticReasoning;\n }\n if (resolution.effective === null || resolution.disposition === 'model-default') {\n if (staticReasoning?.effort !== undefined) {\n throw new Error(\n `Static reasoning.effort ${staticReasoning.effort} conflicts with ${resolution.disposition === 'model-default' ? 'provider-default selection' : 'an effort resolution that does not apply a native control'}.`,\n );\n }\n return staticReasoning;\n }\n const effort = mapEffortToOpenAIReasoningEffort(resolution.effective);\n if (staticReasoning?.effort !== undefined && staticReasoning.effort !== effort) {\n throw new Error(\n `Resolved effort ${effort} conflicts with static reasoning.effort ${staticReasoning.effort}.`,\n );\n }\n return {\n ...staticReasoning,\n effort,\n };\n}\n","import type {\n IOpenAIResponsesFunctionTool,\n IOpenAIResponsesMessageInput,\n TOpenAIResponsesInputContent,\n TOpenAIResponsesInputItem,\n} from './responses-types';\nimport type {\n IAssistantMessage,\n IToolSchema,\n TUniversalMessage,\n TUniversalMessagePart,\n} from '@robota-sdk/agent-core';\n\nexport function convertToOpenAIResponsesInput(\n messages: TUniversalMessage[],\n): TOpenAIResponsesInputItem[] {\n return messages.flatMap((message) => convertMessage(message));\n}\n\n/**\n * MCP-005: `tools` arrives ALREADY projected — `AbstractAIProvider.projectTools()` ran the strict or\n * permissive profile (`STRICT_TOOL_SCHEMA_PROFILE` / `PERMISSIVE_TOOL_SCHEMA_PROFILE`) over every\n * schema before this converter ever sees it, closing objects for strict mode where PROV-007's\n * `closeObjectSchemas` used to run inline here. This function does no schema transformation of its\n * own — it only shapes the already-projected `parameters` into the wire tool definition and keeps\n * `strict: true` on the emitted field when `strictTools` is on (a request-field concern, not a schema\n * one: the schema was already closed by the projection step).\n */\nexport function convertToOpenAIResponsesTools(\n tools: IToolSchema[] | undefined,\n strictTools: boolean | undefined,\n): IOpenAIResponsesFunctionTool[] | undefined {\n const strict = strictTools ?? false;\n const converted =\n tools?.map((tool) => ({\n type: 'function' as const,\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n strict,\n })) ?? [];\n return converted.length > 0 ? converted : undefined;\n}\n\nfunction convertMessage(message: TUniversalMessage): TOpenAIResponsesInputItem[] {\n if (message.role === 'user') {\n return [createMessageInput('user', getUserContent(message.content, message.parts))];\n }\n if (message.role === 'system') {\n return [createMessageInput('system', message.content)];\n }\n if (message.role === 'tool') {\n if (!message.toolCallId || message.toolCallId.trim().length === 0) {\n throw new Error(`Tool message missing toolCallId: ${JSON.stringify(message)}`);\n }\n return [\n {\n type: 'function_call_output',\n call_id: message.toolCallId,\n output: message.content || '',\n },\n ];\n }\n return convertAssistantMessage(message);\n}\n\nfunction convertAssistantMessage(message: IAssistantMessage): TOpenAIResponsesInputItem[] {\n const items: TOpenAIResponsesInputItem[] = [];\n if (message.content && message.content.length > 0) {\n items.push(createMessageInput('assistant', message.content));\n }\n for (const toolCall of message.toolCalls ?? []) {\n items.push({\n type: 'function_call',\n call_id: toolCall.id,\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n });\n }\n if (items.length === 0) {\n items.push(createMessageInput('assistant', ''));\n }\n return items;\n}\n\nfunction getUserContent(\n content: string,\n parts: TUniversalMessagePart[] | undefined,\n): string | TOpenAIResponsesInputContent[] {\n if (!parts || parts.length === 0) {\n return content;\n }\n\n const converted = parts.map((part) => convertPart(part));\n if (content.length > 0 && !parts.some((part) => part.type === 'text')) {\n return [{ type: 'input_text', text: content }, ...converted];\n }\n return converted;\n}\n\nfunction convertPart(part: TUniversalMessagePart): TOpenAIResponsesInputContent {\n if (part.type === 'text') {\n return { type: 'input_text', text: part.text };\n }\n if (part.type === 'image_uri') {\n return { type: 'input_image', image_url: part.uri };\n }\n return {\n type: 'input_image',\n image_url: `data:${part.mimeType};base64,${part.data}`,\n };\n}\n\nfunction createMessageInput(\n role: IOpenAIResponsesMessageInput['role'],\n content: string | TOpenAIResponsesInputContent[],\n): IOpenAIResponsesMessageInput {\n return {\n role,\n content,\n };\n}\n","export async function* streamWithAbort<T>(\n source: AsyncIterable<T>,\n signal?: AbortSignal,\n): AsyncGenerator<T> {\n const iterator = source[Symbol.asyncIterator]();\n try {\n while (!signal?.aborted) {\n const item = await nextStreamItem(iterator, signal);\n if (item.done || signal?.aborted) {\n break;\n }\n yield item.value;\n }\n } finally {\n if (signal?.aborted) {\n await iterator.return?.();\n }\n }\n}\n\nasync function nextStreamItem<T>(\n iterator: AsyncIterator<T>,\n signal?: AbortSignal,\n): Promise<IteratorResult<T>> {\n if (!signal) {\n return iterator.next();\n }\n if (signal.aborted) {\n return { done: true, value: undefined as T };\n }\n\n let abortListener: (() => void) | undefined;\n const aborted = new Promise<IteratorResult<T>>((resolve) => {\n abortListener = (): void => resolve({ done: true, value: undefined as T });\n signal.addEventListener('abort', abortListener, { once: true });\n });\n\n try {\n return await Promise.race([iterator.next(), aborted]);\n } finally {\n if (abortListener) {\n signal.removeEventListener('abort', abortListener);\n }\n }\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { streamWithAbort } from './responses-stream-utils';\n\nimport type {\n IOpenAIResponsesErrorEvent,\n IOpenAIResponsesFunctionCallOutputItem,\n IOpenAIResponsesMessageOutputItem,\n IOpenAIResponsesReasoningOutputItem,\n IOpenAIResponsesResponse,\n IOpenAIResponsesUsage,\n TOpenAIResponsesOutputContent,\n TOpenAIResponsesOutputItem,\n TOpenAIResponsesStreamEvent,\n} from './responses-types';\nimport type {\n IToolCall,\n ITokenUsageWithCacheRead,\n TTextDeltaCallback,\n TUniversalMessage,\n} from '@robota-sdk/agent-core';\n\n/** Message usage; `totalTokens` is absent when the response omitted `total_tokens`. */\ntype TResponsesMessageUsage = Omit<ITokenUsageWithCacheRead, 'totalTokens'> &\n Partial<Pick<ITokenUsageWithCacheRead, 'totalTokens'>>;\n\ninterface IOpenAIResponsesStreamAssemblyOptions {\n stream: AsyncIterable<TOpenAIResponsesStreamEvent>;\n onTextDelta?: TTextDeltaCallback;\n signal?: AbortSignal;\n}\n\ninterface IOpenAIResponsesReasoningMetadata {\n reasoningSummaryCount: number;\n reasoningSummaries: string[];\n hasEncryptedReasoning: boolean;\n}\n\ninterface IOpenAIResponsesStreamState {\n textParts: string[];\n toolCalls: IToolCall[];\n completedResponse?: IOpenAIResponsesResponse;\n reasoning: IOpenAIResponsesReasoningMetadata;\n}\n\nexport function parseOpenAIResponsesResponse(\n response: IOpenAIResponsesResponse,\n): TUniversalMessage {\n assertUsableResponse(response);\n const output = response.output ?? [];\n const content = response.output_text ?? extractMessageText(output);\n return buildAssistantMessage({\n content,\n toolCalls: extractFunctionToolCalls(output),\n response,\n reasoning: collectReasoningMetadata(output),\n });\n}\n\nexport async function assembleOpenAIResponsesStream(\n options: IOpenAIResponsesStreamAssemblyOptions,\n): Promise<TUniversalMessage> {\n const state: IOpenAIResponsesStreamState = {\n textParts: [],\n toolCalls: [],\n reasoning: createEmptyReasoningMetadata(),\n };\n\n for await (const event of streamWithAbort(options.stream, options.signal)) {\n applyStreamEvent(state, event, options.onTextDelta);\n }\n\n if (state.completedResponse !== undefined) {\n return buildMessageFromCompletedResponse(state);\n }\n\n return buildAssistantMessage({\n content: state.textParts.join(''),\n toolCalls: state.toolCalls,\n reasoning: state.reasoning,\n });\n}\n\nfunction applyStreamEvent(\n state: IOpenAIResponsesStreamState,\n event: TOpenAIResponsesStreamEvent,\n onTextDelta: TTextDeltaCallback | undefined,\n): void {\n if (event.type === 'response.output_text.delta') {\n state.textParts.push(event.delta);\n onTextDelta?.(event.delta);\n return;\n }\n\n if (event.type === 'response.completed') {\n state.completedResponse = event.response;\n mergeReasoningMetadata(state.reasoning, collectReasoningMetadata(event.response.output ?? []));\n return;\n }\n\n if (event.type === 'response.output_item.done') {\n applyOutputItem(state, event.item);\n return;\n }\n\n if (\n event.type === 'response.error' ||\n event.type === 'response.failed' ||\n event.type === 'response.incomplete'\n ) {\n throw new Error(`OpenAI Responses API failed: ${extractErrorMessage(event)}`);\n }\n}\n\nfunction applyOutputItem(\n state: IOpenAIResponsesStreamState,\n item: TOpenAIResponsesOutputItem,\n): void {\n if (isFunctionCallOutputItem(item)) {\n state.toolCalls.push(convertFunctionCall(item));\n return;\n }\n if (isReasoningOutputItem(item)) {\n mergeReasoningMetadata(state.reasoning, collectReasoningMetadata([item]));\n }\n}\n\nfunction buildMessageFromCompletedResponse(state: IOpenAIResponsesStreamState): TUniversalMessage {\n const response = state.completedResponse;\n if (response === undefined) {\n throw new Error('OpenAI Responses stream completed without response metadata');\n }\n\n assertUsableResponse(response);\n const output = response.output ?? [];\n const responseToolCalls = extractFunctionToolCalls(output);\n const content =\n state.textParts.length > 0\n ? state.textParts.join('')\n : (response.output_text ?? extractMessageText(output));\n const reasoning = collectReasoningMetadata(output);\n mergeReasoningMetadata(reasoning, state.reasoning);\n\n return buildAssistantMessage({\n content,\n toolCalls: responseToolCalls.length > 0 ? responseToolCalls : state.toolCalls,\n response,\n reasoning,\n });\n}\n\nfunction buildAssistantMessage(input: {\n content: string;\n toolCalls: IToolCall[];\n response?: IOpenAIResponsesResponse;\n reasoning: IOpenAIResponsesReasoningMetadata;\n}): TUniversalMessage {\n return {\n id: randomUUID(),\n role: 'assistant',\n content: input.content,\n state: 'complete',\n timestamp: new Date(),\n ...(input.toolCalls.length > 0 && { toolCalls: input.toolCalls }),\n ...(input.response?.usage !== undefined && { usage: mapUsage(input.response.usage) }),\n metadata: {\n ...buildMetadata(input.response, input.reasoning),\n ...(input.response?.usage !== undefined && {\n usageProvenance:\n input.response.usage.input_tokens !== undefined &&\n input.response.usage.output_tokens !== undefined &&\n input.response.usage.total_tokens !== undefined\n ? 'complete'\n : 'partial',\n }),\n },\n };\n}\n\nfunction buildMetadata(\n response: IOpenAIResponsesResponse | undefined,\n reasoning: IOpenAIResponsesReasoningMetadata,\n): NonNullable<TUniversalMessage['metadata']> {\n return {\n providerApiSurface: 'responses',\n ...(response?.id !== undefined && { responseId: response.id }),\n ...(response?.model !== undefined && { model: response.model }),\n ...(response?.status !== undefined && { finishReason: response.status }),\n ...(reasoning.reasoningSummaryCount > 0 && {\n reasoningSummaryCount: reasoning.reasoningSummaryCount,\n reasoningSummaries: reasoning.reasoningSummaries,\n }),\n ...(reasoning.hasEncryptedReasoning && { hasEncryptedReasoning: true }),\n };\n}\n\nfunction mapUsage(usage: IOpenAIResponsesUsage): TResponsesMessageUsage {\n const cachedTokens = usage.input_tokens_details?.cached_tokens;\n return {\n promptTokens: usage.input_tokens ?? 0,\n completionTokens: usage.output_tokens ?? 0,\n // An omitted total stays omitted: a 0 reads downstream as a real, empty call.\n ...(usage.total_tokens !== undefined && { totalTokens: usage.total_tokens }),\n ...(typeof cachedTokens === 'number' && { cacheReadTokens: cachedTokens }),\n };\n}\n\nfunction extractFunctionToolCalls(output: readonly TOpenAIResponsesOutputItem[]): IToolCall[] {\n return output.filter(isFunctionCallOutputItem).map((item) => convertFunctionCall(item));\n}\n\nfunction isFunctionCallOutputItem(\n item: TOpenAIResponsesOutputItem,\n): item is IOpenAIResponsesFunctionCallOutputItem {\n return (\n item.type === 'function_call' && 'call_id' in item && 'name' in item && 'arguments' in item\n );\n}\n\nfunction convertFunctionCall(item: IOpenAIResponsesFunctionCallOutputItem): IToolCall {\n return {\n id: item.call_id,\n type: 'function',\n function: {\n name: item.name,\n arguments: item.arguments,\n },\n };\n}\n\nfunction extractMessageText(output: readonly TOpenAIResponsesOutputItem[]): string {\n return output\n .filter(isMessageOutputItem)\n .flatMap((item) => item.content)\n .map(extractTextContent)\n .join('');\n}\n\nfunction extractTextContent(content: TOpenAIResponsesOutputContent): string {\n if (content.type === 'refusal') {\n return content.refusal;\n }\n return content.text;\n}\n\nfunction isMessageOutputItem(\n item: TOpenAIResponsesOutputItem,\n): item is IOpenAIResponsesMessageOutputItem {\n return item.type === 'message' && 'content' in item && Array.isArray(item.content);\n}\n\nfunction collectReasoningMetadata(\n output: readonly TOpenAIResponsesOutputItem[],\n): IOpenAIResponsesReasoningMetadata {\n const metadata = createEmptyReasoningMetadata();\n for (const item of output) {\n if (!isReasoningOutputItem(item)) {\n continue;\n }\n const summaries = item.summary?.map((summary) => summary.text).filter(isString) ?? [];\n metadata.reasoningSummaryCount += summaries.length;\n metadata.reasoningSummaries.push(...summaries);\n metadata.hasEncryptedReasoning = metadata.hasEncryptedReasoning || !!item.encrypted_content;\n }\n return metadata;\n}\n\nfunction isReasoningOutputItem(\n item: TOpenAIResponsesOutputItem,\n): item is IOpenAIResponsesReasoningOutputItem {\n return item.type === 'reasoning';\n}\n\nfunction createEmptyReasoningMetadata(): IOpenAIResponsesReasoningMetadata {\n return {\n reasoningSummaryCount: 0,\n reasoningSummaries: [],\n hasEncryptedReasoning: false,\n };\n}\n\nfunction mergeReasoningMetadata(\n target: IOpenAIResponsesReasoningMetadata,\n source: IOpenAIResponsesReasoningMetadata,\n): void {\n target.reasoningSummaryCount += source.reasoningSummaryCount;\n target.reasoningSummaries.push(...source.reasoningSummaries);\n target.hasEncryptedReasoning = target.hasEncryptedReasoning || source.hasEncryptedReasoning;\n}\n\nfunction isString(value: string | undefined): value is string {\n return value !== undefined;\n}\n\nfunction assertUsableResponse(response: IOpenAIResponsesResponse): void {\n if (response.status === 'failed' || response.status === 'incomplete') {\n throw new Error(`OpenAI Responses API failed: ${response.error?.message ?? response.status}`);\n }\n}\n\nfunction extractErrorMessage(event: IOpenAIResponsesErrorEvent): string {\n return event.message ?? event.error?.message ?? event.response?.error?.message ?? 'unknown error';\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { toProviderError } from '@robota-sdk/agent-core';\n\nimport {\n observeProviderNativeRawPayloadStream,\n toOpenAIResponsesToolChoice,\n} from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport { buildOpenAIResponsesTextConfig } from './openai-request-format';\nimport { resolveOpenAIReasoningOptions } from './reasoning-effort';\nimport {\n awaitWithProviderRequestId,\n readOpenAIRequestId,\n withProviderRequestId,\n} from './request-id';\nimport {\n convertToOpenAIResponsesInput,\n convertToOpenAIResponsesTools,\n} from './responses-converter';\nimport { openAIRequestOptions } from './request-options';\nimport { assembleOpenAIResponsesStream, parseOpenAIResponsesResponse } from './responses-parser';\n\nimport type {\n IOpenAIResponsesRequestNonStreaming,\n IOpenAIResponsesRequestStreaming,\n TOpenAIResponsesStreamEvent,\n} from './responses-types';\nimport type { IOpenAIProviderOptions } from './types';\nimport type { IChatOptions, TTextDeltaCallback, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\nexport interface IOpenAIResponsesChatOptions {\n client?: OpenAI;\n messages: TUniversalMessage[];\n chatOptions?: IChatOptions;\n providerOptions: IOpenAIProviderOptions;\n onTextDelta?: TTextDeltaCallback;\n /** Per-request headers (trusted `traceparent`), sent after the raw request payload is captured. */\n requestHeaders?: Readonly<Record<string, string>>;\n}\n\ninterface IResponsesStreamMessageQueue {\n deltas: TUniversalMessage[];\n finalMessage?: TUniversalMessage;\n error?: Error;\n wake?: () => void;\n}\n\nexport async function chatWithOpenAIResponsesApi(\n input: IOpenAIResponsesChatOptions,\n): Promise<TUniversalMessage> {\n const textDeltaCb = input.chatOptions?.onTextDelta ?? input.onTextDelta;\n if (textDeltaCb) {\n return chatWithOpenAIResponsesStreamingAssembly({\n ...input,\n chatOptions: {\n ...input.chatOptions,\n onTextDelta: textDeltaCb,\n },\n });\n }\n\n if (!input.client) {\n throw new Error('OpenAI Responses client not available.');\n }\n\n try {\n const requestParams = buildResponsesRequestParams(input);\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'responses',\n payloadKind: 'request',\n payload: requestParams,\n });\n const response = await input.client.responses.create(\n requestParams as OpenAI.Responses.ResponseCreateParamsNonStreaming,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n );\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'responses',\n payloadKind: 'response',\n payload: response,\n });\n return withProviderRequestId(\n parseOpenAIResponsesResponse(response),\n readOpenAIRequestId(response),\n );\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI responses failed');\n }\n}\n\nexport async function* chatStreamWithOpenAIResponsesApi(\n input: IOpenAIResponsesChatOptions,\n): AsyncIterable<TUniversalMessage> {\n const queue: IResponsesStreamMessageQueue = { deltas: [] };\n const textDeltaCb = input.chatOptions?.onTextDelta ?? input.onTextDelta;\n const assembly = chatWithOpenAIResponsesStreamingAssembly({\n ...input,\n chatOptions: {\n ...input.chatOptions,\n onTextDelta: (delta) => {\n textDeltaCb?.(delta);\n enqueueStreamDelta(queue, createStreamDeltaMessage(delta));\n },\n },\n })\n .then((result) => finishStreamQueue(queue, result))\n .catch((error) => failStreamQueue(queue, toError(error)));\n\n yield* drainResponsesStreamQueue(queue);\n await assembly;\n}\n\nasync function chatWithOpenAIResponsesStreamingAssembly(\n input: IOpenAIResponsesChatOptions,\n): Promise<TUniversalMessage> {\n if (!input.client) {\n throw new Error('OpenAI Responses client not available.');\n }\n\n try {\n const requestParams = buildResponsesStreamingRequestParams(input);\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'responses',\n payloadKind: 'request',\n payload: requestParams,\n });\n const { data: stream, providerRequestId } = await awaitWithProviderRequestId(\n input.client.responses.create(\n requestParams as OpenAI.Responses.ResponseCreateParamsStreaming,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n ),\n );\n const assembled = await assembleOpenAIResponsesStream({\n stream: observeProviderNativeRawPayloadStream(\n stream as AsyncIterable<TOpenAIResponsesStreamEvent>,\n {\n provider: 'openai',\n apiSurface: 'responses',\n onProviderNativeRawPayload: input.chatOptions?.onProviderNativeRawPayload,\n },\n ),\n onTextDelta: input.chatOptions?.onTextDelta,\n signal: input.chatOptions?.signal,\n });\n return withProviderRequestId(assembled, providerRequestId);\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI responses stream failed');\n }\n}\n\nfunction buildResponsesRequestParams(\n input: IOpenAIResponsesChatOptions,\n): IOpenAIResponsesRequestNonStreaming {\n const model = input.chatOptions?.model ?? input.providerOptions.defaultModel;\n if (!model) {\n throw new Error(\n 'Model is required in chat options. Please specify a model in defaultModel configuration.',\n );\n }\n\n const tools = convertToOpenAIResponsesTools(\n input.chatOptions?.tools,\n input.providerOptions.strictTools,\n );\n const textConfig = buildOpenAIResponsesTextConfig(input.providerOptions);\n // Native effort mapping: thread the per-call reasoning-effort dial onto the Responses\n // API `reasoning.effort` parameter, merged with any static reasoning options.\n const reasoning = resolveOpenAIReasoningOptions(\n input.providerOptions.reasoning,\n input.chatOptions?.effortResolution,\n );\n return {\n model,\n input: convertToOpenAIResponsesInput(input.messages),\n ...(tools !== undefined && {\n tools,\n tool_choice: toOpenAIResponsesToolChoice(input.chatOptions?.toolChoice),\n }),\n ...(input.chatOptions?.temperature !== undefined && {\n temperature: input.chatOptions.temperature,\n }),\n ...(input.chatOptions?.maxTokens !== undefined && {\n max_output_tokens: input.chatOptions.maxTokens,\n }),\n ...(textConfig !== undefined && { text: textConfig }),\n ...(reasoning !== undefined && {\n reasoning,\n }),\n ...(input.providerOptions.includeEncryptedReasoning === true && {\n include: ['reasoning.encrypted_content'],\n }),\n ...(input.providerOptions.store !== undefined && { store: input.providerOptions.store }),\n };\n}\n\nfunction buildResponsesStreamingRequestParams(\n input: IOpenAIResponsesChatOptions,\n): IOpenAIResponsesRequestStreaming {\n return {\n ...buildResponsesRequestParams(input),\n stream: true,\n };\n}\n\nfunction createStreamDeltaMessage(delta: string): TUniversalMessage {\n return {\n id: randomUUID(),\n role: 'assistant',\n content: delta,\n state: 'complete',\n timestamp: new Date(),\n metadata: {\n providerApiSurface: 'responses',\n isStreamChunk: true,\n isComplete: false,\n },\n };\n}\n\nasync function* drainResponsesStreamQueue(\n queue: IResponsesStreamMessageQueue,\n): AsyncIterable<TUniversalMessage> {\n while (true) {\n const next = queue.deltas.shift();\n if (next !== undefined) {\n yield next;\n continue;\n }\n if (queue.error !== undefined) {\n throw queue.error;\n }\n if (queue.finalMessage !== undefined) {\n yield createFinalStreamMessage(queue.finalMessage);\n return;\n }\n await waitForStreamQueue(queue);\n }\n}\n\nfunction enqueueStreamDelta(queue: IResponsesStreamMessageQueue, message: TUniversalMessage): void {\n queue.deltas.push(message);\n wakeStreamQueue(queue);\n}\n\nfunction finishStreamQueue(queue: IResponsesStreamMessageQueue, result: TUniversalMessage): void {\n queue.finalMessage = result;\n wakeStreamQueue(queue);\n}\n\nfunction failStreamQueue(queue: IResponsesStreamMessageQueue, error: Error): void {\n queue.error = error;\n wakeStreamQueue(queue);\n}\n\nfunction waitForStreamQueue(queue: IResponsesStreamMessageQueue): Promise<void> {\n return new Promise((resolve) => {\n queue.wake = resolve;\n });\n}\n\nfunction wakeStreamQueue(queue: IResponsesStreamMessageQueue): void {\n queue.wake?.();\n queue.wake = undefined;\n}\n\nfunction createFinalStreamMessage(result: TUniversalMessage): TUniversalMessage {\n return {\n ...result,\n content: '',\n metadata: {\n ...result.metadata,\n isStreamChunk: true,\n isComplete: true,\n },\n };\n}\n\nfunction toError(error: Error | string): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n","import { AbstractAIProvider } from '@robota-sdk/agent-core';\nimport { createModelEffortOutcome } from '@robota-sdk/agent-core';\nimport { PERMISSIVE_TOOL_SCHEMA_PROFILE, STRICT_TOOL_SCHEMA_PROFILE } from '@robota-sdk/agent-core';\nimport { resolveModelEffort } from '@robota-sdk/agent-core';\nimport { SilentLogger } from '@robota-sdk/agent-core';\nimport { traceHeadersFor } from '@robota-sdk/agent-core';\nimport OpenAI from 'openai';\n\nimport {\n chatStreamWithOpenAIChatCompletions,\n chatWithOpenAIChatCompletions,\n} from './chat-completions-chat';\nimport { OPENAI_MODEL_EFFORT_TABLE } from './model-effort-table';\nimport { OpenAIResponseParser } from './parsers/response-parser';\nimport { chatStreamWithOpenAIResponsesApi, chatWithOpenAIResponsesApi } from './responses-chat';\n\nimport type { IPayloadLogger } from './interfaces/payload-logger';\nimport type { IOpenAIProviderOptions, TOpenAIApiSurface } from './types';\nimport type {\n TUniversalMessage,\n IChatOptions,\n IAssistantMessage,\n IProviderCapabilities,\n IProviderModelEffortTable,\n IToolSchemaProjectionProfile,\n TTextDeltaCallback,\n} from '@robota-sdk/agent-core';\n\n/**\n * OpenAI provider implementation for Robota\n *\n * Provides integration with OpenAI models through the Robota provider contract.\n * Uses OpenAI SDK native types internally for optimal performance and feature support.\n *\n * @public\n */\nexport class OpenAIProvider extends AbstractAIProvider {\n override readonly name = 'openai';\n override readonly version = '1.0.0';\n\n private readonly client?: OpenAI;\n private readonly options: IOpenAIProviderOptions;\n private readonly apiSurface: TOpenAIApiSurface;\n private readonly payloadLogger: IPayloadLogger | undefined;\n private readonly responseParser: OpenAIResponseParser;\n\n /**\n * Optional callback for text deltas during streaming.\n * Set by the consumer (e.g., Session) to receive real-time text chunks.\n * When set, chat() uses streaming internally while still returning\n * the complete assembled message.\n */\n onTextDelta?: TTextDeltaCallback;\n\n constructor(options: IOpenAIProviderOptions) {\n super(options.logger || SilentLogger);\n this.options = options;\n this.apiSurface = resolveApiSurface(options);\n validateOpenAIProviderNativeWebTools(this.apiSurface, options.nativeWebTools);\n\n if (options.executor) {\n this.executor = options.executor;\n }\n\n if (!this.executor) {\n if (options.client) {\n this.client = options.client;\n } else if (options.apiKey) {\n this.client = new OpenAI({\n apiKey: options.apiKey,\n ...(options.organization && { organization: options.organization }),\n ...(options.timeout && { timeout: options.timeout }),\n ...(options.baseURL && { baseURL: options.baseURL }),\n });\n } else {\n throw new Error('Either OpenAI client, apiKey, or executor is required');\n }\n }\n\n this.responseParser = new OpenAIResponseParser(this.logger);\n this.payloadLogger = options.payloadLogger;\n }\n\n override async chat(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): Promise<TUniversalMessage> {\n this.validateMessages(messages);\n this.validateNativeWebTools(options?.nativeWebTools);\n const resolvedOptions = this.resolveEffortOptions(options);\n\n if (this.executor) {\n try {\n const result = await this.executeViaExecutorOrDirect(messages, resolvedOptions);\n if (result.modelEffortOutcome === undefined) {\n this.publishModelEffortOutcome(resolvedOptions, 'opaque-executor');\n }\n return result.message;\n } catch (error) {\n this.logger.error(\n 'OpenAI Provider executor chat error:',\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n }\n }\n\n if (this.apiSurface === 'responses') {\n const response = await chatWithOpenAIResponsesApi({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n return response;\n }\n\n const response = await chatWithOpenAIChatCompletions({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n payloadLogger: this.payloadLogger,\n responseParser: this.responseParser,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n return response;\n }\n\n override async *chatStream(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TUniversalMessage> {\n this.validateNativeWebTools(options?.nativeWebTools);\n const resolvedOptions = this.resolveEffortOptions(options);\n\n if (this.executor) {\n try {\n let executorOutcomeSeen = false;\n for await (const event of this.executeStreamViaExecutorOrDirect(\n messages,\n resolvedOptions,\n )) {\n if (event.kind === 'message') {\n yield event.message;\n } else {\n executorOutcomeSeen = event.modelEffortOutcome !== undefined;\n }\n }\n if (!executorOutcomeSeen) {\n this.publishModelEffortOutcome(resolvedOptions, 'opaque-executor');\n }\n return;\n } catch (error) {\n this.logger.error(\n 'OpenAI Provider executor stream error:',\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n }\n }\n\n yield* this.streamDirect(messages, resolvedOptions);\n }\n\n private async *streamDirect(\n messages: TUniversalMessage[],\n resolvedOptions: IChatOptions | undefined,\n ): AsyncIterable<TUniversalMessage> {\n if (this.apiSurface === 'responses') {\n yield* chatStreamWithOpenAIResponsesApi({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n return;\n }\n\n yield* chatStreamWithOpenAIChatCompletions({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n payloadLogger: this.payloadLogger,\n responseParser: this.responseParser,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n }\n\n /**\n * CORE-043: this provider declares no capability table — nobody has verified one for OpenAI, and\n * inventing one would be a fabricated claim. It can still answer THIS question honestly, which is\n * why the endpoint signal is not a field on the table.\n *\n * It matters most here of all the providers: setting `baseURL` also switches the API surface to\n * `chat-completions` (see `resolveApiSurface`), so the advertised gateway configuration is exactly\n * the one where a structured request is least likely to be enforced by whatever is on the far end.\n */\n endpointIsVendorDefault(): boolean {\n return this.options.baseURL === undefined;\n }\n\n /**\n * The client's own base URL is the origin every request goes to (the SDK has already applied a\n * constructor option or `OPENAI_BASE_URL`). An executor sends elsewhere, and an injected client\n * whose base URL cannot be read gives no origin to compare, so neither can propagate.\n */\n canPropagateTraceContext(): boolean {\n return !this.executor && this.effectiveBaseUrl() !== undefined;\n }\n\n private effectiveBaseUrl(): string | undefined {\n const baseURL: unknown = (this.client as { baseURL?: unknown } | undefined)?.baseURL;\n return typeof baseURL === 'string' && baseURL.length > 0 ? baseURL : undefined;\n }\n\n private traceRequestHeaders(options: IChatOptions | undefined): Readonly<Record<string, string>> {\n if (!this.canPropagateTraceContext()) return {};\n return traceHeadersFor(this.effectiveBaseUrl(), options?.outboundTraceContext);\n }\n\n override effortTable(): IProviderModelEffortTable | undefined {\n return this.endpointIsVendorDefault() && this.apiSurface === 'responses'\n ? OPENAI_MODEL_EFFORT_TABLE\n : undefined;\n }\n\n private resolveEffortOptions(options: IChatOptions | undefined): IChatOptions | undefined {\n if (options?.effort === undefined || options.effortResolution !== undefined) return options;\n const model = options.model ?? this.options.defaultModel;\n if (model === undefined) return options;\n return {\n ...options,\n effortResolution: resolveModelEffort(this.effortTable(), model, options.effort),\n };\n }\n\n /**\n * MCP-005: strict mode's supported subset is documented; non-strict accepts standard JSON Schema.\n * Both the Responses and Chat Completions surfaces honor `strictTools` identically (§ Profiles).\n */\n protected override projectionProfile(): IToolSchemaProjectionProfile | undefined {\n return this.options.strictTools\n ? { ...STRICT_TOOL_SCHEMA_PROFILE, providerName: 'openai' }\n : { ...PERMISSIVE_TOOL_SCHEMA_PROFILE, providerName: 'openai' };\n }\n\n /**\n * Project `chatOptions.tools` through `projectionProfile()` before either request-building module\n * (`responses-chat.ts`, `chat-completions-chat.ts`) sees them — the module helpers receive the\n * projected array as a parameter; `options.tools` itself is never mutated. An empty projected array\n * (every tool quarantined) becomes `undefined` so the downstream `tools &&` truthiness checks treat\n * it the same as \"no tools\", not as a zero-length `tools: []` request field.\n */\n private projectChatOptions(chatOptions: IChatOptions | undefined): IChatOptions | undefined {\n if (!chatOptions?.tools) {\n return chatOptions;\n }\n const model = chatOptions.model ?? this.options.defaultModel ?? '';\n const projected = this.projectTools(chatOptions.tools, model);\n return {\n ...chatOptions,\n tools: projected && projected.length > 0 ? projected : undefined,\n };\n }\n\n private publishModelEffortOutcome(\n options: IChatOptions | undefined,\n opaqueReason?: string,\n ): void {\n const resolution = options?.effortResolution;\n const observer = options?.onModelEffortOutcome;\n if (resolution === undefined || observer === undefined) return;\n\n const nativeControl =\n opaqueReason !== undefined\n ? { state: 'omitted' as const, reason: opaqueReason }\n : resolution.effective !== null && resolution.disposition !== 'model-default'\n ? { state: 'sent' as const, id: 'responses.reasoning.effort' }\n : {\n state: 'omitted' as const,\n reason:\n resolution.disposition === 'model-default'\n ? 'provider-default-selection'\n : 'model-effort-not-applied',\n };\n const providerDispatch =\n opaqueReason !== undefined\n ? { state: 'not-dispatched' as const, reason: opaqueReason }\n : { state: 'sent' as const };\n try {\n observer(createModelEffortOutcome(resolution, { nativeControl, providerDispatch }));\n } catch (error) {\n this.logger.warn('Model-effort outcome observer failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n override supportsTools(): boolean {\n return true;\n }\n\n override getCapabilities(): IProviderCapabilities {\n const source =\n this.apiSurface === 'chat-completions'\n ? 'openai-compatible-chat-completions'\n : 'openai-responses';\n return {\n functionCalling: { supported: true },\n nativeWebTools: {\n webSearch: {\n supported: false,\n enabled: false,\n source,\n reason: getOpenAIUnsupportedNativeWebReason(this.apiSurface, 'search'),\n },\n webFetch: {\n supported: false,\n enabled: false,\n source,\n reason: getOpenAIUnsupportedNativeWebReason(this.apiSurface, 'fetch'),\n },\n },\n };\n }\n\n override validateConfig(): boolean {\n return !!this.client && !!this.options;\n }\n\n override async dispose(): Promise<void> {\n // OpenAI client doesn't need explicit cleanup\n }\n\n protected override validateMessages(messages: TUniversalMessage[]): void {\n super.validateMessages(messages);\n\n for (const message of messages) {\n if (message.role === 'assistant') {\n const assistantMsg = message as IAssistantMessage;\n if (\n assistantMsg.toolCalls &&\n assistantMsg.toolCalls.length > 0 &&\n assistantMsg.content === ''\n ) {\n continue;\n }\n }\n }\n }\n}\n\nfunction resolveApiSurface(options: IOpenAIProviderOptions): TOpenAIApiSurface {\n if (options.apiSurface !== undefined) {\n return options.apiSurface;\n }\n return options.baseURL ? 'chat-completions' : 'responses';\n}\n\nfunction getOpenAIUnsupportedNativeWebReason(\n apiSurface: TOpenAIApiSurface,\n toolKind: 'search' | 'fetch',\n): string {\n if (apiSurface === 'chat-completions') {\n return `OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${toolKind}.`;\n }\n return `OpenAI Responses native web ${toolKind} is not wired in this Robota provider version.`;\n}\n\nfunction validateOpenAIProviderNativeWebTools(\n apiSurface: TOpenAIApiSurface,\n nativeWebTools: IOpenAIProviderOptions['nativeWebTools'],\n): void {\n if (nativeWebTools?.webSearch !== true && nativeWebTools?.webFetch !== true) {\n return;\n }\n throw new Error(\n `Provider openai native web search/fetch is not supported for apiSurface ${apiSurface} in this Robota provider version.`,\n );\n}\n","import type { TUniversalMessage, IAssistantMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\n/**\n * OpenAI Conversation Adapter\n *\n * Converts between TUniversalMessage format and OpenAI native types.\n * Provides bidirectional conversion for seamless integration.\n *\n * @public\n */\nexport class OpenAIConversationAdapter {\n /**\n * Filter messages for OpenAI compatibility\n *\n * OpenAI has specific requirements:\n * - Tool messages must have valid toolCallId\n * - Messages must be in proper sequence\n * - Tool messages without toolCallId should be excluded\n */\n static filterMessagesForOpenAI(messages: TUniversalMessage[]): TUniversalMessage[] {\n return messages.filter((msg) => {\n // Always include user, assistant, and system messages\n if (msg.role === 'user' || msg.role === 'assistant' || msg.role === 'system') {\n return true;\n }\n\n // For tool messages, only include if they have a valid toolCallId\n if (msg.role === 'tool') {\n // Must have toolCallId and it must not be empty or 'unknown'\n return !!(msg.toolCallId && msg.toolCallId.trim() !== '' && msg.toolCallId !== 'unknown');\n }\n\n return false;\n });\n }\n\n /**\n * Convert TUniversalMessage array to OpenAI message format\n * Now properly handles tool messages for OpenAI's tool calling feature\n */\n static toOpenAIFormat(messages: TUniversalMessage[]): OpenAI.Chat.ChatCompletionMessageParam[] {\n // First filter messages for OpenAI compatibility\n const filteredMessages = this.filterMessagesForOpenAI(messages);\n return filteredMessages.map((msg) => this.convertMessage(msg));\n }\n\n /**\n * Convert a single TUniversalMessage to OpenAI format\n * Handles all message types including tool messages\n */\n static convertMessage(msg: TUniversalMessage): OpenAI.Chat.ChatCompletionMessageParam {\n const messageRole = msg.role;\n\n if (messageRole === 'user') {\n return {\n role: 'user',\n content: msg.content,\n };\n }\n\n if (messageRole === 'assistant') {\n const assistantMsg = msg as IAssistantMessage;\n\n // Handle tool_calls format\n if (assistantMsg.toolCalls && assistantMsg.toolCalls.length > 0) {\n const result: OpenAI.Chat.ChatCompletionAssistantMessageParam = {\n role: 'assistant',\n // CRITICAL: OpenAI API requires content to be null (not empty string) when tool_calls are present\n // VERIFIED: 2024-12 - This prevents \"400 Bad Request\" errors from OpenAI API\n // DO NOT CHANGE without testing against actual OpenAI API\n content: assistantMsg.content === '' ? null : assistantMsg.content || null,\n tool_calls: assistantMsg.toolCalls.map((toolCall) => ({\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n },\n })),\n };\n return result;\n }\n\n // Regular assistant message (without tool calls)\n // VERIFIED: OpenAI accepts both null and string content for regular messages\n // We preserve null when content is null or empty string for API consistency\n return {\n role: 'assistant',\n content:\n assistantMsg.content === null\n ? null\n : assistantMsg.content === ''\n ? null\n : assistantMsg.content || '',\n };\n }\n\n if (messageRole === 'system') {\n return {\n role: 'system',\n content: msg.content,\n };\n }\n\n // Handle tool messages for OpenAI tool calling\n if (messageRole === 'tool') {\n if (!msg.toolCallId || msg.toolCallId.trim() === '') {\n throw new Error(`Tool message missing toolCallId: ${JSON.stringify(msg)}`);\n }\n\n const result: OpenAI.Chat.ChatCompletionToolMessageParam = {\n role: 'tool',\n content: msg.content,\n tool_call_id: msg.toolCallId,\n };\n return result;\n }\n\n const exhaustive: never = messageRole;\n throw new Error(`Unsupported message role: ${exhaustive}`);\n }\n\n /**\n * Add system prompt to message array if needed\n */\n static addSystemPromptIfNeeded(\n messages: OpenAI.Chat.ChatCompletionMessageParam[],\n systemPrompt?: string,\n ): OpenAI.Chat.ChatCompletionMessageParam[] {\n if (!systemPrompt) {\n return messages;\n }\n\n // Check if system message already exists\n const hasSystemMessage = messages.some((msg) => msg.role === 'system');\n\n if (hasSystemMessage) {\n return messages;\n }\n\n // Add system prompt at the beginning\n return [{ role: 'system', content: systemPrompt }, ...messages];\n }\n}\n","import { probeOpenAICompatibleProfile } from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport { OpenAIProvider } from './provider';\n\nimport type { IOpenAINativeWebToolsOptions, TOpenAIApiSurface } from './types';\nimport type { IProviderDefinition, TUniversalValue } from '@robota-sdk/agent-core';\n\nexport const DEFAULT_OPENAI_PROVIDER_MODEL: string | undefined = undefined;\nexport const DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE = '$ENV:OPENAI_API_KEY';\nconst OPENAI_API_KEY_URL = 'https://platform.openai.com/api-keys';\nconst OPENAI_SETUP_SOURCE_URL =\n 'https://developers.openai.com/api/reference/overview#authentication';\nconst OPENAI_SETUP_LAST_VERIFIED_AT = '2026-05-08';\nconst OPENAI_SETUP_HELP_LINKS: NonNullable<IProviderDefinition['setupHelpLinks']> = [\n {\n kind: 'api-key',\n label: 'OpenAI API keys',\n url: OPENAI_API_KEY_URL,\n sourceUrl: OPENAI_SETUP_SOURCE_URL,\n lastVerifiedAt: OPENAI_SETUP_LAST_VERIFIED_AT,\n },\n];\n\nexport function createOpenAIProviderDefinition(): IProviderDefinition {\n return {\n type: 'openai',\n displayName: 'OpenAI',\n description: 'GPT series — general-purpose assistant. API key required.',\n category: 'cloud-paid',\n // Interim provider-level cost (ARCH-PROVIDER-003), migrated from the former llm-text-openai node.\n costPerTokenUsd: 0.001,\n defaults: {\n apiKey: DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,\n },\n // OBSERVABILITY-1991: the SDK embeds this endpoint; declared here for the pre-session doctor only.\n endpoint: { host: 'api.openai.com', port: 443 },\n modelCatalog: {\n status: 'unavailable',\n sourceUrl: 'https://platform.openai.com/docs/api-reference/models/list',\n message: 'OpenAI model availability should be discovered live from GET /v1/models.',\n },\n setupHelpLinks: OPENAI_SETUP_HELP_LINKS,\n setupSteps: [\n {\n key: 'model',\n title: 'OpenAI model',\n required: true,\n },\n {\n key: 'apiKey',\n title: 'OpenAI API key',\n defaultValue: DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,\n masked: true,\n },\n ],\n requiresApiKey: true,\n probeProfile: probeOpenAICompatibleProfile,\n // The OpenAI SDK falls back to the base URL variable when none is configured, and sends the\n // organization and project the others name.\n destinationEnvironment: ['OPENAI_BASE_URL', 'OPENAI_ORG_ID', 'OPENAI_PROJECT_ID'],\n createProvider: (config) => {\n const apiSurface = readApiSurface(config.options);\n const nativeWebTools = readNativeWebTools(config.options);\n validateOpenAINativeWebTools(config.baseURL, apiSurface, nativeWebTools);\n return new OpenAIProvider({\n apiKey: requireApiKey(config.apiKey),\n ...(config.baseURL !== undefined && { baseURL: config.baseURL }),\n ...(config.timeout !== undefined && { timeout: config.timeout }),\n ...(apiSurface !== undefined && { apiSurface }),\n ...(nativeWebTools !== undefined && { nativeWebTools }),\n defaultModel: config.model,\n });\n },\n };\n}\n\nfunction requireApiKey(apiKey: string | undefined): string {\n if (!apiKey) {\n throw new Error('Provider openai requires apiKey');\n }\n return apiKey;\n}\n\nfunction readApiSurface(\n options: Record<string, TUniversalValue> | undefined,\n): TOpenAIApiSurface | undefined {\n const apiSurface = options?.['apiSurface'];\n if (apiSurface === 'responses' || apiSurface === 'chat-completions') {\n return apiSurface;\n }\n return undefined;\n}\n\nfunction readNativeWebTools(\n options: Record<string, TUniversalValue> | undefined,\n): IOpenAINativeWebToolsOptions | undefined {\n const nativeWebTools =\n readNativeWebToolsRecord(options?.['nativeWebTools']) ??\n readNativeWebToolsRecord(options?.['builtInWebTools']);\n if (nativeWebTools === undefined) {\n return undefined;\n }\n return nativeWebTools;\n}\n\nfunction readNativeWebToolsRecord(\n value: TUniversalValue | undefined,\n): IOpenAINativeWebToolsOptions | undefined {\n if (value === null || value === undefined || value instanceof Date || Array.isArray(value)) {\n return undefined;\n }\n if (typeof value !== 'object') {\n return undefined;\n }\n const webSearch = value['webSearch'];\n const webFetch = value['webFetch'];\n return {\n ...(typeof webSearch === 'boolean' && { webSearch }),\n ...(typeof webFetch === 'boolean' && { webFetch }),\n };\n}\n\nfunction validateOpenAINativeWebTools(\n baseURL: string | undefined,\n apiSurface: TOpenAIApiSurface | undefined,\n nativeWebTools: IOpenAINativeWebToolsOptions | undefined,\n): void {\n if (nativeWebTools?.webSearch !== true && nativeWebTools?.webFetch !== true) {\n return;\n }\n if (baseURL !== undefined || apiSurface === 'chat-completions') {\n throw new Error(\n 'Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use Robota local WebSearch/WebFetch tools or a provider with documented hosted web support.',\n );\n }\n throw new Error(\n 'Provider openai native web search/fetch is not wired in this Robota provider version. Use Robota local WebSearch/WebFetch tools or a provider with documented hosted web support.',\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["assembleOpenAIStream","exhaustive"],"sources":["../../src/openai/message-converter.ts","../../src/openai/openai-request-format.ts","../../src/openai/request-id.ts","../../src/openai/request-options.ts","../../src/openai/chat-completions-chat.ts","../../src/openai/model-effort-table.ts","../../src/openai/parsers/response-parser.ts","../../src/openai/reasoning-effort.ts","../../src/openai/responses-converter.ts","../../src/openai/responses-stream-utils.ts","../../src/openai/responses-parser.ts","../../src/openai/responses-chat.ts","../../src/openai/provider.ts","../../src/openai/adapter.ts","../../src/openai/provider-definition.ts"],"sourcesContent":["import {\n convertToOpenAICompatibleMessages,\n convertToOpenAICompatibleTools,\n} from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport type { IToolSchema, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\n/**\n * Convert TUniversalMessage array to OpenAI chat completion message format.\n */\nexport function convertToOpenAIMessages(\n messages: TUniversalMessage[],\n): OpenAI.Chat.ChatCompletionMessageParam[] {\n return convertToOpenAICompatibleMessages(messages);\n}\n\n/**\n * Convert tool schemas to OpenAI function tool format. With `strictTools` each function is declared\n * `strict: true`, as the Responses surface does, so strict mode is requested on both surfaces.\n */\nexport function convertToOpenAITools(\n tools: IToolSchema[],\n strictTools?: boolean,\n): OpenAI.Chat.ChatCompletionTool[] {\n return convertToOpenAICompatibleTools(tools, { strict: strictTools === true });\n}\n","import type {\n IOpenAIResponsesTextConfig,\n IOpenAIResponsesTextFormatJsonSchema,\n} from './responses-types';\nimport type { IOpenAIProviderOptions, TOpenAIProviderOptionValue } from './types';\nimport type { IChatOptions } from '@robota-sdk/agent-core';\n\nexport interface IOpenAIChatTextFormatText {\n type: 'text';\n}\n\nexport interface IOpenAIChatTextFormatJsonObject {\n type: 'json_object';\n}\n\nexport interface IOpenAIChatTextFormatJsonSchema {\n type: 'json_schema';\n json_schema: {\n name: string;\n schema: Record<string, TOpenAIProviderOptionValue>;\n description?: string;\n strict?: boolean;\n };\n}\n\nexport type TOpenAIChatResponseFormat =\n IOpenAIChatTextFormatText | IOpenAIChatTextFormatJsonObject | IOpenAIChatTextFormatJsonSchema;\n\n/**\n * Merge a per-call `IChatOptions.responseFormat` onto the provider options (CORE-015).\n * A `json_schema` chat option carries its schema payload into `jsonSchema`; the\n * provider-level `jsonSchema` option remains as-is for `text`/`json_object`.\n */\nexport function mergeChatResponseFormat(\n providerOptions: IOpenAIProviderOptions,\n responseFormat: IChatOptions['responseFormat'],\n): IOpenAIProviderOptions {\n if (responseFormat?.type === undefined) {\n return providerOptions;\n }\n if (responseFormat.type === 'json_schema') {\n return {\n ...providerOptions,\n responseFormat: 'json_schema',\n jsonSchema: {\n name: responseFormat.name ?? 'structured_output',\n schema: responseFormat.schema as Record<string, TOpenAIProviderOptionValue>,\n },\n };\n }\n return { ...providerOptions, responseFormat: responseFormat.type };\n}\n\nexport function buildOpenAIChatResponseFormat(\n options: IOpenAIProviderOptions,\n): TOpenAIChatResponseFormat | undefined {\n if (options.responseFormat === undefined || options.responseFormat === 'text') {\n return undefined;\n }\n if (options.responseFormat === 'json_object') {\n return { type: 'json_object' };\n }\n\n const schema = requireJsonSchema(options);\n return {\n type: 'json_schema',\n json_schema: {\n name: schema.name,\n schema: schema.schema,\n ...(schema.description !== undefined && { description: schema.description }),\n ...(schema.strict !== undefined && { strict: schema.strict }),\n },\n };\n}\n\nexport function buildOpenAIResponsesTextConfig(\n options: IOpenAIProviderOptions,\n): IOpenAIResponsesTextConfig | undefined {\n if (options.responseFormat === undefined || options.responseFormat === 'text') {\n return undefined;\n }\n if (options.responseFormat === 'json_object') {\n return { format: { type: 'json_object' } };\n }\n\n const schema = requireJsonSchema(options);\n const format: IOpenAIResponsesTextFormatJsonSchema = {\n type: 'json_schema',\n name: schema.name,\n schema: schema.schema,\n ...(schema.description !== undefined && { description: schema.description }),\n ...(schema.strict !== undefined && { strict: schema.strict }),\n };\n return { format };\n}\n\nfunction requireJsonSchema(input: IOpenAIProviderOptions): {\n name: string;\n schema: Record<string, TOpenAIProviderOptionValue>;\n description?: string;\n strict?: boolean;\n} {\n const schema = input.jsonSchema;\n if (input.responseFormat !== 'json_schema') {\n throw new Error(`Unsupported OpenAI response format: ${input.responseFormat}`);\n }\n if (!schema?.schema) {\n throw new Error('OpenAI jsonSchema.schema is required when responseFormat is json_schema');\n }\n return {\n name: schema.name,\n schema: schema.schema,\n ...(schema.description !== undefined && { description: schema.description }),\n ...(schema.strict !== undefined && { strict: schema.strict }),\n };\n}\n","import type { TUniversalMessage } from '@robota-sdk/agent-core';\n\n/** The subset of the OpenAI SDK's `APIPromise` this module depends on. */\ninterface IWithResponseCapable<T> {\n withResponse?: () => Promise<{ data: T; request_id?: string | null }>;\n}\n\n/**\n * Await an OpenAI `create()` call, reading the server's own request ID off `.withResponse()` when\n * the client exposes it. A test double or older client that resolves to a plain value has no\n * `withResponse`, so this falls back to the awaited value with no ID — never a fabricated one.\n */\nexport async function awaitWithProviderRequestId<T>(\n call: PromiseLike<T> & IWithResponseCapable<T>,\n): Promise<{ data: T; providerRequestId?: string }> {\n if (typeof call.withResponse === 'function') {\n const { data, request_id } = await call.withResponse();\n return {\n data,\n ...(typeof request_id === 'string' && request_id.length > 0 && { providerRequestId: request_id }),\n };\n }\n return { data: await call };\n}\n\n/** The non-stream response shape the SDK attaches its own request ID to directly. */\nexport function readOpenAIRequestId(response: unknown): string | undefined {\n const id = (response as { _request_id?: string | null } | null | undefined)?._request_id;\n return typeof id === 'string' && id.length > 0 ? id : undefined;\n}\n\n/** Merge a provider-returned request ID into a message's metadata; a no-op when there isn't one. */\nexport function withProviderRequestId<T extends TUniversalMessage>(\n message: T,\n providerRequestId: string | undefined,\n): T {\n if (providerRequestId === undefined) return message;\n return { ...message, metadata: { ...message.metadata, providerRequestId } };\n}\n","import type OpenAI from 'openai';\n\n/**\n * Per-request SDK options, or none at all when there is neither a signal nor a header to send, so\n * a call without either keeps the exact shape it always had.\n */\nexport function openAIRequestOptions(\n signal: AbortSignal | undefined,\n headers: Readonly<Record<string, string>> | undefined,\n): OpenAI.RequestOptions | undefined {\n const hasHeaders = headers !== undefined && Object.keys(headers).length > 0;\n if (!signal && !hasHeaders) return undefined;\n return { ...(signal ? { signal } : {}), ...(hasHeaders ? { headers: { ...headers } } : {}) };\n}\n","import { toProviderError } from '@robota-sdk/agent-core';\nimport {\n observeProviderNativeRawPayloadStream,\n toOpenAICompatibleToolChoice,\n} from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport { convertToOpenAIMessages, convertToOpenAITools } from './message-converter';\nimport { buildOpenAIChatResponseFormat, mergeChatResponseFormat } from './openai-request-format';\nimport {\n awaitWithProviderRequestId,\n readOpenAIRequestId,\n withProviderRequestId,\n} from './request-id';\nimport { openAIRequestOptions } from './request-options';\nimport { assembleOpenAIStream } from './streaming/stream-assembler';\n\nimport type { IPayloadLogger } from './interfaces/payload-logger';\nimport type { OpenAIResponseParser } from './parsers/response-parser';\nimport type { IOpenAIProviderOptions } from './types';\nimport type { IOpenAILogData } from './types/api-types';\nimport type { IChatOptions, TTextDeltaCallback, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\nexport interface IOpenAIChatCompletionsOptions {\n client?: OpenAI;\n messages: TUniversalMessage[];\n chatOptions?: IChatOptions;\n providerOptions: IOpenAIProviderOptions;\n payloadLogger?: IPayloadLogger;\n responseParser: OpenAIResponseParser;\n onTextDelta?: TTextDeltaCallback;\n /** Per-request headers (trusted `traceparent`), sent after the raw request payload is captured. */\n requestHeaders?: Readonly<Record<string, string>>;\n}\n\nexport async function chatWithOpenAIChatCompletions(\n input: IOpenAIChatCompletionsOptions,\n): Promise<TUniversalMessage> {\n const client = requireClient(input.client);\n\n try {\n const requestParams = buildChatRequestParams(input);\n const textDeltaCb = input.chatOptions?.onTextDelta ?? input.onTextDelta;\n if (textDeltaCb) {\n return await chatWithStreamingAssembly(client, input, {\n ...requestParams,\n stream: true,\n ...buildStreamOptions(input),\n });\n }\n\n await logPayload(input, requestParams, 'chat');\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'request',\n payload: requestParams,\n });\n const requestOptions = openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders);\n const response = requestOptions\n ? await client.chat.completions.create(requestParams, requestOptions)\n : await client.chat.completions.create(requestParams);\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'response',\n payload: response,\n });\n return withProviderRequestId(\n input.responseParser.parseResponse(response),\n readOpenAIRequestId(response),\n );\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI chat failed');\n }\n}\n\nexport async function* chatStreamWithOpenAIChatCompletions(\n input: IOpenAIChatCompletionsOptions,\n): AsyncIterable<TUniversalMessage> {\n const client = requireClient(input.client);\n\n try {\n const requestParams: OpenAI.Chat.ChatCompletionCreateParamsStreaming = {\n ...buildChatRequestParams(input),\n stream: true,\n ...buildStreamOptions(input),\n };\n\n await logPayload(input, requestParams, 'stream');\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'request',\n payload: requestParams,\n });\n const { data: stream, providerRequestId } = await awaitWithProviderRequestId(\n client.chat.completions.create(\n requestParams,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n ),\n );\n\n for await (const chunk of observeProviderNativeRawPayloadStream(stream, {\n provider: 'openai',\n apiSurface: 'chat-completions',\n onProviderNativeRawPayload: input.chatOptions?.onProviderNativeRawPayload,\n })) {\n const universalMessage = input.responseParser.parseStreamingChunk(chunk);\n if (universalMessage) {\n yield withProviderRequestId(universalMessage, providerRequestId);\n }\n }\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI stream failed');\n }\n}\n\n/**\n * Streaming requests opt into token usage via `stream_options: { include_usage: true }`\n * unless the provider sets `includeStreamUsage: false`. Only ever sent on streaming requests.\n */\nfunction buildStreamOptions(\n input: IOpenAIChatCompletionsOptions,\n): { stream_options: { include_usage: true } } | Record<string, never> {\n if (input.providerOptions.includeStreamUsage === false) {\n return {};\n }\n return { stream_options: { include_usage: true } };\n}\n\nfunction buildChatRequestParams(\n input: IOpenAIChatCompletionsOptions,\n): OpenAI.Chat.ChatCompletionCreateParamsNonStreaming {\n const openaiMessages = convertToOpenAIMessages(input.messages);\n const model = input.chatOptions?.model ?? input.providerOptions.defaultModel;\n if (!model) {\n throw new Error(\n 'Model is required in chat options. Please specify a model in defaultModel configuration.',\n );\n }\n\n const responseFormat = buildOpenAIChatResponseFormat(\n mergeChatResponseFormat(input.providerOptions, input.chatOptions?.responseFormat),\n );\n return {\n model,\n messages: openaiMessages,\n ...(input.chatOptions?.temperature !== undefined && {\n temperature: input.chatOptions.temperature,\n }),\n ...(input.chatOptions?.maxTokens !== undefined && { max_tokens: input.chatOptions.maxTokens }),\n ...(input.chatOptions?.tools && {\n tools: convertToOpenAITools(input.chatOptions.tools, input.providerOptions.strictTools),\n tool_choice: toOpenAICompatibleToolChoice(input.chatOptions.toolChoice),\n }),\n ...(responseFormat !== undefined && { response_format: responseFormat }),\n } as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming;\n}\n\nasync function chatWithStreamingAssembly(\n client: OpenAI,\n input: IOpenAIChatCompletionsOptions,\n requestParams: OpenAI.Chat.ChatCompletionCreateParamsStreaming,\n): Promise<TUniversalMessage> {\n try {\n await logPayload(input, requestParams, 'stream');\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'chat-completions',\n payloadKind: 'request',\n payload: requestParams,\n });\n const { data: stream, providerRequestId } = await awaitWithProviderRequestId(\n client.chat.completions.create(\n requestParams,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n ),\n );\n\n const assembled = await assembleOpenAIStream({\n stream: observeProviderNativeRawPayloadStream(stream, {\n provider: 'openai',\n apiSurface: 'chat-completions',\n onProviderNativeRawPayload: input.chatOptions?.onProviderNativeRawPayload,\n }),\n onTextDelta: input.chatOptions?.onTextDelta ?? input.onTextDelta,\n signal: input.chatOptions?.signal,\n });\n return withProviderRequestId(assembled, providerRequestId);\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI stream failed');\n }\n}\n\nasync function logPayload(\n input: IOpenAIChatCompletionsOptions,\n requestParams:\n | OpenAI.Chat.ChatCompletionCreateParamsNonStreaming\n | OpenAI.Chat.ChatCompletionCreateParamsStreaming,\n type: 'chat' | 'stream',\n): Promise<void> {\n if (!input.payloadLogger?.isEnabled()) {\n return;\n }\n\n const logData: IOpenAILogData = {\n model: requestParams.model,\n messagesCount: requestParams.messages.length,\n hasTools: !!requestParams.tools,\n temperature: requestParams.temperature ?? undefined,\n maxTokens: requestParams.max_tokens ?? undefined,\n timestamp: new Date().toISOString(),\n };\n await input.payloadLogger.logPayload(logData, type);\n}\n\nfunction requireClient(client: OpenAI | undefined): OpenAI {\n if (!client) {\n throw new Error(\n 'OpenAI client not available. Either provide a client/apiKey or use an executor.',\n );\n }\n return client;\n}\n","import type { IProviderModelEffortTable } from '@robota-sdk/agent-core';\n\n/**\n * Exact model facts verified against OpenAI's Responses reference on 2026-09-11.\n *\n * The adapter deliberately declares no prefix or vendor-wide fallback. A different model id must\n * remain `not-applied` until its documented controls and default are added here.\n */\nexport const OPENAI_MODEL_EFFORT_TABLE: IProviderModelEffortTable = {\n verifiedAt: '2026-09-11',\n sourceUrl: 'https://platform.openai.com/docs/api-reference/responses',\n models: {\n 'gpt-5.1': {\n supportedEfforts: ['none', 'low', 'medium', 'high'],\n defaultEffort: 'none',\n nativeControlId: 'responses.reasoning.effort',\n },\n },\n};\n","import { OpenAICompatibleResponseParser } from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport type { ILogger, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\n/**\n * OpenAI response parser compatibility wrapper.\n *\n * The implementation delegates to the shared OpenAI-compatible parser while\n * preserving the OpenAI-branded error messages that are part of this package's\n * current test contract.\n */\nexport class OpenAIResponseParser {\n private readonly parser: OpenAICompatibleResponseParser;\n\n constructor(logger?: ILogger) {\n this.parser = new OpenAICompatibleResponseParser({ logger });\n }\n\n parseResponse(response: OpenAI.Chat.ChatCompletion): TUniversalMessage {\n try {\n return this.parser.parseResponse(response);\n } catch (error) {\n const message = normalizeParserMessage(\n error instanceof Error ? error.message : 'OpenAI response parsing failed',\n );\n throw new Error(`OpenAI response parsing failed: ${message}`);\n }\n }\n\n parseStreamingChunk(chunk: OpenAI.Chat.ChatCompletionChunk): TUniversalMessage | null {\n try {\n return this.parser.parseStreamingChunk(chunk);\n } catch (error) {\n const message = normalizeParserMessage(\n error instanceof Error ? error.message : 'OpenAI chunk parsing failed',\n );\n throw new Error(`OpenAI chunk parsing failed: ${message}`);\n }\n }\n}\n\nfunction normalizeParserMessage(message: string): string {\n return message\n .replace(/^OpenAI-compatible response parsing failed: /, '')\n .replace(/^OpenAI-compatible chunk parsing failed: /, '')\n .replace('OpenAI-compatible response', 'OpenAI response');\n}\n","import type { IOpenAIResponsesReasoningOptions } from './types';\nimport type { IModelEffortResolution, TModelEffort } from '@robota-sdk/agent-core';\n\n/**\n * Map the framework's per-call reasoning-effort dial onto the OpenAI Responses API\n * `reasoning.effort` parameter.\n *\n * Per-model support and downward clamping are resolved by the Core table before this boundary.\n * This function only serializes the verified concrete value, without reinterpreting it.\n */\nexport function mapEffortToOpenAIReasoningEffort(\n effort: TModelEffort,\n): IOpenAIResponsesReasoningOptions['effort'] {\n return effort;\n}\n\n/**\n * Merge the per-call effort dial into the provider's static reasoning options.\n *\n * A verified concrete resolution takes precedence over static native control; a conflicting static\n * control is rejected rather than silently overwritten. `auto` and `not-applied` resolutions leave\n * the provider default untouched and never manufacture a native effort field.\n */\nexport function resolveOpenAIReasoningOptions(\n staticReasoning: IOpenAIResponsesReasoningOptions | undefined,\n resolution: IModelEffortResolution | undefined,\n): IOpenAIResponsesReasoningOptions | undefined {\n if (resolution === undefined) {\n return staticReasoning;\n }\n if (resolution.effective === null || resolution.disposition === 'model-default') {\n if (staticReasoning?.effort !== undefined) {\n throw new Error(\n `Static reasoning.effort ${staticReasoning.effort} conflicts with ${resolution.disposition === 'model-default' ? 'provider-default selection' : 'an effort resolution that does not apply a native control'}.`,\n );\n }\n return staticReasoning;\n }\n const effort = mapEffortToOpenAIReasoningEffort(resolution.effective);\n if (staticReasoning?.effort !== undefined && staticReasoning.effort !== effort) {\n throw new Error(\n `Resolved effort ${effort} conflicts with static reasoning.effort ${staticReasoning.effort}.`,\n );\n }\n return {\n ...staticReasoning,\n effort,\n };\n}\n","import { nonVisualObservationText } from '@robota-sdk/agent-core';\nimport type {\n IOpenAIResponsesFunctionTool,\n IOpenAIResponsesMessageInput,\n TOpenAIResponsesInputContent,\n TOpenAIResponsesInputItem,\n} from './responses-types';\nimport type {\n IAssistantMessage,\n IToolSchema,\n TUniversalMessage,\n TUniversalMessagePart,\n} from '@robota-sdk/agent-core';\n\nexport function convertToOpenAIResponsesInput(\n messages: TUniversalMessage[],\n): TOpenAIResponsesInputItem[] {\n return messages.flatMap((message) => convertMessage(message));\n}\n\n/**\n * MCP-005: `tools` arrives ALREADY projected — `AbstractAIProvider.projectTools()` ran the strict or\n * permissive profile (`STRICT_TOOL_SCHEMA_PROFILE` / `PERMISSIVE_TOOL_SCHEMA_PROFILE`) over every\n * schema before this converter ever sees it, closing objects for strict mode where PROV-007's\n * `closeObjectSchemas` used to run inline here. This function does no schema transformation of its\n * own — it only shapes the already-projected `parameters` into the wire tool definition and keeps\n * `strict: true` on the emitted field when `strictTools` is on (a request-field concern, not a schema\n * one: the schema was already closed by the projection step).\n */\nexport function convertToOpenAIResponsesTools(\n tools: IToolSchema[] | undefined,\n strictTools: boolean | undefined,\n): IOpenAIResponsesFunctionTool[] | undefined {\n const strict = strictTools ?? false;\n const converted =\n tools?.map((tool) => ({\n type: 'function' as const,\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n strict,\n })) ?? [];\n return converted.length > 0 ? converted : undefined;\n}\n\nfunction convertMessage(message: TUniversalMessage): TOpenAIResponsesInputItem[] {\n if (message.role === 'user') {\n return [createMessageInput('user', getUserContent(message.content, message.parts))];\n }\n if (message.role === 'system') {\n return [createMessageInput('system', message.content)];\n }\n if (message.role === 'tool') {\n if (!message.toolCallId || message.toolCallId.trim().length === 0) {\n throw new Error(`Tool message missing toolCallId: ${JSON.stringify(message)}`);\n }\n return [\n {\n type: 'function_call_output',\n call_id: message.toolCallId,\n output: message.parts?.length\n ? [\n ...(message.content &&\n !message.parts.some((part) => part.type === 'text' && part.text === message.content)\n ? [{ type: 'input_text' as const, text: message.content }]\n : []),\n ...message.parts.map(convertPart),\n ]\n : message.content || '',\n },\n ];\n }\n return convertAssistantMessage(message);\n}\n\nfunction convertAssistantMessage(message: IAssistantMessage): TOpenAIResponsesInputItem[] {\n const items: TOpenAIResponsesInputItem[] = [];\n if (message.content && message.content.length > 0) {\n items.push(createMessageInput('assistant', message.content));\n }\n for (const toolCall of message.toolCalls ?? []) {\n items.push({\n type: 'function_call',\n call_id: toolCall.id,\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n });\n }\n if (items.length === 0) {\n items.push(createMessageInput('assistant', ''));\n }\n return items;\n}\n\nfunction getUserContent(\n content: string,\n parts: TUniversalMessagePart[] | undefined,\n): string | TOpenAIResponsesInputContent[] {\n if (!parts || parts.length === 0) {\n return content;\n }\n\n const converted = parts.map((part) => convertPart(part));\n if (content.length > 0 && !parts.some((part) => part.type === 'text')) {\n return [{ type: 'input_text', text: content }, ...converted];\n }\n return converted;\n}\n\nfunction convertPart(part: TUniversalMessagePart): TOpenAIResponsesInputContent {\n if (part.type === 'text') {\n return { type: 'input_text', text: part.text };\n }\n if (part.type === 'image_uri') {\n return { type: 'input_image', image_url: part.uri };\n }\n if (part.type === 'image_inline') return {\n type: 'input_image',\n image_url: `data:${part.mimeType};base64,${part.data}`,\n };\n return { type: 'input_text', text: nonVisualObservationText(part) ?? 'Unsupported observation' };\n}\n\nfunction createMessageInput(\n role: IOpenAIResponsesMessageInput['role'],\n content: string | TOpenAIResponsesInputContent[],\n): IOpenAIResponsesMessageInput {\n return {\n role,\n content,\n };\n}\n","export async function* streamWithAbort<T>(\n source: AsyncIterable<T>,\n signal?: AbortSignal,\n): AsyncGenerator<T> {\n const iterator = source[Symbol.asyncIterator]();\n try {\n while (!signal?.aborted) {\n const item = await nextStreamItem(iterator, signal);\n if (item.done || signal?.aborted) {\n break;\n }\n yield item.value;\n }\n } finally {\n if (signal?.aborted) {\n await iterator.return?.();\n }\n }\n}\n\nasync function nextStreamItem<T>(\n iterator: AsyncIterator<T>,\n signal?: AbortSignal,\n): Promise<IteratorResult<T>> {\n if (!signal) {\n return iterator.next();\n }\n if (signal.aborted) {\n return { done: true, value: undefined as T };\n }\n\n let abortListener: (() => void) | undefined;\n const aborted = new Promise<IteratorResult<T>>((resolve) => {\n abortListener = (): void => resolve({ done: true, value: undefined as T });\n signal.addEventListener('abort', abortListener, { once: true });\n });\n\n try {\n return await Promise.race([iterator.next(), aborted]);\n } finally {\n if (abortListener) {\n signal.removeEventListener('abort', abortListener);\n }\n }\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { streamWithAbort } from './responses-stream-utils';\n\nimport type {\n IOpenAIResponsesErrorEvent,\n IOpenAIResponsesFunctionCallOutputItem,\n IOpenAIResponsesMessageOutputItem,\n IOpenAIResponsesReasoningOutputItem,\n IOpenAIResponsesResponse,\n IOpenAIResponsesUsage,\n TOpenAIResponsesOutputContent,\n TOpenAIResponsesOutputItem,\n TOpenAIResponsesStreamEvent,\n} from './responses-types';\nimport type {\n IToolCall,\n ITokenUsageWithCacheRead,\n TTextDeltaCallback,\n TUniversalMessage,\n} from '@robota-sdk/agent-core';\n\n/** Message usage; `totalTokens` is absent when the response omitted `total_tokens`. */\ntype TResponsesMessageUsage = Omit<ITokenUsageWithCacheRead, 'totalTokens'> &\n Partial<Pick<ITokenUsageWithCacheRead, 'totalTokens'>>;\n\ninterface IOpenAIResponsesStreamAssemblyOptions {\n stream: AsyncIterable<TOpenAIResponsesStreamEvent>;\n onTextDelta?: TTextDeltaCallback;\n signal?: AbortSignal;\n}\n\ninterface IOpenAIResponsesReasoningMetadata {\n reasoningSummaryCount: number;\n reasoningSummaries: string[];\n hasEncryptedReasoning: boolean;\n}\n\ninterface IOpenAIResponsesStreamState {\n textParts: string[];\n toolCalls: IToolCall[];\n completedResponse?: IOpenAIResponsesResponse;\n reasoning: IOpenAIResponsesReasoningMetadata;\n}\n\nexport function parseOpenAIResponsesResponse(\n response: IOpenAIResponsesResponse,\n): TUniversalMessage {\n assertUsableResponse(response);\n const output = response.output ?? [];\n const content = response.output_text ?? extractMessageText(output);\n return buildAssistantMessage({\n content,\n toolCalls: extractFunctionToolCalls(output),\n response,\n reasoning: collectReasoningMetadata(output),\n });\n}\n\nexport async function assembleOpenAIResponsesStream(\n options: IOpenAIResponsesStreamAssemblyOptions,\n): Promise<TUniversalMessage> {\n const state: IOpenAIResponsesStreamState = {\n textParts: [],\n toolCalls: [],\n reasoning: createEmptyReasoningMetadata(),\n };\n\n for await (const event of streamWithAbort(options.stream, options.signal)) {\n applyStreamEvent(state, event, options.onTextDelta);\n }\n\n if (state.completedResponse !== undefined) {\n return buildMessageFromCompletedResponse(state);\n }\n\n return buildAssistantMessage({\n content: state.textParts.join(''),\n toolCalls: state.toolCalls,\n reasoning: state.reasoning,\n });\n}\n\nfunction applyStreamEvent(\n state: IOpenAIResponsesStreamState,\n event: TOpenAIResponsesStreamEvent,\n onTextDelta: TTextDeltaCallback | undefined,\n): void {\n if (event.type === 'response.output_text.delta') {\n state.textParts.push(event.delta);\n onTextDelta?.(event.delta);\n return;\n }\n\n if (event.type === 'response.completed') {\n state.completedResponse = event.response;\n mergeReasoningMetadata(state.reasoning, collectReasoningMetadata(event.response.output ?? []));\n return;\n }\n\n if (event.type === 'response.output_item.done') {\n applyOutputItem(state, event.item);\n return;\n }\n\n if (\n event.type === 'response.error' ||\n event.type === 'response.failed' ||\n event.type === 'response.incomplete'\n ) {\n throw new Error(`OpenAI Responses API failed: ${extractErrorMessage(event)}`);\n }\n}\n\nfunction applyOutputItem(\n state: IOpenAIResponsesStreamState,\n item: TOpenAIResponsesOutputItem,\n): void {\n if (isFunctionCallOutputItem(item)) {\n state.toolCalls.push(convertFunctionCall(item));\n return;\n }\n if (isReasoningOutputItem(item)) {\n mergeReasoningMetadata(state.reasoning, collectReasoningMetadata([item]));\n }\n}\n\nfunction buildMessageFromCompletedResponse(state: IOpenAIResponsesStreamState): TUniversalMessage {\n const response = state.completedResponse;\n if (response === undefined) {\n throw new Error('OpenAI Responses stream completed without response metadata');\n }\n\n assertUsableResponse(response);\n const output = response.output ?? [];\n const responseToolCalls = extractFunctionToolCalls(output);\n const content =\n state.textParts.length > 0\n ? state.textParts.join('')\n : (response.output_text ?? extractMessageText(output));\n const reasoning = collectReasoningMetadata(output);\n mergeReasoningMetadata(reasoning, state.reasoning);\n\n return buildAssistantMessage({\n content,\n toolCalls: responseToolCalls.length > 0 ? responseToolCalls : state.toolCalls,\n response,\n reasoning,\n });\n}\n\nfunction buildAssistantMessage(input: {\n content: string;\n toolCalls: IToolCall[];\n response?: IOpenAIResponsesResponse;\n reasoning: IOpenAIResponsesReasoningMetadata;\n}): TUniversalMessage {\n return {\n id: randomUUID(),\n role: 'assistant',\n content: input.content,\n state: 'complete',\n timestamp: new Date(),\n ...(input.toolCalls.length > 0 && { toolCalls: input.toolCalls }),\n ...(input.response?.usage !== undefined && { usage: mapUsage(input.response.usage) }),\n metadata: {\n ...buildMetadata(input.response, input.reasoning),\n ...(input.response?.usage !== undefined && {\n usageProvenance:\n input.response.usage.input_tokens !== undefined &&\n input.response.usage.output_tokens !== undefined &&\n input.response.usage.total_tokens !== undefined\n ? 'complete'\n : 'partial',\n }),\n },\n };\n}\n\nfunction buildMetadata(\n response: IOpenAIResponsesResponse | undefined,\n reasoning: IOpenAIResponsesReasoningMetadata,\n): NonNullable<TUniversalMessage['metadata']> {\n return {\n providerApiSurface: 'responses',\n ...(response?.id !== undefined && { responseId: response.id }),\n ...(response?.model !== undefined && { model: response.model }),\n ...(response?.status !== undefined && { finishReason: response.status }),\n ...(reasoning.reasoningSummaryCount > 0 && {\n reasoningSummaryCount: reasoning.reasoningSummaryCount,\n reasoningSummaries: reasoning.reasoningSummaries,\n }),\n ...(reasoning.hasEncryptedReasoning && { hasEncryptedReasoning: true }),\n };\n}\n\nfunction mapUsage(usage: IOpenAIResponsesUsage): TResponsesMessageUsage {\n const cachedTokens = usage.input_tokens_details?.cached_tokens;\n return {\n promptTokens: usage.input_tokens ?? 0,\n completionTokens: usage.output_tokens ?? 0,\n // An omitted total stays omitted: a 0 reads downstream as a real, empty call.\n ...(usage.total_tokens !== undefined && { totalTokens: usage.total_tokens }),\n ...(typeof cachedTokens === 'number' && { cacheReadTokens: cachedTokens }),\n };\n}\n\nfunction extractFunctionToolCalls(output: readonly TOpenAIResponsesOutputItem[]): IToolCall[] {\n return output.filter(isFunctionCallOutputItem).map((item) => convertFunctionCall(item));\n}\n\nfunction isFunctionCallOutputItem(\n item: TOpenAIResponsesOutputItem,\n): item is IOpenAIResponsesFunctionCallOutputItem {\n return (\n item.type === 'function_call' && 'call_id' in item && 'name' in item && 'arguments' in item\n );\n}\n\nfunction convertFunctionCall(item: IOpenAIResponsesFunctionCallOutputItem): IToolCall {\n return {\n id: item.call_id,\n type: 'function',\n function: {\n name: item.name,\n arguments: item.arguments,\n },\n };\n}\n\nfunction extractMessageText(output: readonly TOpenAIResponsesOutputItem[]): string {\n return output\n .filter(isMessageOutputItem)\n .flatMap((item) => item.content)\n .map(extractTextContent)\n .join('');\n}\n\nfunction extractTextContent(content: TOpenAIResponsesOutputContent): string {\n if (content.type === 'refusal') {\n return content.refusal;\n }\n return content.text;\n}\n\nfunction isMessageOutputItem(\n item: TOpenAIResponsesOutputItem,\n): item is IOpenAIResponsesMessageOutputItem {\n return item.type === 'message' && 'content' in item && Array.isArray(item.content);\n}\n\nfunction collectReasoningMetadata(\n output: readonly TOpenAIResponsesOutputItem[],\n): IOpenAIResponsesReasoningMetadata {\n const metadata = createEmptyReasoningMetadata();\n for (const item of output) {\n if (!isReasoningOutputItem(item)) {\n continue;\n }\n const summaries = item.summary?.map((summary) => summary.text).filter(isString) ?? [];\n metadata.reasoningSummaryCount += summaries.length;\n metadata.reasoningSummaries.push(...summaries);\n metadata.hasEncryptedReasoning = metadata.hasEncryptedReasoning || !!item.encrypted_content;\n }\n return metadata;\n}\n\nfunction isReasoningOutputItem(\n item: TOpenAIResponsesOutputItem,\n): item is IOpenAIResponsesReasoningOutputItem {\n return item.type === 'reasoning';\n}\n\nfunction createEmptyReasoningMetadata(): IOpenAIResponsesReasoningMetadata {\n return {\n reasoningSummaryCount: 0,\n reasoningSummaries: [],\n hasEncryptedReasoning: false,\n };\n}\n\nfunction mergeReasoningMetadata(\n target: IOpenAIResponsesReasoningMetadata,\n source: IOpenAIResponsesReasoningMetadata,\n): void {\n target.reasoningSummaryCount += source.reasoningSummaryCount;\n target.reasoningSummaries.push(...source.reasoningSummaries);\n target.hasEncryptedReasoning = target.hasEncryptedReasoning || source.hasEncryptedReasoning;\n}\n\nfunction isString(value: string | undefined): value is string {\n return value !== undefined;\n}\n\nfunction assertUsableResponse(response: IOpenAIResponsesResponse): void {\n if (response.status === 'failed' || response.status === 'incomplete') {\n throw new Error(`OpenAI Responses API failed: ${response.error?.message ?? response.status}`);\n }\n}\n\nfunction extractErrorMessage(event: IOpenAIResponsesErrorEvent): string {\n return event.message ?? event.error?.message ?? event.response?.error?.message ?? 'unknown error';\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { toProviderError } from '@robota-sdk/agent-core';\n\nimport {\n observeProviderNativeRawPayloadStream,\n toOpenAIResponsesToolChoice,\n} from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport { buildOpenAIResponsesTextConfig } from './openai-request-format';\nimport { resolveOpenAIReasoningOptions } from './reasoning-effort';\nimport {\n awaitWithProviderRequestId,\n readOpenAIRequestId,\n withProviderRequestId,\n} from './request-id';\nimport {\n convertToOpenAIResponsesInput,\n convertToOpenAIResponsesTools,\n} from './responses-converter';\nimport { openAIRequestOptions } from './request-options';\nimport { assembleOpenAIResponsesStream, parseOpenAIResponsesResponse } from './responses-parser';\n\nimport type {\n IOpenAIResponsesRequestNonStreaming,\n IOpenAIResponsesRequestStreaming,\n TOpenAIResponsesStreamEvent,\n} from './responses-types';\nimport type { IOpenAIProviderOptions } from './types';\nimport type { IChatOptions, TTextDeltaCallback, TUniversalMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\nexport interface IOpenAIResponsesChatOptions {\n client?: OpenAI;\n messages: TUniversalMessage[];\n chatOptions?: IChatOptions;\n providerOptions: IOpenAIProviderOptions;\n onTextDelta?: TTextDeltaCallback;\n /** Per-request headers (trusted `traceparent`), sent after the raw request payload is captured. */\n requestHeaders?: Readonly<Record<string, string>>;\n}\n\ninterface IResponsesStreamMessageQueue {\n deltas: TUniversalMessage[];\n finalMessage?: TUniversalMessage;\n error?: Error;\n wake?: () => void;\n}\n\nexport async function chatWithOpenAIResponsesApi(\n input: IOpenAIResponsesChatOptions,\n): Promise<TUniversalMessage> {\n const textDeltaCb = input.chatOptions?.onTextDelta ?? input.onTextDelta;\n if (textDeltaCb) {\n return chatWithOpenAIResponsesStreamingAssembly({\n ...input,\n chatOptions: {\n ...input.chatOptions,\n onTextDelta: textDeltaCb,\n },\n });\n }\n\n if (!input.client) {\n throw new Error('OpenAI Responses client not available.');\n }\n\n try {\n const requestParams = buildResponsesRequestParams(input);\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'responses',\n payloadKind: 'request',\n payload: requestParams,\n });\n const response = await input.client.responses.create(\n requestParams as OpenAI.Responses.ResponseCreateParamsNonStreaming,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n );\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'responses',\n payloadKind: 'response',\n payload: response,\n });\n return withProviderRequestId(\n parseOpenAIResponsesResponse(response),\n readOpenAIRequestId(response),\n );\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI responses failed');\n }\n}\n\nexport async function* chatStreamWithOpenAIResponsesApi(\n input: IOpenAIResponsesChatOptions,\n): AsyncIterable<TUniversalMessage> {\n const queue: IResponsesStreamMessageQueue = { deltas: [] };\n const textDeltaCb = input.chatOptions?.onTextDelta ?? input.onTextDelta;\n const assembly = chatWithOpenAIResponsesStreamingAssembly({\n ...input,\n chatOptions: {\n ...input.chatOptions,\n onTextDelta: (delta) => {\n textDeltaCb?.(delta);\n enqueueStreamDelta(queue, createStreamDeltaMessage(delta));\n },\n },\n })\n .then((result) => finishStreamQueue(queue, result))\n .catch((error) => failStreamQueue(queue, toError(error)));\n\n yield* drainResponsesStreamQueue(queue);\n await assembly;\n}\n\nasync function chatWithOpenAIResponsesStreamingAssembly(\n input: IOpenAIResponsesChatOptions,\n): Promise<TUniversalMessage> {\n if (!input.client) {\n throw new Error('OpenAI Responses client not available.');\n }\n\n try {\n const requestParams = buildResponsesStreamingRequestParams(input);\n input.chatOptions?.onProviderNativeRawPayload?.({\n provider: 'openai',\n apiSurface: 'responses',\n payloadKind: 'request',\n payload: requestParams,\n });\n const { data: stream, providerRequestId } = await awaitWithProviderRequestId(\n input.client.responses.create(\n requestParams as OpenAI.Responses.ResponseCreateParamsStreaming,\n openAIRequestOptions(input.chatOptions?.signal, input.requestHeaders),\n ),\n );\n const assembled = await assembleOpenAIResponsesStream({\n stream: observeProviderNativeRawPayloadStream(\n stream as AsyncIterable<TOpenAIResponsesStreamEvent>,\n {\n provider: 'openai',\n apiSurface: 'responses',\n onProviderNativeRawPayload: input.chatOptions?.onProviderNativeRawPayload,\n },\n ),\n onTextDelta: input.chatOptions?.onTextDelta,\n signal: input.chatOptions?.signal,\n });\n return withProviderRequestId(assembled, providerRequestId);\n } catch (error) {\n throw toProviderError(error, 'openai', 'OpenAI responses stream failed');\n }\n}\n\nfunction buildResponsesRequestParams(\n input: IOpenAIResponsesChatOptions,\n): IOpenAIResponsesRequestNonStreaming {\n const model = input.chatOptions?.model ?? input.providerOptions.defaultModel;\n if (!model) {\n throw new Error(\n 'Model is required in chat options. Please specify a model in defaultModel configuration.',\n );\n }\n\n const tools = convertToOpenAIResponsesTools(\n input.chatOptions?.tools,\n input.providerOptions.strictTools,\n );\n const textConfig = buildOpenAIResponsesTextConfig(input.providerOptions);\n // Native effort mapping: thread the per-call reasoning-effort dial onto the Responses\n // API `reasoning.effort` parameter, merged with any static reasoning options.\n const reasoning = resolveOpenAIReasoningOptions(\n input.providerOptions.reasoning,\n input.chatOptions?.effortResolution,\n );\n return {\n model,\n input: convertToOpenAIResponsesInput(input.messages),\n ...(tools !== undefined && {\n tools,\n tool_choice: toOpenAIResponsesToolChoice(input.chatOptions?.toolChoice),\n }),\n ...(input.chatOptions?.temperature !== undefined && {\n temperature: input.chatOptions.temperature,\n }),\n ...(input.chatOptions?.maxTokens !== undefined && {\n max_output_tokens: input.chatOptions.maxTokens,\n }),\n ...(textConfig !== undefined && { text: textConfig }),\n ...(reasoning !== undefined && {\n reasoning,\n }),\n ...(input.providerOptions.includeEncryptedReasoning === true && {\n include: ['reasoning.encrypted_content'],\n }),\n ...(input.providerOptions.store !== undefined && { store: input.providerOptions.store }),\n };\n}\n\nfunction buildResponsesStreamingRequestParams(\n input: IOpenAIResponsesChatOptions,\n): IOpenAIResponsesRequestStreaming {\n return {\n ...buildResponsesRequestParams(input),\n stream: true,\n };\n}\n\nfunction createStreamDeltaMessage(delta: string): TUniversalMessage {\n return {\n id: randomUUID(),\n role: 'assistant',\n content: delta,\n state: 'complete',\n timestamp: new Date(),\n metadata: {\n providerApiSurface: 'responses',\n isStreamChunk: true,\n isComplete: false,\n },\n };\n}\n\nasync function* drainResponsesStreamQueue(\n queue: IResponsesStreamMessageQueue,\n): AsyncIterable<TUniversalMessage> {\n while (true) {\n const next = queue.deltas.shift();\n if (next !== undefined) {\n yield next;\n continue;\n }\n if (queue.error !== undefined) {\n throw queue.error;\n }\n if (queue.finalMessage !== undefined) {\n yield createFinalStreamMessage(queue.finalMessage);\n return;\n }\n await waitForStreamQueue(queue);\n }\n}\n\nfunction enqueueStreamDelta(queue: IResponsesStreamMessageQueue, message: TUniversalMessage): void {\n queue.deltas.push(message);\n wakeStreamQueue(queue);\n}\n\nfunction finishStreamQueue(queue: IResponsesStreamMessageQueue, result: TUniversalMessage): void {\n queue.finalMessage = result;\n wakeStreamQueue(queue);\n}\n\nfunction failStreamQueue(queue: IResponsesStreamMessageQueue, error: Error): void {\n queue.error = error;\n wakeStreamQueue(queue);\n}\n\nfunction waitForStreamQueue(queue: IResponsesStreamMessageQueue): Promise<void> {\n return new Promise((resolve) => {\n queue.wake = resolve;\n });\n}\n\nfunction wakeStreamQueue(queue: IResponsesStreamMessageQueue): void {\n queue.wake?.();\n queue.wake = undefined;\n}\n\nfunction createFinalStreamMessage(result: TUniversalMessage): TUniversalMessage {\n return {\n ...result,\n content: '',\n metadata: {\n ...result.metadata,\n isStreamChunk: true,\n isComplete: true,\n },\n };\n}\n\nfunction toError(error: Error | string): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n","import { randomUUID } from 'node:crypto';\nimport { AbstractAIProvider } from '@robota-sdk/agent-core';\nimport { createModelEffortOutcome } from '@robota-sdk/agent-core';\nimport { PERMISSIVE_TOOL_SCHEMA_PROFILE, STRICT_TOOL_SCHEMA_PROFILE } from '@robota-sdk/agent-core';\nimport { resolveModelEffort } from '@robota-sdk/agent-core';\nimport { SilentLogger } from '@robota-sdk/agent-core';\nimport { traceHeadersFor } from '@robota-sdk/agent-core';\nimport OpenAI from 'openai';\n\nimport {\n chatStreamWithOpenAIChatCompletions,\n chatWithOpenAIChatCompletions,\n} from './chat-completions-chat';\nimport { OPENAI_MODEL_EFFORT_TABLE } from './model-effort-table';\nimport { OpenAIResponseParser } from './parsers/response-parser';\nimport { chatStreamWithOpenAIResponsesApi, chatWithOpenAIResponsesApi } from './responses-chat';\n\nimport type { IPayloadLogger } from './interfaces/payload-logger';\nimport type { IOpenAIProviderOptions, TOpenAIApiSurface } from './types';\nimport type {\n TUniversalMessage,\n IChatOptions,\n IAssistantMessage,\n IProviderCapabilities,\n IProviderModelEffortTable,\n IToolSchemaProjectionProfile,\n TTextDeltaCallback,\n} from '@robota-sdk/agent-core';\n\n/**\n * OpenAI provider implementation for ConversationAgent\n *\n * Provides integration with OpenAI models through the ConversationAgent provider contract.\n * Uses OpenAI SDK native types internally for optimal performance and feature support.\n *\n * @public\n */\nexport class OpenAIProvider extends AbstractAIProvider {\n override readonly name = 'openai';\n override readonly version = '1.0.0';\n\n private readonly client?: OpenAI;\n private readonly options: IOpenAIProviderOptions;\n private readonly apiSurface: TOpenAIApiSurface;\n private readonly payloadLogger: IPayloadLogger | undefined;\n private readonly responseParser: OpenAIResponseParser;\n\n /**\n * Optional callback for text deltas during streaming.\n * Set by the consumer (e.g., Session) to receive real-time text chunks.\n * When set, chat() uses streaming internally while still returning\n * the complete assembled message.\n */\n onTextDelta?: TTextDeltaCallback;\n\n constructor(options: IOpenAIProviderOptions) {\n super(options.logger || SilentLogger);\n this.options = options;\n this.apiSurface = resolveApiSurface(options);\n validateOpenAIProviderNativeWebTools(this.apiSurface, options.nativeWebTools);\n\n if (options.executor) {\n this.executor = options.executor;\n }\n\n if (!this.executor) {\n if (options.client) {\n this.client = options.client;\n } else if (options.apiKey) {\n this.client = new OpenAI({\n apiKey: options.apiKey,\n ...(options.organization && { organization: options.organization }),\n ...(options.timeout && { timeout: options.timeout }),\n ...(options.baseURL && { baseURL: options.baseURL }),\n });\n } else {\n throw new Error('Either OpenAI client, apiKey, or executor is required');\n }\n }\n\n this.responseParser = new OpenAIResponseParser(this.logger);\n this.payloadLogger = options.payloadLogger;\n }\n\n override async chat(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): Promise<TUniversalMessage> {\n this.validateMessages(messages);\n this.validateNativeWebTools(options?.nativeWebTools);\n const resolvedOptions = this.resolveEffortOptions(options);\n\n if (this.executor) {\n try {\n const result = await this.executeViaExecutorOrDirect(messages, resolvedOptions);\n if (result.modelEffortOutcome === undefined) {\n this.publishModelEffortOutcome(resolvedOptions, 'opaque-executor');\n }\n return result.message;\n } catch (error) {\n this.logger.error(\n 'OpenAI Provider executor chat error:',\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n }\n }\n\n if (this.apiSurface === 'responses') {\n const response = await chatWithOpenAIResponsesApi({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n return response;\n }\n\n const response = await chatWithOpenAIChatCompletions({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n payloadLogger: this.payloadLogger,\n responseParser: this.responseParser,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n return response;\n }\n\n override async *chatStream(\n messages: TUniversalMessage[],\n options?: IChatOptions,\n ): AsyncIterable<TUniversalMessage> {\n this.validateNativeWebTools(options?.nativeWebTools);\n const resolvedOptions = this.resolveEffortOptions(options);\n\n if (this.executor) {\n try {\n let executorOutcomeSeen = false;\n for await (const event of this.executeStreamViaExecutorOrDirect(\n messages,\n resolvedOptions,\n )) {\n if (event.kind === 'message') {\n yield event.message;\n } else {\n executorOutcomeSeen = event.modelEffortOutcome !== undefined;\n }\n }\n if (!executorOutcomeSeen) {\n this.publishModelEffortOutcome(resolvedOptions, 'opaque-executor');\n }\n return;\n } catch (error) {\n this.logger.error(\n 'OpenAI Provider executor stream error:',\n error instanceof Error ? error.message : String(error),\n );\n throw error;\n }\n }\n\n yield* this.streamDirect(messages, resolvedOptions);\n }\n\n private async *streamDirect(\n messages: TUniversalMessage[],\n resolvedOptions: IChatOptions | undefined,\n ): AsyncIterable<TUniversalMessage> {\n if (this.apiSurface === 'responses') {\n yield* chatStreamWithOpenAIResponsesApi({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n return;\n }\n\n yield* chatStreamWithOpenAIChatCompletions({\n client: this.client,\n messages,\n chatOptions: this.projectChatOptions(resolvedOptions),\n providerOptions: this.options,\n payloadLogger: this.payloadLogger,\n responseParser: this.responseParser,\n onTextDelta: this.onTextDelta,\n requestHeaders: this.traceRequestHeaders(resolvedOptions),\n });\n this.publishModelEffortOutcome(resolvedOptions);\n }\n\n /**\n * CORE-043: this provider declares no capability table — nobody has verified one for OpenAI, and\n * inventing one would be a fabricated claim. It can still answer THIS question honestly, which is\n * why the endpoint signal is not a field on the table.\n *\n * It matters most here of all the providers: setting `baseURL` also switches the API surface to\n * `chat-completions` (see `resolveApiSurface`), so the advertised gateway configuration is exactly\n * the one where a structured request is least likely to be enforced by whatever is on the far end.\n */\n endpointIsVendorDefault(): boolean {\n return this.options.baseURL === undefined;\n }\n\n /**\n * The client's own base URL is the origin every request goes to (the SDK has already applied a\n * constructor option or `OPENAI_BASE_URL`). An executor sends elsewhere, and an injected client\n * whose base URL cannot be read gives no origin to compare, so neither can propagate.\n */\n canPropagateTraceContext(): boolean {\n return !this.executor && this.effectiveBaseUrl() !== undefined;\n }\n\n private effectiveBaseUrl(): string | undefined {\n const baseURL: unknown = (this.client as { baseURL?: unknown } | undefined)?.baseURL;\n return typeof baseURL === 'string' && baseURL.length > 0 ? baseURL : undefined;\n }\n\n private traceRequestHeaders(options: IChatOptions | undefined): Readonly<Record<string, string>> {\n return {\n ...(this.canPropagateTraceContext()\n ? traceHeadersFor(this.effectiveBaseUrl(), options?.outboundTraceContext)\n : {}),\n ...(this.options.durableOperations === true ? { 'Idempotency-Key': randomUUID() } : {}),\n };\n }\n\n override effortTable(): IProviderModelEffortTable | undefined {\n return this.endpointIsVendorDefault() && this.apiSurface === 'responses'\n ? OPENAI_MODEL_EFFORT_TABLE\n : undefined;\n }\n\n private resolveEffortOptions(options: IChatOptions | undefined): IChatOptions | undefined {\n if (options?.effort === undefined || options.effortResolution !== undefined) return options;\n const model = options.model ?? this.options.defaultModel;\n if (model === undefined) return options;\n return {\n ...options,\n effortResolution: resolveModelEffort(this.effortTable(), model, options.effort),\n };\n }\n\n /**\n * MCP-005: strict mode's supported subset is documented; non-strict accepts standard JSON Schema.\n * Both the Responses and Chat Completions surfaces honor `strictTools` identically (§ Profiles).\n */\n protected override projectionProfile(): IToolSchemaProjectionProfile | undefined {\n return this.options.strictTools\n ? { ...STRICT_TOOL_SCHEMA_PROFILE, providerName: 'openai' }\n : { ...PERMISSIVE_TOOL_SCHEMA_PROFILE, providerName: 'openai' };\n }\n\n /**\n * Project `chatOptions.tools` through `projectionProfile()` before either request-building module\n * (`responses-chat.ts`, `chat-completions-chat.ts`) sees them — the module helpers receive the\n * projected array as a parameter; `options.tools` itself is never mutated. An empty projected array\n * (every tool quarantined) becomes `undefined` so the downstream `tools &&` truthiness checks treat\n * it the same as \"no tools\", not as a zero-length `tools: []` request field.\n */\n private projectChatOptions(chatOptions: IChatOptions | undefined): IChatOptions | undefined {\n if (!chatOptions?.tools) {\n return chatOptions;\n }\n const model = chatOptions.model ?? this.options.defaultModel ?? '';\n const projected = this.projectTools(chatOptions.tools, model);\n return {\n ...chatOptions,\n tools: projected && projected.length > 0 ? projected : undefined,\n };\n }\n\n private publishModelEffortOutcome(\n options: IChatOptions | undefined,\n opaqueReason?: string,\n ): void {\n const resolution = options?.effortResolution;\n const observer = options?.onModelEffortOutcome;\n if (resolution === undefined || observer === undefined) return;\n\n const nativeControl =\n opaqueReason !== undefined\n ? { state: 'omitted' as const, reason: opaqueReason }\n : resolution.effective !== null && resolution.disposition !== 'model-default'\n ? { state: 'sent' as const, id: 'responses.reasoning.effort' }\n : {\n state: 'omitted' as const,\n reason:\n resolution.disposition === 'model-default'\n ? 'provider-default-selection'\n : 'model-effort-not-applied',\n };\n const providerDispatch =\n opaqueReason !== undefined\n ? { state: 'not-dispatched' as const, reason: opaqueReason }\n : { state: 'sent' as const };\n try {\n observer(createModelEffortOutcome(resolution, { nativeControl, providerDispatch }));\n } catch (error) {\n this.logger.warn('Model-effort outcome observer failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n override supportsTools(): boolean {\n return true;\n }\n\n override getCapabilities(): IProviderCapabilities {\n const source =\n this.apiSurface === 'chat-completions'\n ? 'openai-compatible-chat-completions'\n : 'openai-responses';\n return {\n functionCalling: { supported: true },\n nativeWebTools: {\n webSearch: {\n supported: false,\n enabled: false,\n source,\n reason: getOpenAIUnsupportedNativeWebReason(this.apiSurface, 'search'),\n },\n webFetch: {\n supported: false,\n enabled: false,\n source,\n reason: getOpenAIUnsupportedNativeWebReason(this.apiSurface, 'fetch'),\n },\n },\n };\n }\n\n override validateConfig(): boolean {\n return !!this.client && !!this.options;\n }\n\n override async dispose(): Promise<void> {\n // OpenAI client doesn't need explicit cleanup\n }\n\n protected override validateMessages(messages: TUniversalMessage[]): void {\n super.validateMessages(messages);\n\n for (const message of messages) {\n if (message.role === 'assistant') {\n const assistantMsg = message as IAssistantMessage;\n if (\n assistantMsg.toolCalls &&\n assistantMsg.toolCalls.length > 0 &&\n assistantMsg.content === ''\n ) {\n continue;\n }\n }\n }\n }\n}\n\nfunction resolveApiSurface(options: IOpenAIProviderOptions): TOpenAIApiSurface {\n if (options.apiSurface !== undefined) {\n return options.apiSurface;\n }\n return options.baseURL ? 'chat-completions' : 'responses';\n}\n\nfunction getOpenAIUnsupportedNativeWebReason(\n apiSurface: TOpenAIApiSurface,\n toolKind: 'search' | 'fetch',\n): string {\n if (apiSurface === 'chat-completions') {\n return `OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${toolKind}.`;\n }\n return `OpenAI Responses native web ${toolKind} is not wired in this provider version.`;\n}\n\nfunction validateOpenAIProviderNativeWebTools(\n apiSurface: TOpenAIApiSurface,\n nativeWebTools: IOpenAIProviderOptions['nativeWebTools'],\n): void {\n if (nativeWebTools?.webSearch !== true && nativeWebTools?.webFetch !== true) {\n return;\n }\n throw new Error(\n `Provider openai native web search/fetch is not supported for apiSurface ${apiSurface} in this provider version.`,\n );\n}\n","import type { TUniversalMessage, IAssistantMessage } from '@robota-sdk/agent-core';\nimport type OpenAI from 'openai';\n\n/**\n * OpenAI Conversation Adapter\n *\n * Converts between TUniversalMessage format and OpenAI native types.\n * Provides bidirectional conversion for seamless integration.\n *\n * @public\n */\nexport class OpenAIConversationAdapter {\n /**\n * Filter messages for OpenAI compatibility\n *\n * OpenAI has specific requirements:\n * - Tool messages must have valid toolCallId\n * - Messages must be in proper sequence\n * - Tool messages without toolCallId should be excluded\n */\n static filterMessagesForOpenAI(messages: TUniversalMessage[]): TUniversalMessage[] {\n return messages.filter((msg) => {\n // Always include user, assistant, and system messages\n if (msg.role === 'user' || msg.role === 'assistant' || msg.role === 'system') {\n return true;\n }\n\n // For tool messages, only include if they have a valid toolCallId\n if (msg.role === 'tool') {\n // Must have toolCallId and it must not be empty or 'unknown'\n return !!(msg.toolCallId && msg.toolCallId.trim() !== '' && msg.toolCallId !== 'unknown');\n }\n\n return false;\n });\n }\n\n /**\n * Convert TUniversalMessage array to OpenAI message format\n * Now properly handles tool messages for OpenAI's tool calling feature\n */\n static toOpenAIFormat(messages: TUniversalMessage[]): OpenAI.Chat.ChatCompletionMessageParam[] {\n // First filter messages for OpenAI compatibility\n const filteredMessages = this.filterMessagesForOpenAI(messages);\n return filteredMessages.map((msg) => this.convertMessage(msg));\n }\n\n /**\n * Convert a single TUniversalMessage to OpenAI format\n * Handles all message types including tool messages\n */\n static convertMessage(msg: TUniversalMessage): OpenAI.Chat.ChatCompletionMessageParam {\n const messageRole = msg.role;\n\n if (messageRole === 'user') {\n return {\n role: 'user',\n content: msg.content,\n };\n }\n\n if (messageRole === 'assistant') {\n const assistantMsg = msg as IAssistantMessage;\n\n // Handle tool_calls format\n if (assistantMsg.toolCalls && assistantMsg.toolCalls.length > 0) {\n const result: OpenAI.Chat.ChatCompletionAssistantMessageParam = {\n role: 'assistant',\n // CRITICAL: OpenAI API requires content to be null (not empty string) when tool_calls are present\n // VERIFIED: 2024-12 - This prevents \"400 Bad Request\" errors from OpenAI API\n // DO NOT CHANGE without testing against actual OpenAI API\n content: assistantMsg.content === '' ? null : assistantMsg.content || null,\n tool_calls: assistantMsg.toolCalls.map((toolCall) => ({\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n },\n })),\n };\n return result;\n }\n\n // Regular assistant message (without tool calls)\n // VERIFIED: OpenAI accepts both null and string content for regular messages\n // We preserve null when content is null or empty string for API consistency\n return {\n role: 'assistant',\n content:\n assistantMsg.content === null\n ? null\n : assistantMsg.content === ''\n ? null\n : assistantMsg.content || '',\n };\n }\n\n if (messageRole === 'system') {\n return {\n role: 'system',\n content: msg.content,\n };\n }\n\n // Handle tool messages for OpenAI tool calling\n if (messageRole === 'tool') {\n if (!msg.toolCallId || msg.toolCallId.trim() === '') {\n throw new Error(`Tool message missing toolCallId: ${JSON.stringify(msg)}`);\n }\n\n const result: OpenAI.Chat.ChatCompletionToolMessageParam = {\n role: 'tool',\n content: msg.content,\n tool_call_id: msg.toolCallId,\n };\n return result;\n }\n\n const exhaustive: never = messageRole;\n throw new Error(`Unsupported message role: ${exhaustive}`);\n }\n\n /**\n * Add system prompt to message array if needed\n */\n static addSystemPromptIfNeeded(\n messages: OpenAI.Chat.ChatCompletionMessageParam[],\n systemPrompt?: string,\n ): OpenAI.Chat.ChatCompletionMessageParam[] {\n if (!systemPrompt) {\n return messages;\n }\n\n // Check if system message already exists\n const hasSystemMessage = messages.some((msg) => msg.role === 'system');\n\n if (hasSystemMessage) {\n return messages;\n }\n\n // Add system prompt at the beginning\n return [{ role: 'system', content: systemPrompt }, ...messages];\n }\n}\n","import { probeOpenAICompatibleProfile } from '@robota-sdk/agent-provider-openai-compatible/shared';\n\nimport { OpenAIProvider } from './provider';\n\nimport type { IOpenAINativeWebToolsOptions, TOpenAIApiSurface } from './types';\nimport type { IProviderDefinition, TUniversalValue } from '@robota-sdk/agent-core';\n\nexport const DEFAULT_OPENAI_PROVIDER_MODEL: string | undefined = undefined;\nexport const DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE = '$ENV:OPENAI_API_KEY';\nconst OPENAI_API_KEY_URL = 'https://platform.openai.com/api-keys';\nconst OPENAI_SETUP_SOURCE_URL =\n 'https://developers.openai.com/api/reference/overview#authentication';\nconst OPENAI_SETUP_LAST_VERIFIED_AT = '2026-05-08';\nconst OPENAI_SETUP_HELP_LINKS: NonNullable<IProviderDefinition['setupHelpLinks']> = [\n {\n kind: 'api-key',\n label: 'OpenAI API keys',\n url: OPENAI_API_KEY_URL,\n sourceUrl: OPENAI_SETUP_SOURCE_URL,\n lastVerifiedAt: OPENAI_SETUP_LAST_VERIFIED_AT,\n },\n];\n\nexport function createOpenAIProviderDefinition(): IProviderDefinition {\n return {\n type: 'openai',\n displayName: 'OpenAI',\n description: 'GPT series — general-purpose assistant. API key required.',\n category: 'cloud-paid',\n // Interim provider-level cost (ARCH-PROVIDER-003), migrated from the former llm-text-openai node.\n costPerTokenUsd: 0.001,\n defaults: {\n apiKey: DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,\n },\n // OBSERVABILITY-1991: the SDK embeds this endpoint; declared here for the pre-session doctor only.\n endpoint: { host: 'api.openai.com', port: 443 },\n modelCatalog: {\n status: 'unavailable',\n sourceUrl: 'https://platform.openai.com/docs/api-reference/models/list',\n message: 'OpenAI model availability should be discovered live from GET /v1/models.',\n },\n setupHelpLinks: OPENAI_SETUP_HELP_LINKS,\n setupSteps: [\n {\n key: 'model',\n title: 'OpenAI model',\n required: true,\n },\n {\n key: 'apiKey',\n title: 'OpenAI API key',\n defaultValue: DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,\n masked: true,\n },\n ],\n requiresApiKey: true,\n probeProfile: probeOpenAICompatibleProfile,\n // The OpenAI SDK falls back to the base URL variable when none is configured, and sends the\n // organization and project the others name.\n destinationEnvironment: ['OPENAI_BASE_URL', 'OPENAI_ORG_ID', 'OPENAI_PROJECT_ID'],\n createProvider: (config) => {\n const apiSurface = readApiSurface(config.options);\n const nativeWebTools = readNativeWebTools(config.options);\n validateOpenAINativeWebTools(config.baseURL, apiSurface, nativeWebTools);\n return new OpenAIProvider({\n apiKey: requireApiKey(config.apiKey),\n ...(config.baseURL !== undefined && { baseURL: config.baseURL }),\n ...(config.timeout !== undefined && { timeout: config.timeout }),\n ...(apiSurface !== undefined && { apiSurface }),\n ...(nativeWebTools !== undefined && { nativeWebTools }),\n ...(config.options?.durableOperations === true && { durableOperations: true }),\n defaultModel: config.model,\n });\n },\n };\n}\n\nfunction requireApiKey(apiKey: string | undefined): string {\n if (!apiKey) {\n throw new Error('Provider openai requires apiKey');\n }\n return apiKey;\n}\n\nfunction readApiSurface(\n options: Record<string, TUniversalValue> | undefined,\n): TOpenAIApiSurface | undefined {\n const apiSurface = options?.['apiSurface'];\n if (apiSurface === 'responses' || apiSurface === 'chat-completions') {\n return apiSurface;\n }\n return undefined;\n}\n\nfunction readNativeWebTools(\n options: Record<string, TUniversalValue> | undefined,\n): IOpenAINativeWebToolsOptions | undefined {\n const nativeWebTools =\n readNativeWebToolsRecord(options?.['nativeWebTools']) ??\n readNativeWebToolsRecord(options?.['builtInWebTools']);\n if (nativeWebTools === undefined) {\n return undefined;\n }\n return nativeWebTools;\n}\n\nfunction readNativeWebToolsRecord(\n value: TUniversalValue | undefined,\n): IOpenAINativeWebToolsOptions | undefined {\n if (value === null || value === undefined || value instanceof Date || Array.isArray(value)) {\n return undefined;\n }\n if (typeof value !== 'object') {\n return undefined;\n }\n const webSearch = value['webSearch'];\n const webFetch = value['webFetch'];\n return {\n ...(typeof webSearch === 'boolean' && { webSearch }),\n ...(typeof webFetch === 'boolean' && { webFetch }),\n };\n}\n\nfunction validateOpenAINativeWebTools(\n baseURL: string | undefined,\n apiSurface: TOpenAIApiSurface | undefined,\n nativeWebTools: IOpenAINativeWebToolsOptions | undefined,\n): void {\n if (nativeWebTools?.webSearch !== true && nativeWebTools?.webFetch !== true) {\n return;\n }\n if (baseURL !== undefined || apiSurface === 'chat-completions') {\n throw new Error(\n 'Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.',\n );\n }\n throw new Error(\n 'Provider openai native web search/fetch is not wired in this provider version. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.',\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-provider-openai",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.87",
|
|
4
4
|
"description": "OpenAI provider implementation for Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -73,20 +73,22 @@
|
|
|
73
73
|
"vitest": "^3.2.6"
|
|
74
74
|
},
|
|
75
75
|
"license": "AGPL-3.0-only OR LicenseRef-Commercial",
|
|
76
|
-
"repository": {
|
|
77
|
-
"type": "git",
|
|
78
|
-
"url": "https://github.com/woojubb/robota.git",
|
|
79
|
-
"directory": "packages/agent-provider-openai"
|
|
80
|
-
},
|
|
81
|
-
"homepage": "https://docs.robota.io/en/packages/agent-provider-openai/",
|
|
82
76
|
"dependencies": {
|
|
83
77
|
"openai": "^4.104.0",
|
|
84
|
-
"@robota-sdk/agent-
|
|
85
|
-
"@robota-sdk/agent-
|
|
78
|
+
"@robota-sdk/agent-core": "3.0.0-beta.87",
|
|
79
|
+
"@robota-sdk/agent-provider-openai-compatible": "3.0.0-beta.87"
|
|
86
80
|
},
|
|
87
81
|
"volta": {
|
|
88
82
|
"extends": "../../package.json"
|
|
89
83
|
},
|
|
84
|
+
"repository": {
|
|
85
|
+
"type": "git",
|
|
86
|
+
"url": "https://github.com/woojubb/robota"
|
|
87
|
+
},
|
|
88
|
+
"bugs": {
|
|
89
|
+
"url": "https://github.com/woojubb/robota/issues"
|
|
90
|
+
},
|
|
91
|
+
"homepage": "https://robota.io/",
|
|
90
92
|
"scripts": {
|
|
91
93
|
"build": "rimraf dist && tsdown",
|
|
92
94
|
"build:js": "pnpm run build",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { OpenAIProvider } from '../provider';
|
|
4
|
+
import type { TUniversalMessage } from '@robota-sdk/agent-core';
|
|
5
|
+
|
|
6
|
+
const messages: TUniversalMessage[] = [
|
|
7
|
+
{ id: 'u1', role: 'user', content: 'hello', state: 'complete', timestamp: new Date() },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
describe('durable operation identity on the SDK wire', () => {
|
|
11
|
+
for (const apiSurface of ['chat-completions', 'responses'] as const) {
|
|
12
|
+
it(`preserves one identity through ${apiSurface} SDK retries and changes it for a new call`, async () => {
|
|
13
|
+
const identities: Array<string | null> = [];
|
|
14
|
+
let failed = false;
|
|
15
|
+
const client = new OpenAI({
|
|
16
|
+
apiKey: 'task-token', baseURL: 'https://company.example/v1', maxRetries: 1,
|
|
17
|
+
fetch: async (_url, init) => {
|
|
18
|
+
identities.push(new Headers(init?.headers).get('Idempotency-Key'));
|
|
19
|
+
if (!failed) {
|
|
20
|
+
failed = true;
|
|
21
|
+
return new Response('{}', { status: 503, headers: { 'retry-after-ms': '1' } });
|
|
22
|
+
}
|
|
23
|
+
const body = apiSurface === 'responses'
|
|
24
|
+
? { id: 'r1', object: 'response', status: 'completed', output: [{ type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'hi', annotations: [] }] }] }
|
|
25
|
+
: { id: 'c1', object: 'chat.completion', choices: [{ index: 0, message: { role: 'assistant', content: 'hi' }, finish_reason: 'stop' }] };
|
|
26
|
+
return new Response(JSON.stringify(body), { headers: { 'content-type': 'application/json' } });
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const provider = new OpenAIProvider({ client, apiSurface, durableOperations: true });
|
|
30
|
+
await provider.chat(messages, { model: 'test' });
|
|
31
|
+
await provider.chat(messages, { model: 'test' });
|
|
32
|
+
expect(identities).toHaveLength(3);
|
|
33
|
+
expect(identities[0]).toMatch(/^[0-9a-f-]{36}$/);
|
|
34
|
+
expect(identities[1]).toBe(identities[0]);
|
|
35
|
+
expect(identities[2]).not.toBe(identities[0]);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import type { IToolMessage } from '@robota-sdk/agent-core';
|
|
3
|
+
import { convertToOpenAIResponsesInput } from '../responses-converter';
|
|
4
|
+
import { withToolProvenance } from '@robota-sdk/agent-core';
|
|
5
|
+
|
|
6
|
+
describe('mixed function observations', () => {
|
|
7
|
+
it('transmits the registered source with the same call identity and observations', () => {
|
|
8
|
+
const observation = withToolProvenance(
|
|
9
|
+
{ success: true, data: { saved: true }, parts: [{ type: 'text', text: 'saved' }] },
|
|
10
|
+
{
|
|
11
|
+
sourceId: 'fixture-plugin',
|
|
12
|
+
component: 'save',
|
|
13
|
+
origin: 'fixture://installed',
|
|
14
|
+
version: '1',
|
|
15
|
+
},
|
|
16
|
+
);
|
|
17
|
+
const message: IToolMessage = {
|
|
18
|
+
id: 'source',
|
|
19
|
+
timestamp: new Date(0),
|
|
20
|
+
state: 'complete',
|
|
21
|
+
role: 'tool',
|
|
22
|
+
toolCallId: 'call-source',
|
|
23
|
+
content: '{"saved":true}',
|
|
24
|
+
parts: observation.parts,
|
|
25
|
+
};
|
|
26
|
+
expect(convertToOpenAIResponsesInput([message])).toMatchObject([
|
|
27
|
+
{
|
|
28
|
+
call_id: 'call-source',
|
|
29
|
+
output: [
|
|
30
|
+
{ type: 'input_text', text: '{"saved":true}' },
|
|
31
|
+
{ type: 'input_text', text: expect.stringContaining('fixture-plugin') },
|
|
32
|
+
{ type: 'input_text', text: 'saved' },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
});
|
|
37
|
+
it('sends structured data, text and images as native function output content', () => {
|
|
38
|
+
const message: IToolMessage = {
|
|
39
|
+
id: 'observation',
|
|
40
|
+
timestamp: new Date(0),
|
|
41
|
+
state: 'complete',
|
|
42
|
+
role: 'tool',
|
|
43
|
+
toolCallId: 'call',
|
|
44
|
+
content: '{"revision":1}',
|
|
45
|
+
parts: [
|
|
46
|
+
{ type: 'text', text: 'Screenshot description' },
|
|
47
|
+
{ type: 'image_inline', mimeType: 'image/png', data: 'image-bytes' },
|
|
48
|
+
{ type: 'image_uri', uri: 'https://example.test/image.png' },
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
expect(convertToOpenAIResponsesInput([message])).toEqual([
|
|
52
|
+
{
|
|
53
|
+
type: 'function_call_output',
|
|
54
|
+
call_id: 'call',
|
|
55
|
+
output: [
|
|
56
|
+
{ type: 'input_text', text: '{"revision":1}' },
|
|
57
|
+
{ type: 'input_text', text: 'Screenshot description' },
|
|
58
|
+
{ type: 'input_image', image_url: 'data:image/png;base64,image-bytes' },
|
|
59
|
+
{ type: 'input_image', image_url: 'https://example.test/image.png' },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('projects resources as untrusted observations and diagnoses unsupported audio without fetching', () => {
|
|
67
|
+
const message: IToolMessage = {
|
|
68
|
+
id: 'resource-observation',
|
|
69
|
+
timestamp: new Date(0),
|
|
70
|
+
state: 'complete',
|
|
71
|
+
role: 'tool',
|
|
72
|
+
toolCallId: 'resource-call',
|
|
73
|
+
content: '{"saved":true}',
|
|
74
|
+
metadata: { success: false },
|
|
75
|
+
parts: [
|
|
76
|
+
{
|
|
77
|
+
type: 'resource_link',
|
|
78
|
+
uri: 'https://example.test/resource.png',
|
|
79
|
+
name: 'opaque-reference',
|
|
80
|
+
mimeType: 'image/png',
|
|
81
|
+
},
|
|
82
|
+
{ type: 'resource_embedded', uri: 'fixture://receipt', text: 'actual persisted state' },
|
|
83
|
+
{
|
|
84
|
+
type: 'resource_embedded',
|
|
85
|
+
uri: 'fixture://binary',
|
|
86
|
+
mimeType: 'application/octet-stream',
|
|
87
|
+
blob: 'c2VjcmV0LWJpbmFyeQ==',
|
|
88
|
+
},
|
|
89
|
+
{ type: 'audio_inline', mimeType: 'audio/wav', data: 'YXVkaW8tYnl0ZXM=' },
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
const payload = convertToOpenAIResponsesInput([message]);
|
|
93
|
+
const serialized = JSON.stringify(payload);
|
|
94
|
+
expect(serialized).toContain('resource-call');
|
|
95
|
+
expect(serialized).toContain('https://example.test/resource.png');
|
|
96
|
+
expect(serialized).toContain('actual persisted state');
|
|
97
|
+
expect(serialized).toContain('not fetched');
|
|
98
|
+
expect(serialized).toContain('does not transmit audio');
|
|
99
|
+
expect(serialized).not.toContain('c2VjcmV0LWJpbmFyeQ==');
|
|
100
|
+
expect(serialized).not.toContain('YXVkaW8tYnl0ZXM=');
|
|
101
|
+
expect(serialized).not.toContain('input_image');
|
|
102
|
+
expect(serialized).not.toContain('"type":"image"');
|
|
103
|
+
});
|
|
@@ -17,7 +17,7 @@ vi.mock('fs', () => {
|
|
|
17
17
|
|
|
18
18
|
// SEC-003: `fs` is mocked, so this is an inert fixture path; it deliberately does not
|
|
19
19
|
// live under the OS temp dir.
|
|
20
|
-
const LOG_DIR = '/var/
|
|
20
|
+
const LOG_DIR = '/var/agent-test/openai-payload-logs';
|
|
21
21
|
|
|
22
22
|
function createMockLogger(): ILogger {
|
|
23
23
|
return {
|
|
@@ -68,6 +68,7 @@ export function createOpenAIProviderDefinition(): IProviderDefinition {
|
|
|
68
68
|
...(config.timeout !== undefined && { timeout: config.timeout }),
|
|
69
69
|
...(apiSurface !== undefined && { apiSurface }),
|
|
70
70
|
...(nativeWebTools !== undefined && { nativeWebTools }),
|
|
71
|
+
...(config.options?.durableOperations === true && { durableOperations: true }),
|
|
71
72
|
defaultModel: config.model,
|
|
72
73
|
});
|
|
73
74
|
},
|
|
@@ -130,10 +131,10 @@ function validateOpenAINativeWebTools(
|
|
|
130
131
|
}
|
|
131
132
|
if (baseURL !== undefined || apiSurface === 'chat-completions') {
|
|
132
133
|
throw new Error(
|
|
133
|
-
'Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use
|
|
134
|
+
'Provider openai profile uses an OpenAI-compatible Chat Completions endpoint; native web search/fetch is not supported for this profile. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.',
|
|
134
135
|
);
|
|
135
136
|
}
|
|
136
137
|
throw new Error(
|
|
137
|
-
'Provider openai native web search/fetch is not wired in this
|
|
138
|
+
'Provider openai native web search/fetch is not wired in this provider version. Use local WebSearch/WebFetch tools or a provider with documented hosted web support.',
|
|
138
139
|
);
|
|
139
140
|
}
|
package/src/openai/provider.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { AbstractAIProvider } from '@robota-sdk/agent-core';
|
|
2
3
|
import { createModelEffortOutcome } from '@robota-sdk/agent-core';
|
|
3
4
|
import { PERMISSIVE_TOOL_SCHEMA_PROFILE, STRICT_TOOL_SCHEMA_PROFILE } from '@robota-sdk/agent-core';
|
|
@@ -27,9 +28,9 @@ import type {
|
|
|
27
28
|
} from '@robota-sdk/agent-core';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
* OpenAI provider implementation for
|
|
31
|
+
* OpenAI provider implementation for ConversationAgent
|
|
31
32
|
*
|
|
32
|
-
* Provides integration with OpenAI models through the
|
|
33
|
+
* Provides integration with OpenAI models through the ConversationAgent provider contract.
|
|
33
34
|
* Uses OpenAI SDK native types internally for optimal performance and feature support.
|
|
34
35
|
*
|
|
35
36
|
* @public
|
|
@@ -226,8 +227,12 @@ export class OpenAIProvider extends AbstractAIProvider {
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
private traceRequestHeaders(options: IChatOptions | undefined): Readonly<Record<string, string>> {
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
return {
|
|
231
|
+
...(this.canPropagateTraceContext()
|
|
232
|
+
? traceHeadersFor(this.effectiveBaseUrl(), options?.outboundTraceContext)
|
|
233
|
+
: {}),
|
|
234
|
+
...(this.options.durableOperations === true ? { 'Idempotency-Key': randomUUID() } : {}),
|
|
235
|
+
};
|
|
231
236
|
}
|
|
232
237
|
|
|
233
238
|
override effortTable(): IProviderModelEffortTable | undefined {
|
|
@@ -376,7 +381,7 @@ function getOpenAIUnsupportedNativeWebReason(
|
|
|
376
381
|
if (apiSurface === 'chat-completions') {
|
|
377
382
|
return `OpenAI-compatible Chat Completions endpoints support declared function tools, not provider-native web ${toolKind}.`;
|
|
378
383
|
}
|
|
379
|
-
return `OpenAI Responses native web ${toolKind} is not wired in this
|
|
384
|
+
return `OpenAI Responses native web ${toolKind} is not wired in this provider version.`;
|
|
380
385
|
}
|
|
381
386
|
|
|
382
387
|
function validateOpenAIProviderNativeWebTools(
|
|
@@ -387,6 +392,6 @@ function validateOpenAIProviderNativeWebTools(
|
|
|
387
392
|
return;
|
|
388
393
|
}
|
|
389
394
|
throw new Error(
|
|
390
|
-
`Provider openai native web search/fetch is not supported for apiSurface ${apiSurface} in this
|
|
395
|
+
`Provider openai native web search/fetch is not supported for apiSurface ${apiSurface} in this provider version.`,
|
|
391
396
|
);
|
|
392
397
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nonVisualObservationText } from '@robota-sdk/agent-core';
|
|
1
2
|
import type {
|
|
2
3
|
IOpenAIResponsesFunctionTool,
|
|
3
4
|
IOpenAIResponsesMessageInput,
|
|
@@ -57,7 +58,15 @@ function convertMessage(message: TUniversalMessage): TOpenAIResponsesInputItem[]
|
|
|
57
58
|
{
|
|
58
59
|
type: 'function_call_output',
|
|
59
60
|
call_id: message.toolCallId,
|
|
60
|
-
output: message.
|
|
61
|
+
output: message.parts?.length
|
|
62
|
+
? [
|
|
63
|
+
...(message.content &&
|
|
64
|
+
!message.parts.some((part) => part.type === 'text' && part.text === message.content)
|
|
65
|
+
? [{ type: 'input_text' as const, text: message.content }]
|
|
66
|
+
: []),
|
|
67
|
+
...message.parts.map(convertPart),
|
|
68
|
+
]
|
|
69
|
+
: message.content || '',
|
|
61
70
|
},
|
|
62
71
|
];
|
|
63
72
|
}
|
|
@@ -105,10 +114,11 @@ function convertPart(part: TUniversalMessagePart): TOpenAIResponsesInputContent
|
|
|
105
114
|
if (part.type === 'image_uri') {
|
|
106
115
|
return { type: 'input_image', image_url: part.uri };
|
|
107
116
|
}
|
|
108
|
-
return {
|
|
117
|
+
if (part.type === 'image_inline') return {
|
|
109
118
|
type: 'input_image',
|
|
110
119
|
image_url: `data:${part.mimeType};base64,${part.data}`,
|
|
111
120
|
};
|
|
121
|
+
return { type: 'input_text', text: nonVisualObservationText(part) ?? 'Unsupported observation' };
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
function createMessageInput(
|
|
@@ -37,7 +37,7 @@ export interface IOpenAIResponsesFunctionCallInput {
|
|
|
37
37
|
export interface IOpenAIResponsesFunctionCallOutputInput {
|
|
38
38
|
type: 'function_call_output';
|
|
39
39
|
call_id: string;
|
|
40
|
-
output: string;
|
|
40
|
+
output: string | TOpenAIResponsesInputContent[];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export type TOpenAIResponsesInputItem =
|
package/src/openai/types.ts
CHANGED
|
@@ -45,6 +45,8 @@ export type TOpenAIProviderOptionValue =
|
|
|
45
45
|
* OpenAI provider options
|
|
46
46
|
*/
|
|
47
47
|
export interface IOpenAIProviderOptions {
|
|
48
|
+
/** Emit one operation ID per model request, preserved by SDK retries, for durable company gateways. */
|
|
49
|
+
durableOperations?: boolean;
|
|
48
50
|
/**
|
|
49
51
|
* Additional provider-specific options
|
|
50
52
|
*/
|
|
@@ -165,7 +167,7 @@ export interface IOpenAIProviderOptions {
|
|
|
165
167
|
/**
|
|
166
168
|
* Provider-native hosted web tool request from provider profile options.
|
|
167
169
|
*
|
|
168
|
-
* OpenAI-compatible Chat Completions endpoints do not support this
|
|
170
|
+
* OpenAI-compatible Chat Completions endpoints do not support this ConversationAgent
|
|
169
171
|
* native web contract. The provider rejects unsupported configurations before
|
|
170
172
|
* any model request is sent.
|
|
171
173
|
*/
|