@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.
Files changed (70) hide show
  1. package/LICENSE +661 -21
  2. package/dist/node/index.cjs +1 -2
  3. package/dist/node/index.d.cts +271 -267
  4. package/dist/node/index.d.cts.map +1 -0
  5. package/dist/node/index.d.ts +271 -267
  6. package/dist/node/index.d.ts.map +1 -0
  7. package/dist/node/index.js +2 -2
  8. package/dist/node/index.js.map +1 -0
  9. package/dist/node/loggers/index.cjs +1 -0
  10. package/dist/node/loggers/index.d.cts +94 -0
  11. package/dist/node/loggers/index.d.cts.map +1 -0
  12. package/dist/node/loggers/index.d.ts +94 -0
  13. package/dist/node/loggers/index.d.ts.map +1 -0
  14. package/dist/node/loggers/index.js +2 -0
  15. package/dist/node/loggers/index.js.map +1 -0
  16. package/dist/node/payload-logger-BaW0K8yI.d.cts +61 -0
  17. package/dist/node/payload-logger-BaW0K8yI.d.cts.map +1 -0
  18. package/dist/node/payload-logger-BaW0K8yI.d.ts +61 -0
  19. package/dist/node/payload-logger-BaW0K8yI.d.ts.map +1 -0
  20. package/dist/node/rolldown-runtime-CMqjfN_6.cjs +1 -0
  21. package/package.json +69 -86
  22. package/src/index.ts +1 -0
  23. package/src/openai/__tests__/endpoint-provenance.test.ts +44 -0
  24. package/src/openai/__tests__/provider-errors.test.ts +114 -0
  25. package/src/openai/__tests__/request-format.test.ts +59 -0
  26. package/src/openai/__tests__/strict-tools-closure.test.ts +136 -0
  27. package/src/openai/__tests__/tool-schema-projection.test.ts +302 -0
  28. package/src/openai/__tests__/trace-context-wire.test.ts +114 -0
  29. package/src/openai/adapter.test.ts +494 -0
  30. package/src/openai/adapter.ts +145 -0
  31. package/src/openai/chat-completions-chat.ts +225 -0
  32. package/src/openai/executor-integration.test.ts +213 -0
  33. package/src/openai/index.ts +19 -0
  34. package/src/openai/interfaces/payload-logger.ts +48 -0
  35. package/src/openai/loggers/console-payload-logger.test.ts +173 -0
  36. package/src/openai/loggers/console-payload-logger.ts +96 -0
  37. package/src/openai/loggers/console.ts +9 -0
  38. package/src/openai/loggers/file-payload-logger.test.ts +243 -0
  39. package/src/openai/loggers/file-payload-logger.ts +124 -0
  40. package/src/openai/loggers/file.ts +9 -0
  41. package/src/openai/loggers/index.ts +12 -0
  42. package/src/openai/loggers/sanitize-openai-log-data.test.ts +89 -0
  43. package/src/openai/loggers/sanitize-openai-log-data.ts +14 -0
  44. package/src/openai/message-converter.ts +23 -0
  45. package/src/openai/model-effort-table.ts +19 -0
  46. package/src/openai/model-effort-verification-config.test.ts +45 -0
  47. package/src/openai/model-effort-verification-config.ts +35 -0
  48. package/src/openai/openai-request-format.ts +116 -0
  49. package/src/openai/parsers/response-parser.test.ts +407 -0
  50. package/src/openai/parsers/response-parser.ts +48 -0
  51. package/src/openai/provider-definition.test.ts +74 -0
  52. package/src/openai/provider-definition.ts +139 -0
  53. package/src/openai/provider.test.ts +1686 -0
  54. package/src/openai/provider.ts +392 -0
  55. package/src/openai/reasoning-effort.test.ts +272 -0
  56. package/src/openai/reasoning-effort.ts +49 -0
  57. package/src/openai/request-id.ts +39 -0
  58. package/src/openai/request-options.ts +14 -0
  59. package/src/openai/responses-chat.ts +285 -0
  60. package/src/openai/responses-converter.ts +122 -0
  61. package/src/openai/responses-parser.ts +297 -0
  62. package/src/openai/responses-stream-utils.ts +45 -0
  63. package/src/openai/responses-types.ts +193 -0
  64. package/src/openai/streaming/stream-assembler.ts +3 -0
  65. package/src/openai/types/api-types.ts +113 -0
  66. package/src/openai/types.ts +235 -0
  67. package/CHANGELOG.md +0 -614
  68. package/README.md +0 -467
  69. package/dist/browser/index.d.ts +0 -307
  70. package/dist/browser/index.js +0 -2
@@ -0,0 +1,297 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ import { streamWithAbort } from './responses-stream-utils';
4
+
5
+ import type {
6
+ IOpenAIResponsesErrorEvent,
7
+ IOpenAIResponsesFunctionCallOutputItem,
8
+ IOpenAIResponsesMessageOutputItem,
9
+ IOpenAIResponsesReasoningOutputItem,
10
+ IOpenAIResponsesResponse,
11
+ IOpenAIResponsesUsage,
12
+ TOpenAIResponsesOutputContent,
13
+ TOpenAIResponsesOutputItem,
14
+ TOpenAIResponsesStreamEvent,
15
+ } from './responses-types';
16
+ import type { IToolCall, TTextDeltaCallback, TUniversalMessage } from '@robota-sdk/agent-core';
17
+
18
+ interface IOpenAIResponsesStreamAssemblyOptions {
19
+ stream: AsyncIterable<TOpenAIResponsesStreamEvent>;
20
+ onTextDelta?: TTextDeltaCallback;
21
+ signal?: AbortSignal;
22
+ }
23
+
24
+ interface IOpenAIResponsesReasoningMetadata {
25
+ reasoningSummaryCount: number;
26
+ reasoningSummaries: string[];
27
+ hasEncryptedReasoning: boolean;
28
+ }
29
+
30
+ interface IOpenAIResponseUsage {
31
+ promptTokens: number;
32
+ completionTokens: number;
33
+ totalTokens: number;
34
+ }
35
+
36
+ interface IOpenAIResponsesStreamState {
37
+ textParts: string[];
38
+ toolCalls: IToolCall[];
39
+ completedResponse?: IOpenAIResponsesResponse;
40
+ reasoning: IOpenAIResponsesReasoningMetadata;
41
+ }
42
+
43
+ export function parseOpenAIResponsesResponse(
44
+ response: IOpenAIResponsesResponse,
45
+ ): TUniversalMessage {
46
+ assertUsableResponse(response);
47
+ const output = response.output ?? [];
48
+ const content = response.output_text ?? extractMessageText(output);
49
+ return buildAssistantMessage({
50
+ content,
51
+ toolCalls: extractFunctionToolCalls(output),
52
+ response,
53
+ reasoning: collectReasoningMetadata(output),
54
+ });
55
+ }
56
+
57
+ export async function assembleOpenAIResponsesStream(
58
+ options: IOpenAIResponsesStreamAssemblyOptions,
59
+ ): Promise<TUniversalMessage> {
60
+ const state: IOpenAIResponsesStreamState = {
61
+ textParts: [],
62
+ toolCalls: [],
63
+ reasoning: createEmptyReasoningMetadata(),
64
+ };
65
+
66
+ for await (const event of streamWithAbort(options.stream, options.signal)) {
67
+ applyStreamEvent(state, event, options.onTextDelta);
68
+ }
69
+
70
+ if (state.completedResponse !== undefined) {
71
+ return buildMessageFromCompletedResponse(state);
72
+ }
73
+
74
+ return buildAssistantMessage({
75
+ content: state.textParts.join(''),
76
+ toolCalls: state.toolCalls,
77
+ reasoning: state.reasoning,
78
+ });
79
+ }
80
+
81
+ function applyStreamEvent(
82
+ state: IOpenAIResponsesStreamState,
83
+ event: TOpenAIResponsesStreamEvent,
84
+ onTextDelta: TTextDeltaCallback | undefined,
85
+ ): void {
86
+ if (event.type === 'response.output_text.delta') {
87
+ state.textParts.push(event.delta);
88
+ onTextDelta?.(event.delta);
89
+ return;
90
+ }
91
+
92
+ if (event.type === 'response.completed') {
93
+ state.completedResponse = event.response;
94
+ mergeReasoningMetadata(state.reasoning, collectReasoningMetadata(event.response.output ?? []));
95
+ return;
96
+ }
97
+
98
+ if (event.type === 'response.output_item.done') {
99
+ applyOutputItem(state, event.item);
100
+ return;
101
+ }
102
+
103
+ if (
104
+ event.type === 'response.error' ||
105
+ event.type === 'response.failed' ||
106
+ event.type === 'response.incomplete'
107
+ ) {
108
+ throw new Error(`OpenAI Responses API failed: ${extractErrorMessage(event)}`);
109
+ }
110
+ }
111
+
112
+ function applyOutputItem(
113
+ state: IOpenAIResponsesStreamState,
114
+ item: TOpenAIResponsesOutputItem,
115
+ ): void {
116
+ if (isFunctionCallOutputItem(item)) {
117
+ state.toolCalls.push(convertFunctionCall(item));
118
+ return;
119
+ }
120
+ if (isReasoningOutputItem(item)) {
121
+ mergeReasoningMetadata(state.reasoning, collectReasoningMetadata([item]));
122
+ }
123
+ }
124
+
125
+ function buildMessageFromCompletedResponse(state: IOpenAIResponsesStreamState): TUniversalMessage {
126
+ const response = state.completedResponse;
127
+ if (response === undefined) {
128
+ throw new Error('OpenAI Responses stream completed without response metadata');
129
+ }
130
+
131
+ assertUsableResponse(response);
132
+ const output = response.output ?? [];
133
+ const responseToolCalls = extractFunctionToolCalls(output);
134
+ const content =
135
+ state.textParts.length > 0
136
+ ? state.textParts.join('')
137
+ : (response.output_text ?? extractMessageText(output));
138
+ const reasoning = collectReasoningMetadata(output);
139
+ mergeReasoningMetadata(reasoning, state.reasoning);
140
+
141
+ return buildAssistantMessage({
142
+ content,
143
+ toolCalls: responseToolCalls.length > 0 ? responseToolCalls : state.toolCalls,
144
+ response,
145
+ reasoning,
146
+ });
147
+ }
148
+
149
+ function buildAssistantMessage(input: {
150
+ content: string;
151
+ toolCalls: IToolCall[];
152
+ response?: IOpenAIResponsesResponse;
153
+ reasoning: IOpenAIResponsesReasoningMetadata;
154
+ }): TUniversalMessage {
155
+ return {
156
+ id: randomUUID(),
157
+ role: 'assistant',
158
+ content: input.content,
159
+ state: 'complete',
160
+ timestamp: new Date(),
161
+ ...(input.toolCalls.length > 0 && { toolCalls: input.toolCalls }),
162
+ ...(input.response?.usage !== undefined && { usage: mapUsage(input.response.usage) }),
163
+ metadata: {
164
+ ...buildMetadata(input.response, input.reasoning),
165
+ ...(input.response?.usage !== undefined && {
166
+ usageProvenance:
167
+ input.response.usage.input_tokens !== undefined &&
168
+ input.response.usage.output_tokens !== undefined &&
169
+ input.response.usage.total_tokens !== undefined
170
+ ? 'complete'
171
+ : 'partial',
172
+ }),
173
+ },
174
+ };
175
+ }
176
+
177
+ function buildMetadata(
178
+ response: IOpenAIResponsesResponse | undefined,
179
+ reasoning: IOpenAIResponsesReasoningMetadata,
180
+ ): NonNullable<TUniversalMessage['metadata']> {
181
+ return {
182
+ providerApiSurface: 'responses',
183
+ ...(response?.id !== undefined && { responseId: response.id }),
184
+ ...(response?.model !== undefined && { model: response.model }),
185
+ ...(response?.status !== undefined && { finishReason: response.status }),
186
+ ...(reasoning.reasoningSummaryCount > 0 && {
187
+ reasoningSummaryCount: reasoning.reasoningSummaryCount,
188
+ reasoningSummaries: reasoning.reasoningSummaries,
189
+ }),
190
+ ...(reasoning.hasEncryptedReasoning && { hasEncryptedReasoning: true }),
191
+ };
192
+ }
193
+
194
+ function mapUsage(usage: IOpenAIResponsesUsage): IOpenAIResponseUsage {
195
+ return {
196
+ promptTokens: usage.input_tokens ?? 0,
197
+ completionTokens: usage.output_tokens ?? 0,
198
+ totalTokens: usage.total_tokens ?? 0,
199
+ };
200
+ }
201
+
202
+ function extractFunctionToolCalls(output: readonly TOpenAIResponsesOutputItem[]): IToolCall[] {
203
+ return output.filter(isFunctionCallOutputItem).map((item) => convertFunctionCall(item));
204
+ }
205
+
206
+ function isFunctionCallOutputItem(
207
+ item: TOpenAIResponsesOutputItem,
208
+ ): item is IOpenAIResponsesFunctionCallOutputItem {
209
+ return (
210
+ item.type === 'function_call' && 'call_id' in item && 'name' in item && 'arguments' in item
211
+ );
212
+ }
213
+
214
+ function convertFunctionCall(item: IOpenAIResponsesFunctionCallOutputItem): IToolCall {
215
+ return {
216
+ id: item.call_id,
217
+ type: 'function',
218
+ function: {
219
+ name: item.name,
220
+ arguments: item.arguments,
221
+ },
222
+ };
223
+ }
224
+
225
+ function extractMessageText(output: readonly TOpenAIResponsesOutputItem[]): string {
226
+ return output
227
+ .filter(isMessageOutputItem)
228
+ .flatMap((item) => item.content)
229
+ .map(extractTextContent)
230
+ .join('');
231
+ }
232
+
233
+ function extractTextContent(content: TOpenAIResponsesOutputContent): string {
234
+ if (content.type === 'refusal') {
235
+ return content.refusal;
236
+ }
237
+ return content.text;
238
+ }
239
+
240
+ function isMessageOutputItem(
241
+ item: TOpenAIResponsesOutputItem,
242
+ ): item is IOpenAIResponsesMessageOutputItem {
243
+ return item.type === 'message' && 'content' in item && Array.isArray(item.content);
244
+ }
245
+
246
+ function collectReasoningMetadata(
247
+ output: readonly TOpenAIResponsesOutputItem[],
248
+ ): IOpenAIResponsesReasoningMetadata {
249
+ const metadata = createEmptyReasoningMetadata();
250
+ for (const item of output) {
251
+ if (!isReasoningOutputItem(item)) {
252
+ continue;
253
+ }
254
+ const summaries = item.summary?.map((summary) => summary.text).filter(isString) ?? [];
255
+ metadata.reasoningSummaryCount += summaries.length;
256
+ metadata.reasoningSummaries.push(...summaries);
257
+ metadata.hasEncryptedReasoning = metadata.hasEncryptedReasoning || !!item.encrypted_content;
258
+ }
259
+ return metadata;
260
+ }
261
+
262
+ function isReasoningOutputItem(
263
+ item: TOpenAIResponsesOutputItem,
264
+ ): item is IOpenAIResponsesReasoningOutputItem {
265
+ return item.type === 'reasoning';
266
+ }
267
+
268
+ function createEmptyReasoningMetadata(): IOpenAIResponsesReasoningMetadata {
269
+ return {
270
+ reasoningSummaryCount: 0,
271
+ reasoningSummaries: [],
272
+ hasEncryptedReasoning: false,
273
+ };
274
+ }
275
+
276
+ function mergeReasoningMetadata(
277
+ target: IOpenAIResponsesReasoningMetadata,
278
+ source: IOpenAIResponsesReasoningMetadata,
279
+ ): void {
280
+ target.reasoningSummaryCount += source.reasoningSummaryCount;
281
+ target.reasoningSummaries.push(...source.reasoningSummaries);
282
+ target.hasEncryptedReasoning = target.hasEncryptedReasoning || source.hasEncryptedReasoning;
283
+ }
284
+
285
+ function isString(value: string | undefined): value is string {
286
+ return value !== undefined;
287
+ }
288
+
289
+ function assertUsableResponse(response: IOpenAIResponsesResponse): void {
290
+ if (response.status === 'failed' || response.status === 'incomplete') {
291
+ throw new Error(`OpenAI Responses API failed: ${response.error?.message ?? response.status}`);
292
+ }
293
+ }
294
+
295
+ function extractErrorMessage(event: IOpenAIResponsesErrorEvent): string {
296
+ return event.message ?? event.error?.message ?? event.response?.error?.message ?? 'unknown error';
297
+ }
@@ -0,0 +1,45 @@
1
+ export async function* streamWithAbort<T>(
2
+ source: AsyncIterable<T>,
3
+ signal?: AbortSignal,
4
+ ): AsyncGenerator<T> {
5
+ const iterator = source[Symbol.asyncIterator]();
6
+ try {
7
+ while (!signal?.aborted) {
8
+ const item = await nextStreamItem(iterator, signal);
9
+ if (item.done || signal?.aborted) {
10
+ break;
11
+ }
12
+ yield item.value;
13
+ }
14
+ } finally {
15
+ if (signal?.aborted) {
16
+ await iterator.return?.();
17
+ }
18
+ }
19
+ }
20
+
21
+ async function nextStreamItem<T>(
22
+ iterator: AsyncIterator<T>,
23
+ signal?: AbortSignal,
24
+ ): Promise<IteratorResult<T>> {
25
+ if (!signal) {
26
+ return iterator.next();
27
+ }
28
+ if (signal.aborted) {
29
+ return { done: true, value: undefined as T };
30
+ }
31
+
32
+ let abortListener: (() => void) | undefined;
33
+ const aborted = new Promise<IteratorResult<T>>((resolve) => {
34
+ abortListener = (): void => resolve({ done: true, value: undefined as T });
35
+ signal.addEventListener('abort', abortListener, { once: true });
36
+ });
37
+
38
+ try {
39
+ return await Promise.race([iterator.next(), aborted]);
40
+ } finally {
41
+ if (abortListener) {
42
+ signal.removeEventListener('abort', abortListener);
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,193 @@
1
+ import type {
2
+ IOpenAIJsonSchemaDefinition,
3
+ IOpenAIResponsesReasoningOptions,
4
+ TOpenAIProviderOptionValue,
5
+ } from './types';
6
+ import type { IToolSchema } from '@robota-sdk/agent-core';
7
+
8
+ export type TOpenAIResponsesInputRole = 'user' | 'assistant' | 'system' | 'developer';
9
+
10
+ export interface IOpenAIResponsesInputTextContent {
11
+ type: 'input_text';
12
+ text: string;
13
+ }
14
+
15
+ export interface IOpenAIResponsesInputImageContent {
16
+ type: 'input_image';
17
+ image_url: string;
18
+ detail?: 'auto' | 'low' | 'high';
19
+ }
20
+
21
+ export type TOpenAIResponsesInputContent =
22
+ IOpenAIResponsesInputTextContent | IOpenAIResponsesInputImageContent;
23
+
24
+ export interface IOpenAIResponsesMessageInput {
25
+ type?: 'message';
26
+ role: TOpenAIResponsesInputRole;
27
+ content: string | TOpenAIResponsesInputContent[];
28
+ }
29
+
30
+ export interface IOpenAIResponsesFunctionCallInput {
31
+ type: 'function_call';
32
+ call_id: string;
33
+ name: string;
34
+ arguments: string;
35
+ }
36
+
37
+ export interface IOpenAIResponsesFunctionCallOutputInput {
38
+ type: 'function_call_output';
39
+ call_id: string;
40
+ output: string;
41
+ }
42
+
43
+ export type TOpenAIResponsesInputItem =
44
+ | IOpenAIResponsesMessageInput
45
+ | IOpenAIResponsesFunctionCallInput
46
+ | IOpenAIResponsesFunctionCallOutputInput;
47
+
48
+ export interface IOpenAIResponsesFunctionTool {
49
+ type: 'function';
50
+ name: string;
51
+ parameters: IToolSchema['parameters'];
52
+ strict: boolean | null;
53
+ description?: string;
54
+ }
55
+
56
+ export type TOpenAIResponsesTool = IOpenAIResponsesFunctionTool;
57
+
58
+ export interface IOpenAIResponsesTextFormatText {
59
+ type: 'text';
60
+ }
61
+
62
+ export interface IOpenAIResponsesTextFormatJsonObject {
63
+ type: 'json_object';
64
+ }
65
+
66
+ export interface IOpenAIResponsesTextFormatJsonSchema extends IOpenAIJsonSchemaDefinition {
67
+ type: 'json_schema';
68
+ schema: Record<string, TOpenAIProviderOptionValue>;
69
+ }
70
+
71
+ export type TOpenAIResponsesTextFormat =
72
+ | IOpenAIResponsesTextFormatText
73
+ | IOpenAIResponsesTextFormatJsonObject
74
+ | IOpenAIResponsesTextFormatJsonSchema;
75
+
76
+ export interface IOpenAIResponsesTextConfig {
77
+ format: TOpenAIResponsesTextFormat;
78
+ }
79
+
80
+ export interface IOpenAIResponsesRequestBase {
81
+ model: string;
82
+ input: TOpenAIResponsesInputItem[];
83
+ tools?: TOpenAIResponsesTool[];
84
+ tool_choice?: 'auto' | 'none' | 'required' | { type: 'function'; name: string };
85
+ text?: IOpenAIResponsesTextConfig;
86
+ temperature?: number;
87
+ max_output_tokens?: number;
88
+ reasoning?: IOpenAIResponsesReasoningOptions;
89
+ include?: 'reasoning.encrypted_content'[];
90
+ store?: boolean;
91
+ }
92
+
93
+ export interface IOpenAIResponsesRequestNonStreaming extends IOpenAIResponsesRequestBase {
94
+ stream?: false;
95
+ }
96
+
97
+ export interface IOpenAIResponsesRequestStreaming extends IOpenAIResponsesRequestBase {
98
+ stream: true;
99
+ }
100
+
101
+ export interface IOpenAIResponsesTextOutputContent {
102
+ type: 'output_text' | 'text';
103
+ text: string;
104
+ }
105
+
106
+ export interface IOpenAIResponsesRefusalOutputContent {
107
+ type: 'refusal';
108
+ refusal: string;
109
+ }
110
+
111
+ export type TOpenAIResponsesOutputContent =
112
+ IOpenAIResponsesTextOutputContent | IOpenAIResponsesRefusalOutputContent;
113
+
114
+ export interface IOpenAIResponsesMessageOutputItem {
115
+ type: 'message';
116
+ role?: 'assistant';
117
+ content: TOpenAIResponsesOutputContent[];
118
+ }
119
+
120
+ export interface IOpenAIResponsesFunctionCallOutputItem {
121
+ type: 'function_call';
122
+ call_id: string;
123
+ name: string;
124
+ arguments: string;
125
+ id?: string;
126
+ status?: string;
127
+ }
128
+
129
+ export interface IOpenAIResponsesReasoningOutputItem {
130
+ type: 'reasoning';
131
+ summary?: Array<{ text?: string }>;
132
+ encrypted_content?: string;
133
+ }
134
+
135
+ export interface IOpenAIResponsesGenericOutputItem {
136
+ type: string;
137
+ id?: string;
138
+ status?: string;
139
+ }
140
+
141
+ export type TOpenAIResponsesOutputItem =
142
+ | IOpenAIResponsesMessageOutputItem
143
+ | IOpenAIResponsesFunctionCallOutputItem
144
+ | IOpenAIResponsesReasoningOutputItem
145
+ | IOpenAIResponsesGenericOutputItem;
146
+
147
+ export interface IOpenAIResponsesUsage {
148
+ input_tokens?: number;
149
+ output_tokens?: number;
150
+ total_tokens?: number;
151
+ }
152
+
153
+ export interface IOpenAIResponsesErrorBody {
154
+ message?: string;
155
+ }
156
+
157
+ export interface IOpenAIResponsesResponse {
158
+ id?: string;
159
+ model?: string;
160
+ output_text?: string;
161
+ output?: TOpenAIResponsesOutputItem[];
162
+ usage?: IOpenAIResponsesUsage;
163
+ status?: string;
164
+ error?: IOpenAIResponsesErrorBody | null;
165
+ }
166
+
167
+ export interface IOpenAIResponsesTextDeltaEvent {
168
+ type: 'response.output_text.delta';
169
+ delta: string;
170
+ }
171
+
172
+ export interface IOpenAIResponsesCompletedEvent {
173
+ type: 'response.completed';
174
+ response: IOpenAIResponsesResponse;
175
+ }
176
+
177
+ export interface IOpenAIResponsesOutputItemDoneEvent {
178
+ type: 'response.output_item.done';
179
+ item: TOpenAIResponsesOutputItem;
180
+ }
181
+
182
+ export interface IOpenAIResponsesErrorEvent {
183
+ type: 'response.error' | 'response.failed' | 'response.incomplete';
184
+ message?: string;
185
+ error?: IOpenAIResponsesErrorBody;
186
+ response?: IOpenAIResponsesResponse;
187
+ }
188
+
189
+ export type TOpenAIResponsesStreamEvent =
190
+ | IOpenAIResponsesTextDeltaEvent
191
+ | IOpenAIResponsesCompletedEvent
192
+ | IOpenAIResponsesOutputItemDoneEvent
193
+ | IOpenAIResponsesErrorEvent;
@@ -0,0 +1,3 @@
1
+ import { assembleOpenAICompatibleStream } from '@robota-sdk/agent-provider-openai-compatible/shared';
2
+
3
+ export { assembleOpenAICompatibleStream as assembleOpenAIStream };
@@ -0,0 +1,113 @@
1
+ import type OpenAI from 'openai';
2
+
3
+ /**
4
+ * OpenAI API Request Parameters
5
+ * Replaces any types with specific OpenAI API structure
6
+ */
7
+ export interface IOpenAIChatRequestParams {
8
+ model: string;
9
+ messages: OpenAI.Chat.ChatCompletionMessageParam[];
10
+ temperature?: number | undefined;
11
+ max_tokens?: number | undefined;
12
+ tools?: OpenAI.Chat.ChatCompletionTool[] | undefined;
13
+ tool_choice?: 'auto' | 'none' | OpenAI.Chat.ChatCompletionNamedToolChoice | undefined;
14
+ stream?: boolean | undefined;
15
+ }
16
+
17
+ /**
18
+ * OpenAI API streaming request parameters
19
+ */
20
+ export interface IOpenAIStreamRequestParams extends Omit<IOpenAIChatRequestParams, 'stream'> {
21
+ stream: true;
22
+ }
23
+
24
+ /**
25
+ * OpenAI API tool call structure
26
+ */
27
+ export interface IOpenAIToolCall {
28
+ id: string;
29
+ type: 'function';
30
+ function: {
31
+ name: string;
32
+ arguments: string;
33
+ };
34
+ }
35
+
36
+ /**
37
+ * OpenAI API message structure with tool calls
38
+ */
39
+ export interface IOpenAIAssistantMessage {
40
+ role: 'assistant';
41
+ content: string | null;
42
+ tool_calls?: IOpenAIToolCall[];
43
+ }
44
+
45
+ /**
46
+ * OpenAI API tool message structure
47
+ */
48
+ export interface IOpenAIToolMessage {
49
+ role: 'tool';
50
+ content: string;
51
+ tool_call_id: string;
52
+ }
53
+
54
+ /**
55
+ * OpenAI streaming chunk delta structure
56
+ */
57
+ export interface IOpenAIStreamDelta {
58
+ role?: 'assistant';
59
+ content?: string | null;
60
+ tool_calls?: Array<{
61
+ index: number;
62
+ id?: string;
63
+ type?: 'function';
64
+ function?: {
65
+ name?: string;
66
+ arguments?: string;
67
+ };
68
+ }>;
69
+ }
70
+
71
+ /**
72
+ * OpenAI streaming chunk structure
73
+ */
74
+ export interface IOpenAIStreamChunk {
75
+ id: string;
76
+ object: 'chat.completion.chunk';
77
+ created: number;
78
+ model: string;
79
+ choices: Array<{
80
+ index: number;
81
+ delta: IOpenAIStreamDelta;
82
+ finish_reason?: string | null;
83
+ }>;
84
+ usage?: {
85
+ prompt_tokens: number;
86
+ completion_tokens: number;
87
+ total_tokens: number;
88
+ };
89
+ }
90
+
91
+ /**
92
+ * OpenAI error structure for type-safe error handling
93
+ */
94
+ export interface IOpenAIError {
95
+ message: string;
96
+ status?: number;
97
+ type?: string;
98
+ param?: string | null;
99
+ code?: string | null;
100
+ }
101
+
102
+ /**
103
+ * Payload logging data structure
104
+ */
105
+ export interface IOpenAILogData {
106
+ model: string;
107
+ messagesCount: number;
108
+ hasTools: boolean;
109
+ temperature?: number | undefined;
110
+ maxTokens?: number | undefined;
111
+ timestamp: string;
112
+ requestId?: string | undefined;
113
+ }