@robota-sdk/agent-provider-openai 3.0.0-beta.82 → 3.0.0-beta.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +231 -0
  2. package/README.md +135 -0
  3. package/dist/node/index.cjs +1 -1
  4. package/dist/node/index.d.cts +8 -3
  5. package/dist/node/index.d.cts.map +1 -1
  6. package/dist/node/index.d.ts +8 -3
  7. package/dist/node/index.d.ts.map +1 -1
  8. package/dist/node/index.js +1 -1
  9. package/dist/node/index.js.map +1 -1
  10. package/dist/node/loggers/index.d.cts +6 -6
  11. package/dist/node/loggers/index.d.cts.map +1 -1
  12. package/dist/node/loggers/index.d.ts +6 -6
  13. package/dist/node/loggers/index.d.ts.map +1 -1
  14. package/dist/node/loggers/index.js.map +1 -1
  15. package/dist/node/{payload-logger-BaW0K8yI.d.ts → payload-logger-n89AQdUn.d.cts} +6 -4
  16. package/dist/node/payload-logger-n89AQdUn.d.cts.map +1 -0
  17. package/dist/node/{payload-logger-BaW0K8yI.d.cts → payload-logger-n89AQdUn.d.ts} +6 -4
  18. package/dist/node/payload-logger-n89AQdUn.d.ts.map +1 -0
  19. package/package.json +11 -5
  20. package/src/openai/__tests__/abort-signal-wire.test.ts +210 -0
  21. package/src/openai/__tests__/provider-errors.test.ts +34 -5
  22. package/src/openai/__tests__/strict-tools-closure.test.ts +49 -2
  23. package/src/openai/__tests__/tool-schema-projection.test.ts +16 -2
  24. package/src/openai/chat-completions-chat.ts +2 -2
  25. package/src/openai/interfaces/payload-logger.ts +5 -3
  26. package/src/openai/loggers/console-payload-logger.ts +2 -2
  27. package/src/openai/loggers/file-payload-logger.ts +6 -5
  28. package/src/openai/message-converter.ts +7 -3
  29. package/src/openai/responses-parser.test.ts +87 -0
  30. package/src/openai/responses-parser.ts +15 -9
  31. package/src/openai/responses-types.ts +2 -0
  32. package/src/openai/types.ts +7 -2
  33. package/dist/node/payload-logger-BaW0K8yI.d.cts.map +0 -1
  34. package/dist/node/payload-logger-BaW0K8yI.d.ts.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,231 @@
1
+ # @robota-sdk/agent-provider-openai
2
+
3
+ ## 3.0.0-beta.84
4
+
5
+ ### Patch Changes
6
+
7
+ - 9c6a8db: Provider adapters now throw the specific typed failure a vendor response describes, instead of a
8
+ generic `ProviderError` carrying only its status. A 401/403 (or a vendor-specific authentication type)
9
+ becomes an `AuthenticationError`; a response naming an unavailable model — by code or, when the vendor
10
+ gives neither (Anthropic's and Gemini's real bodies carry no distinguishing code), by its message —
11
+ becomes a `ModelNotAvailableError`, whose `model` is now optional since a bare HTTP status does not
12
+ always name one; a transport failure becomes a `NetworkError`, which now also carries the provider
13
+ name. A 429's `retry-after` header (a delta or an HTTP-date) is read into `RateLimitError.retryAfter`
14
+ when the vendor sends one.
15
+
16
+ Vendor error text is scrubbed of anything that reads like a credential — an `Authorization`/`Bearer`
17
+ value, an API key in a header, query string or JSON body, a bare `sk-`/`AIza…` token — before it is
18
+ kept on any of these typed errors, so a misconfigured self-hosted gateway that echoes a request back
19
+ can no longer leak one into a message or a "Details" disclosure. The new `scrubSecrets` export applies
20
+ the same scrubbing to arbitrary text.
21
+
22
+ - Updated dependencies [9f46375]
23
+ - Updated dependencies [9c6a8db]
24
+ - @robota-sdk/agent-core@3.0.0-beta.84
25
+ - @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.84
26
+
27
+ ## 3.0.0-beta.83
28
+
29
+ ### Patch Changes
30
+
31
+ - 8bd5fac: Cached input tokens are no longer dropped (#3209 R3). The OpenAI and OpenAI-compatible adapters read
32
+ `prompt_tokens_details.cached_tokens` (Chat Completions, including the final streamed usage chunk) and
33
+ `input_tokens_details.cached_tokens` (Responses, OpenAI and Qwen) into `cacheReadTokens` on the message
34
+ usage: the part of the prompt served from the provider's prompt cache, present only when reported.
35
+ It reaches the committed assistant message, `readTokenUsageFromMessage()`, and the
36
+ `provider_call_completed` execution event, so a consumer can apply the cache discount.
37
+
38
+ New `sumMessagesUsage(messages)` sums the usage on assistant messages (with `cacheReadTokens` when any
39
+ reported it), so one run's usage is `sumMessagesUsage(agent.getHistory().slice(before))` without
40
+ converting through `messageToHistoryEntry` (#3209 S1). `sumHistoryUsage` returns the same triple as before.
41
+
42
+ A forced-summary reply now keeps the usage its provider reported the same way a tool round's reply
43
+ does: an endpoint that omits `total_tokens` no longer loses exactly the summary call's usage (#3209 N3). Counts
44
+ the adapter could not attest as a consistent total are recorded with `usageProvenance: 'partial'`.
45
+
46
+ - 274328f: `OpenAIProvider({ strictTools: true })` now requests strict function calling on the Chat Completions
47
+ surface too (each tool is sent with `function.strict: true`), not only on the Responses surface. This
48
+ matters for every provider created with a `baseURL`, which defaults to Chat Completions. With
49
+ `strictTools` off the request is unchanged. `convertToOpenAICompatibleTools` accepts an optional
50
+ `{ strict }` argument.
51
+ - 57280bf: Every published package now declares `"engines": { "node": ">=22.12.0" }`. Before, 27 of the 38
52
+ packages declared no floor (`agent-core`, `agent-tools` and every provider among them),
53
+ `agent-session` and `agent-file-authority` declared `>=20.19.0`, and the other nine declared
54
+ `>=22.0.0`, so a consumer on Node 20 saw at most a warning from a transitive dependency.
55
+
56
+ Why 22.12: `agent-cli` and `agent-ui-terminal` need Node 22 through `ink` 7, and the CommonJS entries
57
+ of `agent-tools` and its dependents, `agent-transport`/`node` and its dependents, and
58
+ `agent-ui-terminal` `require()` ESM-only dependencies (`p-limit`, `jose`, `chalk`), which Node 22
59
+ supports unflagged only from 22.12. `engines` is advisory unless the consumer enables `engine-strict`.
60
+
61
+ No code changes: `tsdown` now reads `node22.12.0` as its build target from the field.
62
+
63
+ - 643effb: Aborting a run now cancels the provider's HTTP request on every call path. The non-streaming
64
+ `chat()` request — the one a forced end-of-round summary makes — sent no `AbortSignal` on OpenAI
65
+ Chat Completions, DeepSeek, Qwen (Chat Completions) and Gemma, so an aborted run left that request
66
+ running to completion; the same held for `chatStream()` on DeepSeek, Qwen (Chat Completions), Gemma
67
+ and Anthropic. Each now hands the call's `signal` to the SDK request.
68
+ - 18c0d5c: Every published package now exports `./package.json`, so `require('<package>/package.json')` and
69
+ `import('<package>/package.json', { with: { type: 'json' } })` work instead of failing with
70
+ `ERR_PACKAGE_PATH_NOT_EXPORTED`, and each tarball now ships the package's `CHANGELOG.md`.
71
+ - Updated dependencies [e689c8e]
72
+ - Updated dependencies [be0e53c]
73
+ - Updated dependencies [8bd5fac]
74
+ - Updated dependencies [274328f]
75
+ - Updated dependencies [57280bf]
76
+ - Updated dependencies [5033dd9]
77
+ - Updated dependencies [643effb]
78
+ - Updated dependencies [18c0d5c]
79
+ - Updated dependencies [dbd888d]
80
+ - Updated dependencies [1887e54]
81
+ - @robota-sdk/agent-core@3.0.0-beta.83
82
+ - @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.83
83
+
84
+ ## 3.0.0-beta.82
85
+
86
+ ### Patch Changes
87
+
88
+ - Updated dependencies [c7f9203]
89
+ - @robota-sdk/agent-core@3.0.0-beta.82
90
+ - @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.82
91
+
92
+ ## 3.0.0-beta.81
93
+
94
+ ### Patch Changes
95
+
96
+ - Updated dependencies [3038eb7]
97
+ - Updated dependencies [02b7452]
98
+ - Updated dependencies [ec5e477]
99
+ - @robota-sdk/agent-core@3.0.0-beta.81
100
+ - @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.81
101
+
102
+ ## 3.0.0-beta.80
103
+
104
+ ### Minor Changes
105
+
106
+ - 1698be4: A child-process subagent can no longer send the parent's provider credential to a different
107
+ endpoint.
108
+
109
+ - **Before spawning a child**, the parent compares every environment variable that decides where
110
+ the provider connects or which credential it sends. If the child's environment differs, the job
111
+ is refused before the credential leaves the parent. The error names the variable, never its
112
+ value. The variables compared are:
113
+ - the proxy and TLS variables;
114
+ - the variables the provider's SDK reads, such as `OPENAI_BASE_URL`, `ANTHROPIC_AUTH_TOKEN` and
115
+ the Vertex settings;
116
+ - the credential's own variable.
117
+ - **The child** repeats the check before it builds its provider. It builds that provider from the
118
+ parent's effective connection exactly: it no longer fills in a base URL, options or a default
119
+ credential from its own registry, and a credential reference that resolves to nothing is refused.
120
+ - **Where the effective connection comes from:** the parent applies its own definition defaults
121
+ (base URL, options). `profileName` is sent only when it names the connection actually sent.
122
+ - **New contracts:**
123
+ - `IProviderDefinition.destinationEnvironment`, declared by every built-in provider.
124
+ - `createProviderFromExactProfile`, `connectionEnvironmentNames`,
125
+ `findConnectionEnvironmentDivergence`, `sealConnectionEnvironment`,
126
+ `verifyConnectionEnvironment` and `TRANSPORT_ENVIRONMENT`.
127
+ - The start payload's `connectionCheck`.
128
+ - The child-process runner's `providerDefinitions` option, now required: a provider with no
129
+ definition there is refused, because its connection cannot be checked.
130
+
131
+ - 4c73a0b: Provider failures keep the vendor's HTTP status and error type. `ProviderError` gains `status` and `type`, adapters throw `ProviderError` (or `RateLimitError` for a rate limit) instead of a bare `Error`, an Anthropic mid-stream `overloaded_error` event surfaces as a `ProviderError` with that type, and media errors carry `status`. New `classifyProviderFailure` says whether a failure is worth retrying on another model, and `toProviderError` is the shared adapter mapping.
132
+ - 7937c19: Split the `@robota-sdk/agent-provider` monolith into SDK-aligned leaf packages (ARCH-PROVIDER-002 Stage A). The single package that hard-bundled all three vendor SDKs (`@anthropic-ai/sdk`, `openai`, `@google/genai`) is **removed** and replaced by per-vendor leaves, each depending only on `@robota-sdk/agent-core` + its one SDK: `@robota-sdk/agent-provider-anthropic`, `@robota-sdk/agent-provider-openai`, `@robota-sdk/agent-provider-openai-compatible` (DeepSeek/Qwen/Gemma over the shared OpenAI-compatible base), `@robota-sdk/agent-provider-gemini` (+ a `./google` entry), and `@robota-sdk/agent-provider-bytedance` (media/video `IVideoGenerationProvider`). The aggregated `createDefaultProviderDefinitions()` now lives in the new `@robota-sdk/agent-builtin-providers` leaf.
133
+
134
+ Migration: replace `@robota-sdk/agent-provider/<vendor>` imports with the corresponding `@robota-sdk/agent-provider-<vendor>` package (`/deepseek`, `/qwen`, `/gemma` → `@robota-sdk/agent-provider-openai-compatible`; `/google` → `@robota-sdk/agent-provider-gemini/google`), and import `createDefaultProviderDefinitions` from `@robota-sdk/agent-builtin-providers`. Consumers now pull only the vendor SDK(s) they actually use.
135
+
136
+ ### Patch Changes
137
+
138
+ - 9fbab1b: Provider DIP Stage B (ARCH-PROVIDER-003), part 1: collapse infrastructure. Adds the
139
+ provider-registry-driven `@robota-sdk/dag-node-llm-text` node that supersedes the
140
+ per-vendor LLM nodes + router, relocates the provider config resolver into
141
+ `agent-core`, adds SSOT cost/allowedModels fields, inverts the `llm-text` validator
142
+ tombstone, and wires `createDagFramework({ providers })`. Additive — the per-vendor
143
+ nodes still exist; consumer migration + their removal follow in part 2.
144
+ - 4f3c075: Assemble complete, verified package generations before switching build output; preserve the previous generation on build failure and pack only verified regular-file images. Include copied CLI web assets in affected-build ordering and artifact transfer. Preserve the CLI version in managed build paths. Public runtime contracts remain compatible (patch).
145
+ - b6d14ce: Make the universal JSON-schema subset able to express an object, so a nested `z.object()` keeps its
146
+ properties and required fields instead of reaching the model as `{ "type": "object" }`. Tools and
147
+ structured-output schemas with one level of nesting are now advertised in full and enforced on the
148
+ tool-input path; `z.union` / `z.discriminatedUnion` / `z.literal` are supported and map to `anyOf`
149
+ and single-value enums; `.nullable()` keeps its null branch; and Zod's `strip`, `strict` and
150
+ `passthrough` modes stop collapsing into two `additionalProperties` emissions. Fixes the shipped
151
+ `Computer` and `AskUserQuestion` built-ins, whose action and question fields were being dropped
152
+ entirely.
153
+
154
+ `agent-core` is **minor**, not patch: `IObjectParameterSchema` is a new export, and
155
+ `IParameterSchema.type` became optional (a union node carries `anyOf` instead of a type), which is a
156
+ consumer-visible type change — two call sites in this repo needed editing to keep compiling.
157
+ `additionalProperties` also widened to `boolean | IParameterSchema`, and `required` and `anyOf` are
158
+ new members. The provider packages are **patch**: each adapts to the widened subset without changing
159
+ its own public surface.
160
+
161
+ - 93d061d: CORE-043: structured output now knows which transport can carry the schema before the first call
162
+
163
+ `run(input, { output })` asked every provider for `responseFormat: { type: 'json_schema' }`. A
164
+ provider whose surface cannot express that accepted the option and dropped it — and the schema was
165
+ stated in words only by the RETRY feedback turn, which runs on attempt two. So against such a
166
+ provider, attempt one carried nothing describing the required shape and could only succeed by luck:
167
+ the advertised three attempts were really two, and the first was spent discovering something the
168
+ capability table already knew.
169
+
170
+ A `(provider, model)` pair now resolves to a mechanism (`response_schema` / `json_object` / `none`)
171
+ and a provenance (`catalog` / `vendor-default` / `undeclared` / `unverified-endpoint`), and the
172
+ request is shaped to match at the one seam that holds both the resolved provider and the outgoing
173
+ messages. When the wire cannot carry the shape, the schema is stated in the prompt on the FIRST
174
+ attempt. Each structured request emits a `structured_output_transport` event reporting what the
175
+ request actually did.
176
+
177
+ - `IAIProvider.endpointIsVendorDefault?()` — a provider configured with a custom `baseURL` reports
178
+ it, so the runtime stops claiming enforcement a gateway may not provide. Separate from
179
+ `capabilityTable?()` on purpose: `@robota-sdk/agent-provider-openai` declares no table (nobody has
180
+ verified one) and must still be able to answer.
181
+ - DeepSeek's capability table declared `json_schema`; DeepSeek guarantees the response PARSES but
182
+ takes no schema parameter. Corrected to `json_object`.
183
+ - A provider that declares nothing is still sent the request unchanged — silence is not a denial.
184
+
185
+ - ebd40a0: Harden on-disk log permissions against CWE-377 (SEC-003, CodeQL `js/insecure-temporary-file`).
186
+
187
+ Session logs, externalized session payloads, and OpenAI request/response payload logs all carry
188
+ conversation and prompt content, but were created with the process umask (typically `0644`) inside a
189
+ caller-supplied directory that may be shared or world-writable. They are now created owner-only
190
+ (`0600`), and the directories that hold them are created `0700`.
191
+
192
+ This is a permissions change only — file locations, names, formats, and APIs are unchanged. Anything
193
+ that read these logs as a _different_ OS user will no longer be able to; the owning user is
194
+ unaffected.
195
+
196
+ - Updated dependencies [7b6234c]
197
+ - Updated dependencies [4eea54b]
198
+ - Updated dependencies [1698be4]
199
+ - Updated dependencies [d4189b9]
200
+ - Updated dependencies [9edae52]
201
+ - Updated dependencies [4078a72]
202
+ - Updated dependencies [4c73a0b]
203
+ - Updated dependencies [196a900]
204
+ - Updated dependencies [f336838]
205
+ - Updated dependencies [34e50f0]
206
+ - Updated dependencies [722e88a]
207
+ - Updated dependencies [d23c848]
208
+ - Updated dependencies [fec722f]
209
+ - Updated dependencies [2d3b2c0]
210
+ - Updated dependencies [4772067]
211
+ - Updated dependencies [7937c19]
212
+ - Updated dependencies [9fbab1b]
213
+ - Updated dependencies [a009f5b]
214
+ - Updated dependencies [4f3c075]
215
+ - Updated dependencies [475e085]
216
+ - Updated dependencies [e477440]
217
+ - Updated dependencies [9dcb5da]
218
+ - Updated dependencies [a95ca85]
219
+ - Updated dependencies [b6d14ce]
220
+ - Updated dependencies [0382a51]
221
+ - Updated dependencies [93d061d]
222
+ - Updated dependencies [39554a1]
223
+ - Updated dependencies [d28430a]
224
+ - Updated dependencies [07b627f]
225
+ - Updated dependencies [d0de5b2]
226
+ - Updated dependencies [2916d00]
227
+ - Updated dependencies [7669851]
228
+ - Updated dependencies [d6b9404]
229
+ - Updated dependencies [9814afc]
230
+ - @robota-sdk/agent-core@3.0.0-beta.80
231
+ - @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.80
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # @robota-sdk/agent-provider-openai
2
+
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 `Robota` agent can run on OpenAI models with
5
+ streaming and tool calling. It is a protocol client rather than a vendor lock: set `baseURL` and the
6
+ same provider talks to any OpenAI-compatible endpoint (AI gateways such as Vercel AI Gateway,
7
+ LiteLLM or OpenRouter, Azure OpenAI, vLLM, Ollama, LM Studio), with model ids passed through
8
+ verbatim.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @robota-sdk/agent-provider-openai @robota-sdk/agent-core
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```typescript
19
+ import { Robota } from '@robota-sdk/agent-core';
20
+ import { OpenAIProvider } from '@robota-sdk/agent-provider-openai';
21
+
22
+ const provider = new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY });
23
+
24
+ const agent = new Robota({
25
+ name: 'MyAgent',
26
+ aiProviders: [provider],
27
+ defaultModel: { provider: 'openai', model: 'gpt-4o' },
28
+ });
29
+
30
+ const response = await agent.run('Hello!');
31
+ console.log(response);
32
+ ```
33
+
34
+ The provider registers under the name `openai`, which is the value `defaultModel.provider` must use.
35
+
36
+ ### OpenAI-compatible endpoints
37
+
38
+ ```typescript
39
+ import { OpenAIProvider } from '@robota-sdk/agent-provider-openai';
40
+
41
+ // An OpenAI-protocol gateway serving a non-OpenAI model
42
+ const provider = new OpenAIProvider({
43
+ apiKey: process.env.AI_GATEWAY_API_KEY,
44
+ baseURL: 'https://ai-gateway.vercel.sh/v1',
45
+ });
46
+ // then: defaultModel: { provider: 'openai', model: 'anthropic/claude-sonnet-4-5' }
47
+ // (a gateway model slug, passed through to the gateway as written)
48
+ ```
49
+
50
+ The API surface follows `baseURL` unless `apiSurface` is set:
51
+
52
+ | Configuration | API surface |
53
+ | --------------------- | --------------------------------------- |
54
+ | No `baseURL` | Responses API (`'responses'`) |
55
+ | `baseURL` set | Chat Completions (`'chat-completions'`) |
56
+ | `apiSurface` provided | The surface you set, either way |
57
+
58
+ ### Strict tools
59
+
60
+ `strictTools: true` closes tool object schemas and requests OpenAI strict function calling. Every
61
+ object node of a tool's parameter schema, nested ones included, gets `additionalProperties: false`
62
+ and a complete `required` list, with optional properties turned into nullable ones, and each function
63
+ tool is sent with `strict: true` on both the Responses and Chat Completions surfaces. An
64
+ OpenAI-compatible endpoint that rejects the `strict` field needs `strictTools` left off. With
65
+ `strictTools` off (the default) tool schemas are forwarded as authored and no `strict` field is sent.
66
+
67
+ ### Reasoning effort and web tools
68
+
69
+ A reasoning-effort selection (`defaultModel.effort` on a `Robota` agent, or `effort` on a chat call)
70
+ is sent as `reasoning.effort` only on the official Responses API (no `baseURL`) and only for models
71
+ in the provider's verified effort table. On Chat Completions, behind a custom `baseURL`, or for other
72
+ models, the effort is reported as not applied and no native field is sent. When a call selects an
73
+ effort, a static `reasoning` option's `effort` must equal the value sent; a different value, or any
74
+ value when no native effort is sent, is rejected.
75
+
76
+ Native web search and web fetch are not available through this provider on either surface. Setting
77
+ `nativeWebTools.webSearch` or `nativeWebTools.webFetch` to `true` makes the constructor throw.
78
+
79
+ ## Options
80
+
81
+ `new OpenAIProvider(options: IOpenAIProviderOptions)`. One of `apiKey`, `client` or `executor` is
82
+ required; the constructor throws otherwise.
83
+
84
+ | Option | Type | Description |
85
+ | --------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
86
+ | `apiKey` | `string` | API key used to create the `openai` client. |
87
+ | `baseURL` | `string` | Endpoint base URL (default `https://api.openai.com/v1`). Also switches the default surface to Chat Completions. |
88
+ | `apiSurface` | `'responses' \| 'chat-completions'` | Forces the API surface instead of deriving it from `baseURL`. |
89
+ | `defaultModel` | `string` | Model used when a call does not name one. |
90
+ | `organization` | `string` | OpenAI organization ID. |
91
+ | `timeout` | `number` | Request timeout in milliseconds. |
92
+ | `strictTools` | `boolean` | Closes tool object schemas and requests OpenAI strict function calling (see above). |
93
+ | `responseFormat` | `'text' \| 'json_object' \| 'json_schema'` | Response format; `'json_schema'` uses `jsonSchema`. |
94
+ | `jsonSchema` | `IOpenAIJsonSchemaDefinition` | Schema for Structured Outputs when `responseFormat` is `'json_schema'`. |
95
+ | `reasoning` | `IOpenAIResponsesReasoningOptions` | Responses API reasoning controls (`effort`, `summary`). |
96
+ | `store` | `boolean` | Responses API only: whether OpenAI stores the response; when unset, OpenAI's default applies. |
97
+ | `includeEncryptedReasoning` | `boolean` | Responses API only: asks for encrypted reasoning items, so reasoning can continue without server-side state. |
98
+ | `nativeWebTools` | `IOpenAINativeWebToolsOptions` | Not supported: `true` for `webSearch` or `webFetch` throws (see above). |
99
+ | `includeStreamUsage` | `boolean` | Requests token usage on streaming Chat Completions turns (default `true`). |
100
+ | `client` | `OpenAI` | A pre-built `openai` client, used instead of `apiKey`. |
101
+ | `executor` | `IExecutor` | Delegates chat calls to an executor instead of calling the API directly. |
102
+ | `payloadLogger` | `IPayloadLogger` | Logs a summary of each Chat Completions request (model, message count, tools present, temperature, max tokens). |
103
+ | `logger` | `ILogger` | Logger for internal provider messages (silent by default). |
104
+
105
+ ## Errors
106
+
107
+ A failed API call throws a typed error from `@robota-sdk/agent-core`: `RateLimitError` (with
108
+ `retryAfter` from the `retry-after` header), `AuthenticationError`, `ModelNotAvailableError` or
109
+ `NetworkError` when the failure is one of those, otherwise a `ProviderError` that carries the HTTP
110
+ `status` and the error `type` the endpoint reported and keeps the SDK error as `originalError`. Both
111
+ API surfaces, streaming included, map failures the same way. An aborted call rethrows the abort
112
+ unchanged. See [Provider failures](../../content/guide/error-handling.md#provider-failures).
113
+
114
+ ## Exports
115
+
116
+ - `OpenAIProvider` and its option types (`IOpenAIProviderOptions`, `TOpenAIApiSurface`, and others).
117
+ - `createOpenAIProviderDefinition()`: the provider definition used by Robota's built-in provider
118
+ registry.
119
+ - `@robota-sdk/agent-provider-openai/loggers`: `FilePayloadLogger` (Node.js, writes log files with
120
+ owner-only permissions) and `ConsolePayloadLogger` (browser console).
121
+
122
+ ## Related packages
123
+
124
+ - [`@robota-sdk/agent-core`](../agent-core/README.md): the `Robota` agent and the provider contract.
125
+ - [`@robota-sdk/agent-provider-openai-compatible`](../agent-provider-openai-compatible/README.md):
126
+ DeepSeek, Qwen and Gemma providers, plus the shared OpenAI-compatible protocol code this package
127
+ uses.
128
+ - [`@robota-sdk/agent-provider-anthropic`](../agent-provider-anthropic/README.md) and
129
+ [`@robota-sdk/agent-provider-gemini`](../agent-provider-gemini/README.md): other chat providers.
130
+
131
+ See [docs/SPEC.md](docs/SPEC.md) for the package contract.
132
+
133
+ ## License
134
+
135
+ Robota is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a [commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
@@ -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){return(0,r.convertToOpenAICompatibleTools)(e)}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(void 0,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),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){return{promptTokens:e.input_tokens??0,completionTokens:e.output_tokens??0,totalTokens:e.total_tokens??0}}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("@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,4 +1,4 @@
1
- import { n as IPayloadLoggerOptions, t as IPayloadLogger } from "./payload-logger-BaW0K8yI.cjs";
1
+ import { n as IPayloadLoggerOptions, t as IPayloadLogger } from "./payload-logger-n89AQdUn.cjs";
2
2
  import { AbstractAIProvider, IChatOptions, IExecutor, ILogger, IProviderCapabilities, IProviderDefinition, IProviderModelEffortTable, IToolSchemaProjectionProfile, TProviderOptionValueBase, TTextDeltaCallback, TUniversalMessage } from "@robota-sdk/agent-core";
3
3
  import OpenAI from "openai";
4
4
  //#region src/openai/types.d.ts
@@ -70,7 +70,7 @@ interface IOpenAIProviderOptions {
70
70
  * @example
71
71
  * ```ts
72
72
  * // Vercel AI Gateway with a non-OpenAI model slug
73
- * createOpenAIProvider({
73
+ * new OpenAIProvider({
74
74
  * apiKey: process.env.AI_GATEWAY_API_KEY,
75
75
  * baseURL: 'https://ai-gateway.vercel.sh/v1',
76
76
  * defaultModel: 'anthropic/claude-sonnet-4-5',
@@ -125,6 +125,9 @@ interface IOpenAIProviderOptions {
125
125
  * schema marked optional becomes required and gains a `null` branch. The model must then supply
126
126
  * the key explicitly, with `null` standing for "not provided". A tool whose handler distinguishes
127
127
  * an absent key from a null value will see the difference.
128
+ *
129
+ * Both surfaces declare the functions strict (`strict: true` on each tool), so an OpenAI-compatible
130
+ * endpoint that rejects that field needs `strictTools` left off.
128
131
  */
129
132
  strictTools?: boolean;
130
133
  /**
@@ -140,7 +143,9 @@ interface IOpenAIProviderOptions {
140
143
  */
141
144
  client?: OpenAI;
142
145
  /**
143
- * Payload logger instance for debugging API requests/responses
146
+ * Payload logger that receives a summary of each Chat Completions request (model, message
147
+ * count, whether tools were sent, temperature, max tokens) for debugging — not prompt or
148
+ * response content. Not called on the Responses API surface.
144
149
  *
145
150
  * Use different implementations based on your environment:
146
151
  * - FilePayloadLogger: Node.js file-based logging
@@ -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;;;;GAId,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA;;;;;;;;;;;;;;EAeA;;;;;;;;EASA,iBAAiB;;;;EAKjB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BT,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BhB,WAAW;;;;;EAMX,SAAS;;;;;;;;;;;;cCrME,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;EAKC,eAAe;UAMhB;;;;;YAcW,qBAAqB;;;;;;;;UAahC;UAYA;EAiCC;EAIA,mBAAmB;EAwBnB;EAIM,WAAW;YAIP,iBAAiB,UAAU;;;;;;;;;;;;cC/UnC;;;;;;;;;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"}
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;;;;GAId,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA;;;;;;;;;;;;;;;;;EAkBA;;;;;;;;EASA,iBAAiB;;;;EAKjB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BT,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BhB,WAAW;;;;;EAMX,SAAS;;;;;;;;;;;;cC1ME,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;EAKC,eAAe;UAMhB;;;;;YAcW,qBAAqB;;;;;;;;UAahC;UAYA;EAiCC;EAIA,mBAAmB;EAwBnB;EAIM,WAAW;YAIP,iBAAiB,UAAU;;;;;;;;;;;;cC/UnC;;;;;;;;;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"}
@@ -1,4 +1,4 @@
1
- import { n as IPayloadLoggerOptions, t as IPayloadLogger } from "./payload-logger-BaW0K8yI.js";
1
+ import { n as IPayloadLoggerOptions, t as IPayloadLogger } from "./payload-logger-n89AQdUn.js";
2
2
  import { AbstractAIProvider, IChatOptions, IExecutor, ILogger, IProviderCapabilities, IProviderDefinition, IProviderModelEffortTable, IToolSchemaProjectionProfile, TProviderOptionValueBase, TTextDeltaCallback, TUniversalMessage } from "@robota-sdk/agent-core";
3
3
  import OpenAI from "openai";
4
4
  //#region src/openai/types.d.ts
@@ -70,7 +70,7 @@ interface IOpenAIProviderOptions {
70
70
  * @example
71
71
  * ```ts
72
72
  * // Vercel AI Gateway with a non-OpenAI model slug
73
- * createOpenAIProvider({
73
+ * new OpenAIProvider({
74
74
  * apiKey: process.env.AI_GATEWAY_API_KEY,
75
75
  * baseURL: 'https://ai-gateway.vercel.sh/v1',
76
76
  * defaultModel: 'anthropic/claude-sonnet-4-5',
@@ -125,6 +125,9 @@ interface IOpenAIProviderOptions {
125
125
  * schema marked optional becomes required and gains a `null` branch. The model must then supply
126
126
  * the key explicitly, with `null` standing for "not provided". A tool whose handler distinguishes
127
127
  * an absent key from a null value will see the difference.
128
+ *
129
+ * Both surfaces declare the functions strict (`strict: true` on each tool), so an OpenAI-compatible
130
+ * endpoint that rejects that field needs `strictTools` left off.
128
131
  */
129
132
  strictTools?: boolean;
130
133
  /**
@@ -140,7 +143,9 @@ interface IOpenAIProviderOptions {
140
143
  */
141
144
  client?: OpenAI;
142
145
  /**
143
- * Payload logger instance for debugging API requests/responses
146
+ * Payload logger that receives a summary of each Chat Completions request (model, message
147
+ * count, whether tools were sent, temperature, max tokens) for debugging — not prompt or
148
+ * response content. Not called on the Responses API surface.
144
149
  *
145
150
  * Use different implementations based on your environment:
146
151
  * - FilePayloadLogger: Node.js file-based logging
@@ -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;;;;GAId,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA;;;;;;;;;;;;;;EAeA;;;;;;;;EASA,iBAAiB;;;;EAKjB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BT,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BhB,WAAW;;;;;EAMX,SAAS;;;;;;;;;;;;cCrME,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;EAKC,eAAe;UAMhB;;;;;YAcW,qBAAqB;;;;;;;;UAahC;UAYA;EAiCC;EAIA,mBAAmB;EAwBnB;EAIM,WAAW;YAIP,iBAAiB,UAAU;;;;;;;;;;;;cC/UnC;;;;;;;;;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"}
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;;;;GAId,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA;;;;;;;;;;;;;;;;;EAkBA;;;;;;;;EASA,iBAAiB;;;;EAKjB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BT,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BhB,WAAW;;;;;EAMX,SAAS;;;;;;;;;;;;cC1ME,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;EAKC,eAAe;UAMhB;;;;;YAcW,qBAAqB;;;;;;;;UAahC;UAYA;EAiCC;EAIA,mBAAmB;EAwBnB;EAIM,WAAW;YAIP,iBAAiB,UAAU;;;;;;;;;;;;cC/UnC;;;;;;;;;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"}