@robota-sdk/agent-provider-openai 3.0.0-beta.63 → 3.0.0-beta.82
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/LICENSE +661 -21
- package/dist/node/index.cjs +1 -2
- package/dist/node/index.d.cts +271 -267
- package/dist/node/index.d.cts.map +1 -0
- package/dist/node/index.d.ts +271 -267
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +2 -2
- package/dist/node/index.js.map +1 -0
- package/dist/node/loggers/index.cjs +1 -0
- package/dist/node/loggers/index.d.cts +94 -0
- package/dist/node/loggers/index.d.cts.map +1 -0
- package/dist/node/loggers/index.d.ts +94 -0
- package/dist/node/loggers/index.d.ts.map +1 -0
- package/dist/node/loggers/index.js +2 -0
- package/dist/node/loggers/index.js.map +1 -0
- package/dist/node/payload-logger-BaW0K8yI.d.cts +61 -0
- package/dist/node/payload-logger-BaW0K8yI.d.cts.map +1 -0
- package/dist/node/payload-logger-BaW0K8yI.d.ts +61 -0
- package/dist/node/payload-logger-BaW0K8yI.d.ts.map +1 -0
- package/dist/node/rolldown-runtime-CMqjfN_6.cjs +1 -0
- package/package.json +69 -86
- package/src/index.ts +1 -0
- package/src/openai/__tests__/endpoint-provenance.test.ts +44 -0
- package/src/openai/__tests__/provider-errors.test.ts +114 -0
- package/src/openai/__tests__/request-format.test.ts +59 -0
- package/src/openai/__tests__/strict-tools-closure.test.ts +136 -0
- package/src/openai/__tests__/tool-schema-projection.test.ts +302 -0
- package/src/openai/__tests__/trace-context-wire.test.ts +114 -0
- package/src/openai/adapter.test.ts +494 -0
- package/src/openai/adapter.ts +145 -0
- package/src/openai/chat-completions-chat.ts +225 -0
- package/src/openai/executor-integration.test.ts +213 -0
- package/src/openai/index.ts +19 -0
- package/src/openai/interfaces/payload-logger.ts +48 -0
- package/src/openai/loggers/console-payload-logger.test.ts +173 -0
- package/src/openai/loggers/console-payload-logger.ts +96 -0
- package/src/openai/loggers/console.ts +9 -0
- package/src/openai/loggers/file-payload-logger.test.ts +243 -0
- package/src/openai/loggers/file-payload-logger.ts +124 -0
- package/src/openai/loggers/file.ts +9 -0
- package/src/openai/loggers/index.ts +12 -0
- package/src/openai/loggers/sanitize-openai-log-data.test.ts +89 -0
- package/src/openai/loggers/sanitize-openai-log-data.ts +14 -0
- package/src/openai/message-converter.ts +23 -0
- package/src/openai/model-effort-table.ts +19 -0
- package/src/openai/model-effort-verification-config.test.ts +45 -0
- package/src/openai/model-effort-verification-config.ts +35 -0
- package/src/openai/openai-request-format.ts +116 -0
- package/src/openai/parsers/response-parser.test.ts +407 -0
- package/src/openai/parsers/response-parser.ts +48 -0
- package/src/openai/provider-definition.test.ts +74 -0
- package/src/openai/provider-definition.ts +139 -0
- package/src/openai/provider.test.ts +1686 -0
- package/src/openai/provider.ts +392 -0
- package/src/openai/reasoning-effort.test.ts +272 -0
- package/src/openai/reasoning-effort.ts +49 -0
- package/src/openai/request-id.ts +39 -0
- package/src/openai/request-options.ts +14 -0
- package/src/openai/responses-chat.ts +285 -0
- package/src/openai/responses-converter.ts +122 -0
- package/src/openai/responses-parser.ts +297 -0
- package/src/openai/responses-stream-utils.ts +45 -0
- package/src/openai/responses-types.ts +193 -0
- package/src/openai/streaming/stream-assembler.ts +3 -0
- package/src/openai/types/api-types.ts +113 -0
- package/src/openai/types.ts +235 -0
- package/CHANGELOG.md +0 -614
- package/README.md +0 -467
- package/dist/browser/index.d.ts +0 -307
- package/dist/browser/index.js +0 -2
package/dist/browser/index.d.ts
DELETED
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import OpenAI from 'openai';
|
|
2
|
-
import { ILogger, IExecutor, TProviderOptionValueBase, AbstractAIProvider, TTextDeltaCallback, TUniversalMessage, IChatOptions, IProviderCapabilities, IProviderProfileConfig, IProviderModelCatalog, IProviderDefinition } from '@robota-sdk/agent-core';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Payload logging data structure
|
|
6
|
-
*/
|
|
7
|
-
interface IOpenAILogData {
|
|
8
|
-
model: string;
|
|
9
|
-
messagesCount: number;
|
|
10
|
-
hasTools: boolean;
|
|
11
|
-
temperature?: number | undefined;
|
|
12
|
-
maxTokens?: number | undefined;
|
|
13
|
-
timestamp: string;
|
|
14
|
-
requestId?: string | undefined;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* IPayloadLogger interface for logging OpenAI API payloads
|
|
19
|
-
*
|
|
20
|
-
* This interface provides a contract for different logging implementations:
|
|
21
|
-
* - FilePayloadLogger: Node.js file-based logging
|
|
22
|
-
* - ConsolePayloadLogger: Browser console-based logging
|
|
23
|
-
* - Custom implementations: User-defined loggers
|
|
24
|
-
*/
|
|
25
|
-
interface IPayloadLogger {
|
|
26
|
-
/**
|
|
27
|
-
* Check if logging is enabled
|
|
28
|
-
* @returns true if logging is active, false otherwise
|
|
29
|
-
*/
|
|
30
|
-
isEnabled(): boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Log API payload data
|
|
33
|
-
* @param payload - The API request/response payload data
|
|
34
|
-
* @param type - Type of operation ('chat' or 'stream')
|
|
35
|
-
*/
|
|
36
|
-
logPayload(payload: IOpenAILogData, type: 'chat' | 'stream'): Promise<void>;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Configuration options for payload loggers
|
|
40
|
-
*/
|
|
41
|
-
interface IPayloadLoggerOptions {
|
|
42
|
-
/**
|
|
43
|
-
* Whether logging is enabled
|
|
44
|
-
* @defaultValue true
|
|
45
|
-
*/
|
|
46
|
-
enabled?: boolean;
|
|
47
|
-
/**
|
|
48
|
-
* Include timestamp in log entries
|
|
49
|
-
* @defaultValue true
|
|
50
|
-
*/
|
|
51
|
-
includeTimestamp?: boolean;
|
|
52
|
-
/**
|
|
53
|
-
* Logger instance for console output
|
|
54
|
-
* @defaultValue SilentLogger
|
|
55
|
-
*/
|
|
56
|
-
logger?: ILogger;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
type TOpenAIApiSurface = 'responses' | 'chat-completions';
|
|
60
|
-
interface IOpenAIJsonSchemaDefinition {
|
|
61
|
-
name: string;
|
|
62
|
-
description?: string;
|
|
63
|
-
schema?: Record<string, TOpenAIProviderOptionValue>;
|
|
64
|
-
strict?: boolean;
|
|
65
|
-
}
|
|
66
|
-
interface IOpenAIResponsesReasoningOptions {
|
|
67
|
-
effort?: 'low' | 'medium' | 'high';
|
|
68
|
-
summary?: 'auto' | 'concise' | 'detailed';
|
|
69
|
-
}
|
|
70
|
-
interface IOpenAINativeWebToolsOptions {
|
|
71
|
-
webSearch?: boolean;
|
|
72
|
-
webFetch?: boolean;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Valid provider option value types
|
|
76
|
-
*/
|
|
77
|
-
type TOpenAIProviderOptionValue = string | number | boolean | undefined | null | IOpenAIJsonSchemaDefinition | IOpenAINativeWebToolsOptions | IOpenAIResponsesReasoningOptions | OpenAI | IPayloadLogger | ILogger | IExecutor | TProviderOptionValueBase | TOpenAIProviderOptionValue[] | {
|
|
78
|
-
[key: string]: TOpenAIProviderOptionValue;
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* OpenAI provider options
|
|
82
|
-
*/
|
|
83
|
-
interface IOpenAIProviderOptions {
|
|
84
|
-
/**
|
|
85
|
-
* Additional provider-specific options
|
|
86
|
-
*/
|
|
87
|
-
[key: string]: TOpenAIProviderOptionValue;
|
|
88
|
-
/**
|
|
89
|
-
* OpenAI API key (required when client is not provided)
|
|
90
|
-
*/
|
|
91
|
-
apiKey?: string;
|
|
92
|
-
/**
|
|
93
|
-
* OpenAI organization ID (optional)
|
|
94
|
-
*/
|
|
95
|
-
organization?: string;
|
|
96
|
-
/**
|
|
97
|
-
* API request timeout (milliseconds)
|
|
98
|
-
*/
|
|
99
|
-
timeout?: number;
|
|
100
|
-
/**
|
|
101
|
-
* API base URL (default: 'https://api.openai.com/v1')
|
|
102
|
-
*/
|
|
103
|
-
baseURL?: string;
|
|
104
|
-
/**
|
|
105
|
-
* Default model used when chat options do not provide a model.
|
|
106
|
-
*/
|
|
107
|
-
defaultModel?: string;
|
|
108
|
-
/**
|
|
109
|
-
* API surface to use for direct OpenAI calls.
|
|
110
|
-
*
|
|
111
|
-
* Defaults to Responses for official OpenAI calls. Profiles with baseURL use
|
|
112
|
-
* Chat Completions by default for OpenAI-compatible endpoint compatibility.
|
|
113
|
-
*/
|
|
114
|
-
apiSurface?: TOpenAIApiSurface;
|
|
115
|
-
/**
|
|
116
|
-
* Response format (default: 'text')
|
|
117
|
-
* - 'text': Plain text response
|
|
118
|
-
* - 'json_object': JSON object mode (requires system message)
|
|
119
|
-
* - 'json_schema': Structured Outputs with schema validation
|
|
120
|
-
*/
|
|
121
|
-
responseFormat?: 'text' | 'json_object' | 'json_schema';
|
|
122
|
-
/**
|
|
123
|
-
* JSON schema for structured outputs (required when responseFormat is 'json_schema')
|
|
124
|
-
*/
|
|
125
|
-
jsonSchema?: IOpenAIJsonSchemaDefinition;
|
|
126
|
-
/**
|
|
127
|
-
* Responses API reasoning controls. Hidden reasoning is never exposed in message
|
|
128
|
-
* content; only explicit summaries/encrypted items requested here are represented.
|
|
129
|
-
*/
|
|
130
|
-
reasoning?: IOpenAIResponsesReasoningOptions;
|
|
131
|
-
/**
|
|
132
|
-
* Whether OpenAI should store Responses API results. Defaults to OpenAI API behavior.
|
|
133
|
-
*/
|
|
134
|
-
store?: boolean;
|
|
135
|
-
/**
|
|
136
|
-
* Include encrypted reasoning items for stateless reasoning continuation.
|
|
137
|
-
*/
|
|
138
|
-
includeEncryptedReasoning?: boolean;
|
|
139
|
-
/**
|
|
140
|
-
* Opt into strict custom function parameter validation where supported.
|
|
141
|
-
*/
|
|
142
|
-
strictTools?: boolean;
|
|
143
|
-
/**
|
|
144
|
-
* Provider-native hosted web tool request from provider profile options.
|
|
145
|
-
*
|
|
146
|
-
* OpenAI-compatible Chat Completions endpoints do not support this Robota
|
|
147
|
-
* native web contract. The provider rejects unsupported configurations before
|
|
148
|
-
* any model request is sent.
|
|
149
|
-
*/
|
|
150
|
-
nativeWebTools?: IOpenAINativeWebToolsOptions;
|
|
151
|
-
/**
|
|
152
|
-
* OpenAI client instance (optional: will be created from apiKey if not provided)
|
|
153
|
-
*/
|
|
154
|
-
client?: OpenAI;
|
|
155
|
-
/**
|
|
156
|
-
* Payload logger instance for debugging API requests/responses
|
|
157
|
-
*
|
|
158
|
-
* Use different implementations based on your environment:
|
|
159
|
-
* - FilePayloadLogger: Node.js file-based logging
|
|
160
|
-
* - ConsolePayloadLogger: Browser console-based logging
|
|
161
|
-
* - Custom: Implement IPayloadLogger interface
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* ```typescript
|
|
165
|
-
* // Node.js
|
|
166
|
-
* import { FilePayloadLogger } from '@robota-sdk/agent-provider-openai/loggers/file';
|
|
167
|
-
* const provider = new OpenAIProvider({
|
|
168
|
-
* client: openaiClient,
|
|
169
|
-
* payloadLogger: new FilePayloadLogger({ logDir: './logs/openai' })
|
|
170
|
-
* });
|
|
171
|
-
*
|
|
172
|
-
* // Browser
|
|
173
|
-
* import { ConsolePayloadLogger } from '@robota-sdk/agent-provider-openai/loggers/console';
|
|
174
|
-
* const provider = new OpenAIProvider({
|
|
175
|
-
* client: openaiClient,
|
|
176
|
-
* payloadLogger: new ConsolePayloadLogger()
|
|
177
|
-
* });
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
|
-
payloadLogger?: IPayloadLogger;
|
|
181
|
-
/**
|
|
182
|
-
* Optional executor for handling AI requests
|
|
183
|
-
*
|
|
184
|
-
* When provided, the provider will delegate all chat operations to this executor
|
|
185
|
-
* instead of making direct API calls. This enables remote execution capabilities.
|
|
186
|
-
*
|
|
187
|
-
* @example
|
|
188
|
-
* ```typescript
|
|
189
|
-
* import { LocalExecutor, RemoteExecutor } from '@robota-sdk/agent-core';
|
|
190
|
-
*
|
|
191
|
-
* // Local execution (registers this provider)
|
|
192
|
-
* const localExecutor = new LocalExecutor();
|
|
193
|
-
* localExecutor.registerProvider('openai', new OpenAIProvider({ apiKey: 'sk-...' }));
|
|
194
|
-
*
|
|
195
|
-
* // Remote execution
|
|
196
|
-
* const remoteExecutor = new RemoteExecutor({
|
|
197
|
-
* serverUrl: 'https://api.robota.io',
|
|
198
|
-
* userApiKey: 'user-token-123'
|
|
199
|
-
* });
|
|
200
|
-
*
|
|
201
|
-
* const provider = new OpenAIProvider({
|
|
202
|
-
* executor: remoteExecutor // No direct API key needed
|
|
203
|
-
* });
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
executor?: IExecutor;
|
|
207
|
-
/**
|
|
208
|
-
* Logger instance for internal OpenAI provider logging
|
|
209
|
-
* @defaultValue SilentLogger
|
|
210
|
-
*/
|
|
211
|
-
logger?: ILogger;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* OpenAI provider implementation for Robota
|
|
216
|
-
*
|
|
217
|
-
* Provides integration with OpenAI models through the Robota provider contract.
|
|
218
|
-
* Uses OpenAI SDK native types internally for optimal performance and feature support.
|
|
219
|
-
*
|
|
220
|
-
* @public
|
|
221
|
-
*/
|
|
222
|
-
declare class OpenAIProvider extends AbstractAIProvider {
|
|
223
|
-
readonly name = "openai";
|
|
224
|
-
readonly version = "1.0.0";
|
|
225
|
-
private readonly client?;
|
|
226
|
-
private readonly options;
|
|
227
|
-
private readonly apiSurface;
|
|
228
|
-
private readonly payloadLogger;
|
|
229
|
-
private readonly responseParser;
|
|
230
|
-
/**
|
|
231
|
-
* Optional callback for text deltas during streaming.
|
|
232
|
-
* Set by the consumer (e.g., Session) to receive real-time text chunks.
|
|
233
|
-
* When set, chat() uses streaming internally while still returning
|
|
234
|
-
* the complete assembled message.
|
|
235
|
-
*/
|
|
236
|
-
onTextDelta?: TTextDeltaCallback;
|
|
237
|
-
constructor(options: IOpenAIProviderOptions);
|
|
238
|
-
chat(messages: TUniversalMessage[], options?: IChatOptions): Promise<TUniversalMessage>;
|
|
239
|
-
chatStream(messages: TUniversalMessage[], options?: IChatOptions): AsyncIterable<TUniversalMessage>;
|
|
240
|
-
supportsTools(): boolean;
|
|
241
|
-
getCapabilities(): IProviderCapabilities;
|
|
242
|
-
validateConfig(): boolean;
|
|
243
|
-
dispose(): Promise<void>;
|
|
244
|
-
protected validateMessages(messages: TUniversalMessage[]): void;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* OpenAI Conversation Adapter
|
|
249
|
-
*
|
|
250
|
-
* Converts between TUniversalMessage format and OpenAI native types.
|
|
251
|
-
* Provides bidirectional conversion for seamless integration.
|
|
252
|
-
*
|
|
253
|
-
* @public
|
|
254
|
-
*/
|
|
255
|
-
declare class OpenAIConversationAdapter {
|
|
256
|
-
/**
|
|
257
|
-
* Filter messages for OpenAI compatibility
|
|
258
|
-
*
|
|
259
|
-
* OpenAI has specific requirements:
|
|
260
|
-
* - Tool messages must have valid toolCallId
|
|
261
|
-
* - Messages must be in proper sequence
|
|
262
|
-
* - Tool messages without toolCallId should be excluded
|
|
263
|
-
*/
|
|
264
|
-
static filterMessagesForOpenAI(messages: TUniversalMessage[]): TUniversalMessage[];
|
|
265
|
-
/**
|
|
266
|
-
* Convert TUniversalMessage array to OpenAI message format
|
|
267
|
-
* Now properly handles tool messages for OpenAI's tool calling feature
|
|
268
|
-
*/
|
|
269
|
-
static toOpenAIFormat(messages: TUniversalMessage[]): OpenAI.Chat.ChatCompletionMessageParam[];
|
|
270
|
-
/**
|
|
271
|
-
* Convert a single TUniversalMessage to OpenAI format
|
|
272
|
-
* Handles all message types including tool messages
|
|
273
|
-
*/
|
|
274
|
-
static convertMessage(msg: TUniversalMessage): OpenAI.Chat.ChatCompletionMessageParam;
|
|
275
|
-
/**
|
|
276
|
-
* Add system prompt to message array if needed
|
|
277
|
-
*/
|
|
278
|
-
static addSystemPromptIfNeeded(messages: OpenAI.Chat.ChatCompletionMessageParam[], systemPrompt?: string): OpenAI.Chat.ChatCompletionMessageParam[];
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
interface IOpenAIModelCatalogResponse {
|
|
282
|
-
data?: readonly IOpenAIModelCatalogResource[];
|
|
283
|
-
}
|
|
284
|
-
interface IOpenAIModelCatalogResource {
|
|
285
|
-
id?: string;
|
|
286
|
-
}
|
|
287
|
-
interface IOpenAIModelCatalogFetchInit {
|
|
288
|
-
headers: Record<string, string>;
|
|
289
|
-
}
|
|
290
|
-
interface IOpenAIModelCatalogFetchResponse {
|
|
291
|
-
ok: boolean;
|
|
292
|
-
status: number;
|
|
293
|
-
statusText?: string;
|
|
294
|
-
json: () => Promise<IOpenAIModelCatalogResponse>;
|
|
295
|
-
}
|
|
296
|
-
type TOpenAIModelCatalogFetch = (url: string, init: IOpenAIModelCatalogFetchInit) => Promise<IOpenAIModelCatalogFetchResponse>;
|
|
297
|
-
interface IRefreshOpenAIModelCatalogOptions {
|
|
298
|
-
fetcher?: TOpenAIModelCatalogFetch;
|
|
299
|
-
now?: () => Date;
|
|
300
|
-
}
|
|
301
|
-
declare function refreshOpenAIModelCatalog(profile: IProviderProfileConfig, options?: IRefreshOpenAIModelCatalogOptions): Promise<IProviderModelCatalog>;
|
|
302
|
-
|
|
303
|
-
declare const DEFAULT_OPENAI_PROVIDER_MODEL: string | undefined;
|
|
304
|
-
declare const DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE = "$ENV:OPENAI_API_KEY";
|
|
305
|
-
declare function createOpenAIProviderDefinition(): IProviderDefinition;
|
|
306
|
-
|
|
307
|
-
export { DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE, DEFAULT_OPENAI_PROVIDER_MODEL, type IOpenAIJsonSchemaDefinition, type IOpenAIModelCatalogFetchInit, type IOpenAIModelCatalogFetchResponse, type IOpenAIModelCatalogResource, type IOpenAIModelCatalogResponse, type IOpenAINativeWebToolsOptions, type IOpenAIProviderOptions, type IOpenAIResponsesReasoningOptions, type IPayloadLogger, type IPayloadLoggerOptions, type IRefreshOpenAIModelCatalogOptions, OpenAIConversationAdapter, OpenAIProvider, type TOpenAIApiSurface, type TOpenAIModelCatalogFetch, type TOpenAIProviderOptionValue, createOpenAIProviderDefinition, refreshOpenAIModelCatalog };
|
package/dist/browser/index.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import Se from'openai';import {AbstractAIProvider,SilentLogger}from'@robota-sdk/agent-core';import {probeOpenAICompatibleProfile,OpenAICompatibleResponseParser,observeProviderNativeRawPayloadStream,assembleOpenAICompatibleStream,convertToOpenAICompatibleMessages,convertToOpenAICompatibleTools}from'@robota-sdk/agent-provider-openai-compatible';import {randomUUID}from'crypto';var p=class{parser;constructor(t){this.parser=new OpenAICompatibleResponseParser({logger:t});}parseResponse(t){try{return this.parser.parseResponse(t)}catch(n){let o=h(n instanceof Error?n.message:"OpenAI response parsing failed");throw new Error(`OpenAI response parsing failed: ${o}`)}}parseStreamingChunk(t){try{return this.parser.parseStreamingChunk(t)}catch(n){let o=h(n instanceof Error?n.message:"OpenAI chunk parsing failed");throw new Error(`OpenAI chunk parsing failed: ${o}`)}}};function h(e){return e.replace(/^OpenAI-compatible response parsing failed: /,"").replace(/^OpenAI-compatible chunk parsing failed: /,"").replace("OpenAI-compatible response","OpenAI response")}function g(e){if(e.responseFormat===void 0||e.responseFormat==="text")return;if(e.responseFormat==="json_object")return {type:"json_object"};let t=y(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 A(e){if(e.responseFormat===void 0||e.responseFormat==="text")return;if(e.responseFormat==="json_object")return {format:{type:"json_object"}};let t=y(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 y(e){let t=e.jsonSchema;if(e.responseFormat!=="json_schema")throw new Error(`Unsupported OpenAI response format: ${e.responseFormat}`);if(!t?.schema)throw new 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}}}function v(e){return convertToOpenAICompatibleMessages(e)}function T(e){return convertToOpenAICompatibleTools(e)}async function b(e){let t=M(e.client);try{let n=S(e);if(e.chatOptions?.onTextDelta??e.onTextDelta)return await ee(t,e,{...n,stream:!0});await d(e,n,"chat"),e.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"chat-completions",payloadKind:"request",payload:n});let s=await t.chat.completions.create(n);return e.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"chat-completions",payloadKind:"response",payload:s}),e.responseParser.parseResponse(s)}catch(n){let s=n.message||"OpenAI API request failed";throw new Error(`OpenAI chat failed: ${s}`)}}async function*P(e){let t=M(e.client);try{let n={...S(e),stream:!0};await d(e,n,"stream"),e.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"chat-completions",payloadKind:"request",payload:n});let o=await t.chat.completions.create(n,e.chatOptions?.signal?{signal:e.chatOptions.signal}:void 0);for await(let s of observeProviderNativeRawPayloadStream(o,{provider:"openai",apiSurface:"chat-completions",onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload})){let r=e.responseParser.parseStreamingChunk(s);r&&(yield r);}}catch(n){let s=n.message||"OpenAI API request failed";throw new Error(`OpenAI stream failed: ${s}`)}}function S(e){let t=v(e.messages),n=e.chatOptions?.model??e.providerOptions.defaultModel;if(!n)throw new Error("Model is required in chat options. Please specify a model in defaultModel configuration.");let o=g(e.providerOptions);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:T(e.chatOptions.tools),tool_choice:"auto"},...o!==void 0&&{response_format:o}}}async function ee(e,t,n){try{await d(t,n,"stream"),t.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"chat-completions",payloadKind:"request",payload:n});let o=await e.chat.completions.create(n,t.chatOptions?.signal?{signal:t.chatOptions.signal}:void 0);return assembleOpenAICompatibleStream({stream:observeProviderNativeRawPayloadStream(o,{provider:"openai",apiSurface:"chat-completions",onProviderNativeRawPayload:t.chatOptions?.onProviderNativeRawPayload}),onTextDelta:t.chatOptions?.onTextDelta??t.onTextDelta,signal:t.chatOptions?.signal})}catch(o){let r=o.message||"OpenAI streaming request failed";throw new Error(`OpenAI stream failed: ${r}`)}}async function d(e,t,n){if(!e.payloadLogger?.isEnabled())return;let o={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(o,n);}function M(e){if(!e)throw new Error("OpenAI client not available. Either provide a client/apiKey or use an executor.");return e}function x(e){return e.flatMap(t=>te(t))}function w(e,t){let n=e?.map(o=>({type:"function",name:o.name,description:o.description,parameters:o.parameters,strict:t??false}))??[];return n.length>0?n:void 0}function te(e){if(e.role==="user")return [l("user",oe(e.content,e.parts))];if(e.role==="system")return [l("system",e.content)];if(e.role==="tool"){if(!e.toolCallId||e.toolCallId.trim().length===0)throw new Error(`Tool message missing toolCallId: ${JSON.stringify(e)}`);return [{type:"function_call_output",call_id:e.toolCallId,output:e.content||""}]}return ne(e)}function ne(e){let t=[];e.content&&e.content.length>0&&t.push(l("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(l("assistant","")),t}function oe(e,t){if(!t||t.length===0)return e;let n=t.map(o=>se(o));return e.length>0&&!t.some(o=>o.type==="text")?[{type:"input_text",text:e},...n]:n}function se(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 l(e,t){return {role:e,content:t}}async function*E(e,t){let n=e[Symbol.asyncIterator]();try{for(;!t?.aborted;){let o=await re(n,t);if(o.done||t?.aborted)break;yield o.value;}}finally{t?.aborted&&await n.return?.();}}async function re(e,t){if(!t)return e.next();if(t.aborted)return {done:true,value:void 0};let n,o=new Promise(s=>{n=()=>s({done:true,value:void 0}),t.addEventListener("abort",n,{once:true});});try{return await Promise.race([e.next(),o])}finally{n&&t.removeEventListener("abort",n);}}function U(e){j(e);let t=e.output??[],n=e.output_text??N(t);return u({content:n,toolCalls:k(t),response:e,reasoning:c(t)})}async function _(e){let t={textParts:[],toolCalls:[],reasoning:W()};for await(let n of E(e.stream,e.signal))ie(t,n,e.onTextDelta);return t.completedResponse!==void 0?le(t):u({content:t.textParts.join(""),toolCalls:t.toolCalls,reasoning:t.reasoning})}function ie(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,m(e.reasoning,c(t.response.output??[]));return}if(t.type==="response.output_item.done"){pe(e,t.item);return}if(t.type==="response.error"||t.type==="response.failed"||t.type==="response.incomplete")throw new Error(`OpenAI Responses API failed: ${fe(t)}`)}function pe(e,t){if(D(t)){e.toolCalls.push(F(t));return}L(t)&&m(e.reasoning,c([t]));}function le(e){let t=e.completedResponse;if(t===void 0)throw new Error("OpenAI Responses stream completed without response metadata");j(t);let n=t.output??[],o=k(n),s=e.textParts.length>0?e.textParts.join(""):t.output_text??N(n),r=c(n);return m(r,e.reasoning),u({content:s,toolCalls:o.length>0?o:e.toolCalls,response:t,reasoning:r})}function u(e){return {id:randomUUID(),role:"assistant",content:e.content,state:"complete",timestamp:new Date,...e.toolCalls.length>0&&{toolCalls:e.toolCalls},...e.response?.usage!==void 0&&{usage:de(e.response.usage)},metadata:ce(e.response,e.reasoning)}}function ce(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:true}}}function de(e){return {promptTokens:e.input_tokens??0,completionTokens:e.output_tokens??0,totalTokens:e.total_tokens??0}}function k(e){return e.filter(D).map(t=>F(t))}function D(e){return e.type==="function_call"&&"call_id"in e&&"name"in e&&"arguments"in e}function F(e){return {id:e.call_id,type:"function",function:{name:e.name,arguments:e.arguments}}}function N(e){return e.filter(me).flatMap(t=>t.content).map(ue).join("")}function ue(e){return e.type==="refusal"?e.refusal:e.text}function me(e){return e.type==="message"&&"content"in e&&Array.isArray(e.content)}function c(e){let t=W();for(let n of e){if(!L(n))continue;let o=n.summary?.map(s=>s.text).filter(Ie)??[];t.reasoningSummaryCount+=o.length,t.reasoningSummaries.push(...o),t.hasEncryptedReasoning=t.hasEncryptedReasoning||!!n.encrypted_content;}return t}function L(e){return e.type==="reasoning"}function W(){return {reasoningSummaryCount:0,reasoningSummaries:[],hasEncryptedReasoning:false}}function m(e,t){e.reasoningSummaryCount+=t.reasoningSummaryCount,e.reasoningSummaries.push(...t.reasoningSummaries),e.hasEncryptedReasoning=e.hasEncryptedReasoning||t.hasEncryptedReasoning;}function Ie(e){return e!==void 0}function j(e){if(e.status==="failed"||e.status==="incomplete")throw new Error(`OpenAI Responses API failed: ${e.error?.message??e.status}`)}function fe(e){return e.message??e.error?.message??e.response?.error?.message??"unknown error"}async function $(e){let t=e.chatOptions?.onTextDelta??e.onTextDelta;if(t)return q({...e,chatOptions:{...e.chatOptions,onTextDelta:t}});if(!e.client)throw new Error("OpenAI Responses client not available.");try{let n=V(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"responses",payloadKind:"request",payload:n});let o=await e.client.responses.create(n,e.chatOptions?.signal?{signal:e.chatOptions.signal}:void 0);return e.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"responses",payloadKind:"response",payload:o}),U(o)}catch(n){let s=n.message||"OpenAI Responses API request failed";throw new Error(`OpenAI responses failed: ${s}`)}}async function*K(e){let t={deltas:[]},n=e.chatOptions?.onTextDelta??e.onTextDelta,o=q({...e,chatOptions:{...e.chatOptions,onTextDelta:s=>{n?.(s),ve(t,Ae(s));}}}).then(s=>Te(t,s)).catch(s=>Re(t,Pe(s)));yield*ye(t),await o;}async function q(e){if(!e.client)throw new Error("OpenAI Responses client not available.");try{let t=ge(e);e.chatOptions?.onProviderNativeRawPayload?.({provider:"openai",apiSurface:"responses",payloadKind:"request",payload:t});let n=await e.client.responses.create(t,e.chatOptions?.signal?{signal:e.chatOptions.signal}:void 0);return _({stream:observeProviderNativeRawPayloadStream(n,{provider:"openai",apiSurface:"responses",onProviderNativeRawPayload:e.chatOptions?.onProviderNativeRawPayload}),onTextDelta:e.chatOptions?.onTextDelta,signal:e.chatOptions?.signal})}catch(t){let o=t.message||"OpenAI Responses streaming request failed";throw new Error(`OpenAI responses stream failed: ${o}`)}}function V(e){let t=e.chatOptions?.model??e.providerOptions.defaultModel;if(!t)throw new Error("Model is required in chat options. Please specify a model in defaultModel configuration.");let n=w(e.chatOptions?.tools,e.providerOptions.strictTools),o=A(e.providerOptions);return {model:t,input:x(e.messages),...n!==void 0&&{tools:n,tool_choice:"auto"},...e.chatOptions?.temperature!==void 0&&{temperature:e.chatOptions.temperature},...e.chatOptions?.maxTokens!==void 0&&{max_output_tokens:e.chatOptions.maxTokens},...o!==void 0&&{text:o},...e.providerOptions.reasoning!==void 0&&{reasoning:e.providerOptions.reasoning},...e.providerOptions.includeEncryptedReasoning===true&&{include:["reasoning.encrypted_content"]},...e.providerOptions.store!==void 0&&{store:e.providerOptions.store}}}function ge(e){return {...V(e),stream:true}}function Ae(e){return {id:randomUUID(),role:"assistant",content:e,state:"complete",timestamp:new Date,metadata:{providerApiSurface:"responses",isStreamChunk:true,isComplete:false}}}async function*ye(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 Ce(e);}}function ve(e,t){e.deltas.push(t),I(e);}function Te(e,t){e.finalMessage=t,I(e);}function Re(e,t){e.error=t,I(e);}function Ce(e){return new Promise(t=>{e.wake=t;})}function I(e){e.wake?.(),e.wake=void 0;}function be(e){return {...e,content:"",metadata:{...e.metadata,isStreamChunk:true,isComplete:true}}}function Pe(e){return e instanceof Error?e:new Error(String(e))}var i=class extends AbstractAIProvider{name="openai";version="1.0.0";client;options;apiSurface;payloadLogger;responseParser;onTextDelta;constructor(t){if(super(t.logger||SilentLogger),this.options=t,this.apiSurface=we(t),Ee(this.apiSurface,t.nativeWebTools),t.executor&&(this.executor=t.executor),!this.executor)if(t.client)this.client=t.client;else if(t.apiKey)this.client=new Se({apiKey:t.apiKey,...t.organization&&{organization:t.organization},...t.timeout&&{timeout:t.timeout},...t.baseURL&&{baseURL:t.baseURL}});else throw new Error("Either OpenAI client, apiKey, or executor is required");this.responseParser=new p(this.logger),this.payloadLogger=t.payloadLogger;}async chat(t,n){if(this.validateMessages(t),this.validateNativeWebTools(n?.nativeWebTools),this.executor)try{return await this.executeViaExecutorOrDirect(t,n)}catch(o){throw this.logger.error("OpenAI Provider executor chat error:",o instanceof Error?o.message:String(o)),o}return this.apiSurface==="responses"?$({client:this.client,messages:t,chatOptions:n,providerOptions:this.options,onTextDelta:this.onTextDelta}):b({client:this.client,messages:t,chatOptions:n,providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta})}async*chatStream(t,n){if(this.validateNativeWebTools(n?.nativeWebTools),this.executor)try{yield*this.executeStreamViaExecutorOrDirect(t,n);return}catch(o){throw this.logger.error("OpenAI Provider executor stream error:",o instanceof Error?o.message:String(o)),o}if(this.apiSurface==="responses"){yield*K({client:this.client,messages:t,chatOptions:n,providerOptions:this.options,onTextDelta:this.onTextDelta});return}yield*P({client:this.client,messages:t,chatOptions:n,providerOptions:this.options,payloadLogger:this.payloadLogger,responseParser:this.responseParser,onTextDelta:this.onTextDelta});}supportsTools(){return true}getCapabilities(){let t=this.apiSurface==="chat-completions"?"openai-compatible-chat-completions":"openai-responses";return {functionCalling:{supported:true},nativeWebTools:{webSearch:{supported:false,enabled:false,source:t,reason:Q(this.apiSurface,"search")},webFetch:{supported:false,enabled:false,source:t,reason:Q(this.apiSurface,"fetch")}}}}validateConfig(){return !!this.client&&!!this.options}async dispose(){}validateMessages(t){super.validateMessages(t);for(let n of t)if(n.role==="assistant"){let o=n;if(o.toolCalls&&o.toolCalls.length>0&&o.content==="")continue}}};function we(e){return e.apiSurface!==void 0?e.apiSurface:e.baseURL?"chat-completions":"responses"}function Q(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 Ee(e,t){if(!(t?.webSearch!==true&&t?.webFetch!==true))throw new Error(`Provider openai native web search/fetch is not supported for apiSurface ${e} in this Robota provider version.`)}var J=class{static filterMessagesForOpenAI(t){return t.filter(n=>n.role==="user"||n.role==="assistant"||n.role==="system"?true:n.role==="tool"?!!(n.toolCallId&&n.toolCallId.trim()!==""&&n.toolCallId!=="unknown"):false)}static toOpenAIFormat(t){return this.filterMessagesForOpenAI(t).map(o=>this.convertMessage(o))}static convertMessage(t){let n=t.role;if(n==="user")return {role:"user",content:t.content};if(n==="assistant"){let s=t;return s.toolCalls&&s.toolCalls.length>0?{role:"assistant",content:s.content===""?null:s.content||null,tool_calls:s.toolCalls.map(a=>({id:a.id,type:"function",function:{name:a.function.name,arguments:a.function.arguments}}))}:{role:"assistant",content:s.content===null||s.content===""?null:s.content||""}}if(n==="system")return {role:"system",content:t.content};if(n==="tool"){if(!t.toolCallId||t.toolCallId.trim()==="")throw new Error(`Tool message missing toolCallId: ${JSON.stringify(t)}`);return {role:"tool",content:t.content,tool_call_id:t.toolCallId}}let o=n;throw new Error(`Unsupported message role: ${o}`)}static addSystemPromptIfNeeded(t,n){return !n||t.some(s=>s.role==="system")?t:[{role:"system",content:n},...t]}};var Ue="https://api.openai.com/v1/models",z="https://platform.openai.com/docs/api-reference/models/list";async function H(e,t={}){if(!e.apiKey)return f("OpenAI model catalog refresh requires apiKey.");let n=t.fetcher??Fe,o=t.now??(()=>new Date),s=_e(e.baseURL);try{let r=await n(s,{headers:{Authorization:`Bearer ${e.apiKey}`}});if(!r.ok)return f(De(r));let a=await r.json(),O=ke(a);return {status:"live",entries:O,lastVerifiedAt:o().toISOString(),sourceUrl:z,message:`${O.length} OpenAI model(s) discovered.`}}catch(r){return f(r instanceof Error?r.message:String(r))}}function _e(e){return e?`${e.replace(/\/$/,"")}/models`:Ue}function ke(e){return (e.data??[]).map(t=>t.id).filter(t=>t!==void 0&&t.trim().length>0).map(t=>({id:t,displayName:t,lifecycle:"active"}))}function De(e){let t=e.statusText?` ${e.statusText}`:"";return `OpenAI model catalog refresh failed: HTTP ${e.status}${t}`}function f(e){return {status:"unavailable",sourceUrl:z,message:e}}async function Fe(e,t){let n=await fetch(e,t);return {ok:n.ok,status:n.status,statusText:n.statusText,json:()=>n.json()}}var St=void 0,Y="$ENV:OPENAI_API_KEY",Le="https://platform.openai.com/api-keys",We="https://developers.openai.com/api/reference/overview#authentication",je="2026-05-08",$e=[{kind:"api-key",label:"OpenAI API keys",url:Le,sourceUrl:We,lastVerifiedAt:je}];function Mt(){return {type:"openai",displayName:"OpenAI",description:"Official OpenAI Responses API provider",defaults:{apiKey:Y},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:$e,setupSteps:[{key:"model",title:"OpenAI model",required:true},{key:"apiKey",title:"OpenAI API key",defaultValue:Y,masked:true}],requiresApiKey:true,probeProfile:probeOpenAICompatibleProfile,refreshModelCatalog:({profile:e})=>H(e),createProvider:e=>{let t=qe(e.options),n=Ve(e.options);return Qe(e.baseURL,t,n),new i({apiKey:Ke(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 Ke(e){if(!e)throw new Error("Provider openai requires apiKey");return e}function qe(e){let t=e?.apiSurface;if(t==="responses"||t==="chat-completions")return t}function Ve(e){let t=G(e?.nativeWebTools)??G(e?.builtInWebTools);if(t!==void 0)return t}function G(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 Qe(e,t,n){if(!(n?.webSearch!==true&&n?.webFetch!==true))throw e!==void 0||t==="chat-completions"?new Error("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."):new Error("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.")}
|
|
2
|
-
export{Y as DEFAULT_OPENAI_PROVIDER_API_KEY_REFERENCE,St as DEFAULT_OPENAI_PROVIDER_MODEL,J as OpenAIConversationAdapter,i as OpenAIProvider,Mt as createOpenAIProviderDefinition,H as refreshOpenAIModelCatalog};
|