@robota-sdk/agent-provider-openai 3.0.0-beta.82 → 3.0.0-beta.83
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 +207 -0
- package/README.md +110 -0
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +8 -3
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +8 -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/dist/node/loggers/index.d.cts +6 -6
- package/dist/node/loggers/index.d.cts.map +1 -1
- package/dist/node/loggers/index.d.ts +6 -6
- package/dist/node/loggers/index.d.ts.map +1 -1
- package/dist/node/loggers/index.js.map +1 -1
- package/dist/node/{payload-logger-BaW0K8yI.d.ts → payload-logger-n89AQdUn.d.cts} +6 -4
- package/dist/node/payload-logger-n89AQdUn.d.cts.map +1 -0
- package/dist/node/{payload-logger-BaW0K8yI.d.cts → payload-logger-n89AQdUn.d.ts} +6 -4
- package/dist/node/payload-logger-n89AQdUn.d.ts.map +1 -0
- package/package.json +10 -5
- package/src/openai/__tests__/abort-signal-wire.test.ts +210 -0
- package/src/openai/__tests__/strict-tools-closure.test.ts +49 -2
- package/src/openai/__tests__/tool-schema-projection.test.ts +16 -2
- package/src/openai/chat-completions-chat.ts +2 -2
- package/src/openai/interfaces/payload-logger.ts +5 -3
- package/src/openai/loggers/console-payload-logger.ts +2 -2
- package/src/openai/loggers/file-payload-logger.ts +6 -5
- package/src/openai/message-converter.ts +7 -3
- package/src/openai/responses-parser.test.ts +87 -0
- package/src/openai/responses-parser.ts +15 -9
- package/src/openai/responses-types.ts +2 -0
- package/src/openai/types.ts +7 -2
- package/dist/node/payload-logger-BaW0K8yI.d.cts.map +0 -1
- package/dist/node/payload-logger-BaW0K8yI.d.ts.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# @robota-sdk/agent-provider-openai
|
|
2
|
+
|
|
3
|
+
## 3.0.0-beta.83
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8bd5fac: Cached input tokens are no longer dropped (#3209 R3). The OpenAI and OpenAI-compatible adapters read
|
|
8
|
+
`prompt_tokens_details.cached_tokens` (Chat Completions, including the final streamed usage chunk) and
|
|
9
|
+
`input_tokens_details.cached_tokens` (Responses, OpenAI and Qwen) into `cacheReadTokens` on the message
|
|
10
|
+
usage: the part of the prompt served from the provider's prompt cache, present only when reported.
|
|
11
|
+
It reaches the committed assistant message, `readTokenUsageFromMessage()`, and the
|
|
12
|
+
`provider_call_completed` execution event, so a consumer can apply the cache discount.
|
|
13
|
+
|
|
14
|
+
New `sumMessagesUsage(messages)` sums the usage on assistant messages (with `cacheReadTokens` when any
|
|
15
|
+
reported it), so one run's usage is `sumMessagesUsage(agent.getHistory().slice(before))` without
|
|
16
|
+
converting through `messageToHistoryEntry` (#3209 S1). `sumHistoryUsage` returns the same triple as before.
|
|
17
|
+
|
|
18
|
+
A forced-summary reply now keeps the usage its provider reported the same way a tool round's reply
|
|
19
|
+
does: an endpoint that omits `total_tokens` no longer loses exactly the summary call's usage (#3209 N3). Counts
|
|
20
|
+
the adapter could not attest as a consistent total are recorded with `usageProvenance: 'partial'`.
|
|
21
|
+
|
|
22
|
+
- 274328f: `OpenAIProvider({ strictTools: true })` now requests strict function calling on the Chat Completions
|
|
23
|
+
surface too (each tool is sent with `function.strict: true`), not only on the Responses surface. This
|
|
24
|
+
matters for every provider created with a `baseURL`, which defaults to Chat Completions. With
|
|
25
|
+
`strictTools` off the request is unchanged. `convertToOpenAICompatibleTools` accepts an optional
|
|
26
|
+
`{ strict }` argument.
|
|
27
|
+
- 57280bf: Every published package now declares `"engines": { "node": ">=22.12.0" }`. Before, 27 of the 38
|
|
28
|
+
packages declared no floor (`agent-core`, `agent-tools` and every provider among them),
|
|
29
|
+
`agent-session` and `agent-file-authority` declared `>=20.19.0`, and the other nine declared
|
|
30
|
+
`>=22.0.0`, so a consumer on Node 20 saw at most a warning from a transitive dependency.
|
|
31
|
+
|
|
32
|
+
Why 22.12: `agent-cli` and `agent-ui-terminal` need Node 22 through `ink` 7, and the CommonJS entries
|
|
33
|
+
of `agent-tools` and its dependents, `agent-transport`/`node` and its dependents, and
|
|
34
|
+
`agent-ui-terminal` `require()` ESM-only dependencies (`p-limit`, `jose`, `chalk`), which Node 22
|
|
35
|
+
supports unflagged only from 22.12. `engines` is advisory unless the consumer enables `engine-strict`.
|
|
36
|
+
|
|
37
|
+
No code changes: `tsdown` now reads `node22.12.0` as its build target from the field.
|
|
38
|
+
|
|
39
|
+
- 643effb: Aborting a run now cancels the provider's HTTP request on every call path. The non-streaming
|
|
40
|
+
`chat()` request — the one a forced end-of-round summary makes — sent no `AbortSignal` on OpenAI
|
|
41
|
+
Chat Completions, DeepSeek, Qwen (Chat Completions) and Gemma, so an aborted run left that request
|
|
42
|
+
running to completion; the same held for `chatStream()` on DeepSeek, Qwen (Chat Completions), Gemma
|
|
43
|
+
and Anthropic. Each now hands the call's `signal` to the SDK request.
|
|
44
|
+
- 18c0d5c: Every published package now exports `./package.json`, so `require('<package>/package.json')` and
|
|
45
|
+
`import('<package>/package.json', { with: { type: 'json' } })` work instead of failing with
|
|
46
|
+
`ERR_PACKAGE_PATH_NOT_EXPORTED`, and each tarball now ships the package's `CHANGELOG.md`.
|
|
47
|
+
- Updated dependencies [e689c8e]
|
|
48
|
+
- Updated dependencies [be0e53c]
|
|
49
|
+
- Updated dependencies [8bd5fac]
|
|
50
|
+
- Updated dependencies [274328f]
|
|
51
|
+
- Updated dependencies [57280bf]
|
|
52
|
+
- Updated dependencies [5033dd9]
|
|
53
|
+
- Updated dependencies [643effb]
|
|
54
|
+
- Updated dependencies [18c0d5c]
|
|
55
|
+
- Updated dependencies [dbd888d]
|
|
56
|
+
- Updated dependencies [1887e54]
|
|
57
|
+
- @robota-sdk/agent-core@3.0.0-beta.83
|
|
58
|
+
- @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.83
|
|
59
|
+
|
|
60
|
+
## 3.0.0-beta.82
|
|
61
|
+
|
|
62
|
+
### Patch Changes
|
|
63
|
+
|
|
64
|
+
- Updated dependencies [c7f9203]
|
|
65
|
+
- @robota-sdk/agent-core@3.0.0-beta.82
|
|
66
|
+
- @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.82
|
|
67
|
+
|
|
68
|
+
## 3.0.0-beta.81
|
|
69
|
+
|
|
70
|
+
### Patch Changes
|
|
71
|
+
|
|
72
|
+
- Updated dependencies [3038eb7]
|
|
73
|
+
- Updated dependencies [02b7452]
|
|
74
|
+
- Updated dependencies [ec5e477]
|
|
75
|
+
- @robota-sdk/agent-core@3.0.0-beta.81
|
|
76
|
+
- @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.81
|
|
77
|
+
|
|
78
|
+
## 3.0.0-beta.80
|
|
79
|
+
|
|
80
|
+
### Minor Changes
|
|
81
|
+
|
|
82
|
+
- 1698be4: A child-process subagent can no longer send the parent's provider credential to a different
|
|
83
|
+
endpoint.
|
|
84
|
+
|
|
85
|
+
- **Before spawning a child**, the parent compares every environment variable that decides where
|
|
86
|
+
the provider connects or which credential it sends. If the child's environment differs, the job
|
|
87
|
+
is refused before the credential leaves the parent. The error names the variable, never its
|
|
88
|
+
value. The variables compared are:
|
|
89
|
+
- the proxy and TLS variables;
|
|
90
|
+
- the variables the provider's SDK reads, such as `OPENAI_BASE_URL`, `ANTHROPIC_AUTH_TOKEN` and
|
|
91
|
+
the Vertex settings;
|
|
92
|
+
- the credential's own variable.
|
|
93
|
+
- **The child** repeats the check before it builds its provider. It builds that provider from the
|
|
94
|
+
parent's effective connection exactly: it no longer fills in a base URL, options or a default
|
|
95
|
+
credential from its own registry, and a credential reference that resolves to nothing is refused.
|
|
96
|
+
- **Where the effective connection comes from:** the parent applies its own definition defaults
|
|
97
|
+
(base URL, options). `profileName` is sent only when it names the connection actually sent.
|
|
98
|
+
- **New contracts:**
|
|
99
|
+
- `IProviderDefinition.destinationEnvironment`, declared by every built-in provider.
|
|
100
|
+
- `createProviderFromExactProfile`, `connectionEnvironmentNames`,
|
|
101
|
+
`findConnectionEnvironmentDivergence`, `sealConnectionEnvironment`,
|
|
102
|
+
`verifyConnectionEnvironment` and `TRANSPORT_ENVIRONMENT`.
|
|
103
|
+
- The start payload's `connectionCheck`.
|
|
104
|
+
- The child-process runner's `providerDefinitions` option, now required: a provider with no
|
|
105
|
+
definition there is refused, because its connection cannot be checked.
|
|
106
|
+
|
|
107
|
+
- 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.
|
|
108
|
+
- 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.
|
|
109
|
+
|
|
110
|
+
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.
|
|
111
|
+
|
|
112
|
+
### Patch Changes
|
|
113
|
+
|
|
114
|
+
- 9fbab1b: Provider DIP Stage B (ARCH-PROVIDER-003), part 1: collapse infrastructure. Adds the
|
|
115
|
+
provider-registry-driven `@robota-sdk/dag-node-llm-text` node that supersedes the
|
|
116
|
+
per-vendor LLM nodes + router, relocates the provider config resolver into
|
|
117
|
+
`agent-core`, adds SSOT cost/allowedModels fields, inverts the `llm-text` validator
|
|
118
|
+
tombstone, and wires `createDagFramework({ providers })`. Additive — the per-vendor
|
|
119
|
+
nodes still exist; consumer migration + their removal follow in part 2.
|
|
120
|
+
- 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).
|
|
121
|
+
- b6d14ce: Make the universal JSON-schema subset able to express an object, so a nested `z.object()` keeps its
|
|
122
|
+
properties and required fields instead of reaching the model as `{ "type": "object" }`. Tools and
|
|
123
|
+
structured-output schemas with one level of nesting are now advertised in full and enforced on the
|
|
124
|
+
tool-input path; `z.union` / `z.discriminatedUnion` / `z.literal` are supported and map to `anyOf`
|
|
125
|
+
and single-value enums; `.nullable()` keeps its null branch; and Zod's `strip`, `strict` and
|
|
126
|
+
`passthrough` modes stop collapsing into two `additionalProperties` emissions. Fixes the shipped
|
|
127
|
+
`Computer` and `AskUserQuestion` built-ins, whose action and question fields were being dropped
|
|
128
|
+
entirely.
|
|
129
|
+
|
|
130
|
+
`agent-core` is **minor**, not patch: `IObjectParameterSchema` is a new export, and
|
|
131
|
+
`IParameterSchema.type` became optional (a union node carries `anyOf` instead of a type), which is a
|
|
132
|
+
consumer-visible type change — two call sites in this repo needed editing to keep compiling.
|
|
133
|
+
`additionalProperties` also widened to `boolean | IParameterSchema`, and `required` and `anyOf` are
|
|
134
|
+
new members. The provider packages are **patch**: each adapts to the widened subset without changing
|
|
135
|
+
its own public surface.
|
|
136
|
+
|
|
137
|
+
- 93d061d: CORE-043: structured output now knows which transport can carry the schema before the first call
|
|
138
|
+
|
|
139
|
+
`run(input, { output })` asked every provider for `responseFormat: { type: 'json_schema' }`. A
|
|
140
|
+
provider whose surface cannot express that accepted the option and dropped it — and the schema was
|
|
141
|
+
stated in words only by the RETRY feedback turn, which runs on attempt two. So against such a
|
|
142
|
+
provider, attempt one carried nothing describing the required shape and could only succeed by luck:
|
|
143
|
+
the advertised three attempts were really two, and the first was spent discovering something the
|
|
144
|
+
capability table already knew.
|
|
145
|
+
|
|
146
|
+
A `(provider, model)` pair now resolves to a mechanism (`response_schema` / `json_object` / `none`)
|
|
147
|
+
and a provenance (`catalog` / `vendor-default` / `undeclared` / `unverified-endpoint`), and the
|
|
148
|
+
request is shaped to match at the one seam that holds both the resolved provider and the outgoing
|
|
149
|
+
messages. When the wire cannot carry the shape, the schema is stated in the prompt on the FIRST
|
|
150
|
+
attempt. Each structured request emits a `structured_output_transport` event reporting what the
|
|
151
|
+
request actually did.
|
|
152
|
+
|
|
153
|
+
- `IAIProvider.endpointIsVendorDefault?()` — a provider configured with a custom `baseURL` reports
|
|
154
|
+
it, so the runtime stops claiming enforcement a gateway may not provide. Separate from
|
|
155
|
+
`capabilityTable?()` on purpose: `@robota-sdk/agent-provider-openai` declares no table (nobody has
|
|
156
|
+
verified one) and must still be able to answer.
|
|
157
|
+
- DeepSeek's capability table declared `json_schema`; DeepSeek guarantees the response PARSES but
|
|
158
|
+
takes no schema parameter. Corrected to `json_object`.
|
|
159
|
+
- A provider that declares nothing is still sent the request unchanged — silence is not a denial.
|
|
160
|
+
|
|
161
|
+
- ebd40a0: Harden on-disk log permissions against CWE-377 (SEC-003, CodeQL `js/insecure-temporary-file`).
|
|
162
|
+
|
|
163
|
+
Session logs, externalized session payloads, and OpenAI request/response payload logs all carry
|
|
164
|
+
conversation and prompt content, but were created with the process umask (typically `0644`) inside a
|
|
165
|
+
caller-supplied directory that may be shared or world-writable. They are now created owner-only
|
|
166
|
+
(`0600`), and the directories that hold them are created `0700`.
|
|
167
|
+
|
|
168
|
+
This is a permissions change only — file locations, names, formats, and APIs are unchanged. Anything
|
|
169
|
+
that read these logs as a _different_ OS user will no longer be able to; the owning user is
|
|
170
|
+
unaffected.
|
|
171
|
+
|
|
172
|
+
- Updated dependencies [7b6234c]
|
|
173
|
+
- Updated dependencies [4eea54b]
|
|
174
|
+
- Updated dependencies [1698be4]
|
|
175
|
+
- Updated dependencies [d4189b9]
|
|
176
|
+
- Updated dependencies [9edae52]
|
|
177
|
+
- Updated dependencies [4078a72]
|
|
178
|
+
- Updated dependencies [4c73a0b]
|
|
179
|
+
- Updated dependencies [196a900]
|
|
180
|
+
- Updated dependencies [f336838]
|
|
181
|
+
- Updated dependencies [34e50f0]
|
|
182
|
+
- Updated dependencies [722e88a]
|
|
183
|
+
- Updated dependencies [d23c848]
|
|
184
|
+
- Updated dependencies [fec722f]
|
|
185
|
+
- Updated dependencies [2d3b2c0]
|
|
186
|
+
- Updated dependencies [4772067]
|
|
187
|
+
- Updated dependencies [7937c19]
|
|
188
|
+
- Updated dependencies [9fbab1b]
|
|
189
|
+
- Updated dependencies [a009f5b]
|
|
190
|
+
- Updated dependencies [4f3c075]
|
|
191
|
+
- Updated dependencies [475e085]
|
|
192
|
+
- Updated dependencies [e477440]
|
|
193
|
+
- Updated dependencies [9dcb5da]
|
|
194
|
+
- Updated dependencies [a95ca85]
|
|
195
|
+
- Updated dependencies [b6d14ce]
|
|
196
|
+
- Updated dependencies [0382a51]
|
|
197
|
+
- Updated dependencies [93d061d]
|
|
198
|
+
- Updated dependencies [39554a1]
|
|
199
|
+
- Updated dependencies [d28430a]
|
|
200
|
+
- Updated dependencies [07b627f]
|
|
201
|
+
- Updated dependencies [d0de5b2]
|
|
202
|
+
- Updated dependencies [2916d00]
|
|
203
|
+
- Updated dependencies [7669851]
|
|
204
|
+
- Updated dependencies [d6b9404]
|
|
205
|
+
- Updated dependencies [9814afc]
|
|
206
|
+
- @robota-sdk/agent-core@3.0.0-beta.80
|
|
207
|
+
- @robota-sdk/agent-provider-openai-compatible@3.0.0-beta.80
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
```
|
|
48
|
+
|
|
49
|
+
The API surface follows `baseURL` unless `apiSurface` is set:
|
|
50
|
+
|
|
51
|
+
| Configuration | API surface |
|
|
52
|
+
| --------------------- | --------------------------------------- |
|
|
53
|
+
| No `baseURL` | Responses API (`'responses'`) |
|
|
54
|
+
| `baseURL` set | Chat Completions (`'chat-completions'`) |
|
|
55
|
+
| `apiSurface` provided | The surface you set, either way |
|
|
56
|
+
|
|
57
|
+
### Strict tools
|
|
58
|
+
|
|
59
|
+
`strictTools: true` closes tool object schemas and requests OpenAI strict function calling. Every
|
|
60
|
+
object node of a tool's parameter schema, nested ones included, gets `additionalProperties: false`
|
|
61
|
+
and a complete `required` list, with optional properties turned into nullable ones, and each function
|
|
62
|
+
tool is sent with `strict: true` on both the Responses and Chat Completions surfaces. An
|
|
63
|
+
OpenAI-compatible endpoint that rejects the `strict` field needs `strictTools` left off. With
|
|
64
|
+
`strictTools` off (the default) tool schemas are forwarded as authored and no `strict` field is sent.
|
|
65
|
+
|
|
66
|
+
## Options
|
|
67
|
+
|
|
68
|
+
`new OpenAIProvider(options: IOpenAIProviderOptions)`. One of `apiKey`, `client` or `executor` is
|
|
69
|
+
required; the constructor throws otherwise.
|
|
70
|
+
|
|
71
|
+
| Option | Type | Description |
|
|
72
|
+
| -------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `apiKey` | `string` | API key used to create the `openai` client. |
|
|
74
|
+
| `baseURL` | `string` | Endpoint base URL (default `https://api.openai.com/v1`). Also switches the default surface to Chat Completions. |
|
|
75
|
+
| `apiSurface` | `'responses' \| 'chat-completions'` | Forces the API surface instead of deriving it from `baseURL`. |
|
|
76
|
+
| `defaultModel` | `string` | Model used when a call does not name one. |
|
|
77
|
+
| `organization` | `string` | OpenAI organization ID. |
|
|
78
|
+
| `timeout` | `number` | Request timeout in milliseconds. |
|
|
79
|
+
| `strictTools` | `boolean` | Closes tool object schemas and requests OpenAI strict function calling (see above). |
|
|
80
|
+
| `responseFormat` | `'text' \| 'json_object' \| 'json_schema'` | Response format; `'json_schema'` uses `jsonSchema`. |
|
|
81
|
+
| `jsonSchema` | `IOpenAIJsonSchemaDefinition` | Schema for Structured Outputs when `responseFormat` is `'json_schema'`. |
|
|
82
|
+
| `reasoning` | `IOpenAIResponsesReasoningOptions` | Responses API reasoning controls (`effort`, `summary`). |
|
|
83
|
+
| `includeStreamUsage` | `boolean` | Requests token usage on streaming Chat Completions turns (default `true`). |
|
|
84
|
+
| `client` | `OpenAI` | A pre-built `openai` client, used instead of `apiKey`. |
|
|
85
|
+
| `executor` | `IExecutor` | Delegates chat calls to an executor instead of calling the API directly. |
|
|
86
|
+
| `payloadLogger` | `IPayloadLogger` | Logs a summary of each Chat Completions request (model, message count, tools present, temperature, max tokens). |
|
|
87
|
+
| `logger` | `ILogger` | Logger for internal provider messages (silent by default). |
|
|
88
|
+
|
|
89
|
+
## Exports
|
|
90
|
+
|
|
91
|
+
- `OpenAIProvider` and its option types (`IOpenAIProviderOptions`, `TOpenAIApiSurface`, and others).
|
|
92
|
+
- `createOpenAIProviderDefinition()`: the provider definition used by Robota's built-in provider
|
|
93
|
+
registry.
|
|
94
|
+
- `@robota-sdk/agent-provider-openai/loggers`: `FilePayloadLogger` (Node.js, writes log files with
|
|
95
|
+
owner-only permissions) and `ConsolePayloadLogger` (browser console).
|
|
96
|
+
|
|
97
|
+
## Related packages
|
|
98
|
+
|
|
99
|
+
- [`@robota-sdk/agent-core`](../agent-core/README.md): the `Robota` agent and the provider contract.
|
|
100
|
+
- [`@robota-sdk/agent-provider-openai-compatible`](../agent-provider-openai-compatible/README.md):
|
|
101
|
+
DeepSeek, Qwen and Gemma providers, plus the shared OpenAI-compatible protocol code this package
|
|
102
|
+
uses.
|
|
103
|
+
- [`@robota-sdk/agent-provider-anthropic`](../agent-provider-anthropic/README.md) and
|
|
104
|
+
[`@robota-sdk/agent-provider-gemini`](../agent-provider-gemini/README.md): other chat providers.
|
|
105
|
+
|
|
106
|
+
See [docs/SPEC.md](docs/SPEC.md) for the package contract.
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
Robota 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){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;
|
package/dist/node/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as IPayloadLoggerOptions, t as IPayloadLogger } from "./payload-logger-
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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"}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as IPayloadLoggerOptions, t as IPayloadLogger } from "./payload-logger-
|
|
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
|
-
*
|
|
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
|
|
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
|
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;;;;GAId,cAAc;;;;EAKf;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA;;;;EAKA;;;;;;;EAQA,aAAa;;;;;;;EAQb;;;;EAKA,aAAa;;;;;EAMb,YAAY;;;;EAKZ;;;;EAKA
|
|
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"}
|