@robota-sdk/agent-provider 3.0.0-beta.64

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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/dist/browser/index.d.ts +1104 -0
  3. package/dist/browser/index.d.ts.map +1 -0
  4. package/dist/browser/index.js +7 -0
  5. package/dist/browser/index.js.map +1 -0
  6. package/dist/loggers/index.cjs +1 -0
  7. package/dist/loggers/index.d.ts +151 -0
  8. package/dist/loggers/index.d.ts.map +1 -0
  9. package/dist/loggers/index.js +2 -0
  10. package/dist/loggers/index.js.map +1 -0
  11. package/dist/node/anthropic/index.cjs +1 -0
  12. package/dist/node/anthropic/index.d.ts +158 -0
  13. package/dist/node/anthropic/index.d.ts.map +1 -0
  14. package/dist/node/anthropic/index.js +1 -0
  15. package/dist/node/anthropic--1vgLC-e.js +5 -0
  16. package/dist/node/anthropic--1vgLC-e.js.map +1 -0
  17. package/dist/node/anthropic-BFQ6DSCP.cjs +4 -0
  18. package/dist/node/bytedance/index.cjs +1 -0
  19. package/dist/node/bytedance/index.d.ts +74 -0
  20. package/dist/node/bytedance/index.d.ts.map +1 -0
  21. package/dist/node/bytedance/index.js +1 -0
  22. package/dist/node/bytedance-C_0sF_pJ.js +2 -0
  23. package/dist/node/bytedance-C_0sF_pJ.js.map +1 -0
  24. package/dist/node/bytedance-DVPxqEiC.cjs +1 -0
  25. package/dist/node/chunk-Bmb41Sf3.cjs +1 -0
  26. package/dist/node/deepseek/index.cjs +1 -0
  27. package/dist/node/deepseek/index.d.ts +2 -0
  28. package/dist/node/deepseek/index.js +1 -0
  29. package/dist/node/deepseek-_8Ixx7rA.js +2 -0
  30. package/dist/node/deepseek-_8Ixx7rA.js.map +1 -0
  31. package/dist/node/deepseek-oA2Y6bD0.cjs +1 -0
  32. package/dist/node/gemini/index.cjs +1 -0
  33. package/dist/node/gemini/index.d.ts +173 -0
  34. package/dist/node/gemini/index.d.ts.map +1 -0
  35. package/dist/node/gemini/index.js +1 -0
  36. package/dist/node/gemini-Bh2U87MY.js +4 -0
  37. package/dist/node/gemini-Bh2U87MY.js.map +1 -0
  38. package/dist/node/gemini-DSaNCxZj.cjs +3 -0
  39. package/dist/node/gemma/index.cjs +1 -0
  40. package/dist/node/gemma/index.d.ts +2 -0
  41. package/dist/node/gemma/index.js +1 -0
  42. package/dist/node/gemma-Dp_AfCUR.js +2 -0
  43. package/dist/node/gemma-Dp_AfCUR.js.map +1 -0
  44. package/dist/node/gemma-G-Pf_PnX.cjs +1 -0
  45. package/dist/node/google/index.cjs +1 -0
  46. package/dist/node/google/index.d.ts +14 -0
  47. package/dist/node/google/index.d.ts.map +1 -0
  48. package/dist/node/google/index.js +2 -0
  49. package/dist/node/google/index.js.map +1 -0
  50. package/dist/node/index-B6PnlDMd.d.ts +82 -0
  51. package/dist/node/index-B6PnlDMd.d.ts.map +1 -0
  52. package/dist/node/index-B7UvPJcI.d.ts +315 -0
  53. package/dist/node/index-B7UvPJcI.d.ts.map +1 -0
  54. package/dist/node/index-BLPOTNb5.d.ts +98 -0
  55. package/dist/node/index-BLPOTNb5.d.ts.map +1 -0
  56. package/dist/node/index-BqixM_XD.d.ts +231 -0
  57. package/dist/node/index-BqixM_XD.d.ts.map +1 -0
  58. package/dist/node/index-C3beaqKO.d.ts +231 -0
  59. package/dist/node/index-C3beaqKO.d.ts.map +1 -0
  60. package/dist/node/index-Cp2XRh9G.d.ts +82 -0
  61. package/dist/node/index-Cp2XRh9G.d.ts.map +1 -0
  62. package/dist/node/index-DSv5xruI.d.ts +98 -0
  63. package/dist/node/index-DSv5xruI.d.ts.map +1 -0
  64. package/dist/node/index-w0bV1uaP.d.ts +315 -0
  65. package/dist/node/index-w0bV1uaP.d.ts.map +1 -0
  66. package/dist/node/index.cjs +1 -0
  67. package/dist/node/index.d.ts +8 -0
  68. package/dist/node/index.js +1 -0
  69. package/dist/node/openai/index.cjs +1 -0
  70. package/dist/node/openai/index.d.ts +2 -0
  71. package/dist/node/openai/index.js +1 -0
  72. package/dist/node/openai-CRQjg4xF.js +2 -0
  73. package/dist/node/openai-CRQjg4xF.js.map +1 -0
  74. package/dist/node/openai-compatible-BYfyY5lb.cjs +1 -0
  75. package/dist/node/openai-compatible-Dm4Sof9e.js +2 -0
  76. package/dist/node/openai-compatible-Dm4Sof9e.js.map +1 -0
  77. package/dist/node/openai-xWC6pY7r.cjs +1 -0
  78. package/dist/node/qwen/index.cjs +1 -0
  79. package/dist/node/qwen/index.d.ts +2 -0
  80. package/dist/node/qwen/index.js +1 -0
  81. package/dist/node/qwen-ChUZobTL.js +2 -0
  82. package/dist/node/qwen-ChUZobTL.js.map +1 -0
  83. package/dist/node/qwen-CjT71vSM.cjs +1 -0
  84. package/package.json +157 -0
  85. package/src/anthropic/__tests__/abort-streaming.test.ts +199 -0
  86. package/src/anthropic/__tests__/model-catalog-refresh.test.ts +92 -0
  87. package/src/anthropic/__tests__/provider-definition.test.ts +55 -0
  88. package/src/anthropic/__tests__/provider.test.ts +1357 -0
  89. package/src/anthropic/__tests__/response-parser.test.ts +326 -0
  90. package/src/anthropic/index.ts +22 -0
  91. package/src/anthropic/message-converter.ts +181 -0
  92. package/src/anthropic/model-catalog-refresh.ts +128 -0
  93. package/src/anthropic/parsers/response-parser.ts +184 -0
  94. package/src/anthropic/provider-definition.ts +93 -0
  95. package/src/anthropic/provider.ts +290 -0
  96. package/src/anthropic/streaming-handler.ts +204 -0
  97. package/src/anthropic/types/api-types.ts +158 -0
  98. package/src/anthropic/types.ts +79 -0
  99. package/src/bytedance/http-client.test.ts +288 -0
  100. package/src/bytedance/http-client.ts +163 -0
  101. package/src/bytedance/index.ts +2 -0
  102. package/src/bytedance/provider.spec.ts +320 -0
  103. package/src/bytedance/provider.ts +171 -0
  104. package/src/bytedance/status-mapper.test.ts +299 -0
  105. package/src/bytedance/status-mapper.ts +141 -0
  106. package/src/bytedance/types.ts +68 -0
  107. package/src/deepseek/defaults.ts +4 -0
  108. package/src/deepseek/index.ts +22 -0
  109. package/src/deepseek/model-catalog-refresh.test.ts +57 -0
  110. package/src/deepseek/model-catalog-refresh.ts +105 -0
  111. package/src/deepseek/model-catalog.ts +55 -0
  112. package/src/deepseek/provider-definition.test.ts +109 -0
  113. package/src/deepseek/provider-definition.ts +132 -0
  114. package/src/deepseek/provider.test.ts +324 -0
  115. package/src/deepseek/provider.ts +298 -0
  116. package/src/deepseek/types.ts +37 -0
  117. package/src/gemini/execution-helpers.ts +233 -0
  118. package/src/gemini/genai-transport.test.ts +208 -0
  119. package/src/gemini/image-operations.test.ts +448 -0
  120. package/src/gemini/image-operations.ts +261 -0
  121. package/src/gemini/index.ts +11 -0
  122. package/src/gemini/message-converter.test.ts +616 -0
  123. package/src/gemini/message-converter.ts +140 -0
  124. package/src/gemini/model-catalog-refresh.test.ts +107 -0
  125. package/src/gemini/model-catalog-refresh.ts +92 -0
  126. package/src/gemini/provider-definition.test.ts +70 -0
  127. package/src/gemini/provider-definition.ts +78 -0
  128. package/src/gemini/provider-extended.test.ts +898 -0
  129. package/src/gemini/provider.spec.ts +216 -0
  130. package/src/gemini/provider.ts +279 -0
  131. package/src/gemini/request-converter.ts +226 -0
  132. package/src/gemini/tool-schema-converter.ts +78 -0
  133. package/src/gemini/types/api-types.ts +235 -0
  134. package/src/gemini/types.ts +121 -0
  135. package/src/gemma/index.ts +5 -0
  136. package/src/gemma/message-factory.ts +38 -0
  137. package/src/gemma/provider-definition.test.ts +43 -0
  138. package/src/gemma/provider-definition.ts +84 -0
  139. package/src/gemma/provider-projection.ts +49 -0
  140. package/src/gemma/provider.test.ts +628 -0
  141. package/src/gemma/provider.ts +308 -0
  142. package/src/gemma/pseudo-command-envelope.ts +58 -0
  143. package/src/gemma/pseudo-tool-call-projector.ts +243 -0
  144. package/src/gemma/pseudo-tool-call-tag-parser.ts +153 -0
  145. package/src/gemma/pseudo-tool-call-types.ts +31 -0
  146. package/src/gemma/reasoning-projector.test.ts +52 -0
  147. package/src/gemma/reasoning-projector.ts +144 -0
  148. package/src/gemma/streaming-projection.ts +79 -0
  149. package/src/gemma/tool-call-argument-parser.ts +126 -0
  150. package/src/gemma/tool-call-projector.test.ts +227 -0
  151. package/src/gemma/tool-call-projector.ts +264 -0
  152. package/src/gemma/types.ts +27 -0
  153. package/src/google/index.ts +11 -0
  154. package/src/google/provider-compat.test.ts +19 -0
  155. package/src/google/provider-definition.ts +6 -0
  156. package/src/google/provider.ts +10 -0
  157. package/src/google/types.ts +5 -0
  158. package/src/index.ts +9 -0
  159. package/src/openai/adapter.test.ts +494 -0
  160. package/src/openai/adapter.ts +145 -0
  161. package/src/openai/chat-completions-chat.ts +189 -0
  162. package/src/openai/executor-integration.test.ts +206 -0
  163. package/src/openai/index.ts +21 -0
  164. package/src/openai/interfaces/payload-logger.ts +48 -0
  165. package/src/openai/loggers/console-payload-logger.test.ts +173 -0
  166. package/src/openai/loggers/console-payload-logger.ts +94 -0
  167. package/src/openai/loggers/console.ts +9 -0
  168. package/src/openai/loggers/file-payload-logger.test.ts +238 -0
  169. package/src/openai/loggers/file-payload-logger.ts +112 -0
  170. package/src/openai/loggers/file.ts +9 -0
  171. package/src/openai/loggers/index.ts +12 -0
  172. package/src/openai/loggers/sanitize-openai-log-data.test.ts +89 -0
  173. package/src/openai/loggers/sanitize-openai-log-data.ts +14 -0
  174. package/src/openai/message-converter.ts +22 -0
  175. package/src/openai/model-catalog-refresh.test.ts +92 -0
  176. package/src/openai/model-catalog-refresh.ts +115 -0
  177. package/src/openai/openai-request-format.ts +92 -0
  178. package/src/openai/parsers/response-parser.test.ts +407 -0
  179. package/src/openai/parsers/response-parser.ts +47 -0
  180. package/src/openai/provider-definition.test.ts +75 -0
  181. package/src/openai/provider-definition.ts +132 -0
  182. package/src/openai/provider.test.ts +1402 -0
  183. package/src/openai/provider.ts +237 -0
  184. package/src/openai/responses-chat.ts +258 -0
  185. package/src/openai/responses-converter.ts +112 -0
  186. package/src/openai/responses-parser.ts +285 -0
  187. package/src/openai/responses-stream-utils.ts +45 -0
  188. package/src/openai/responses-types.ts +195 -0
  189. package/src/openai/streaming/stream-assembler.ts +3 -0
  190. package/src/openai/streaming/stream-handler.test.ts +367 -0
  191. package/src/openai/streaming/stream-handler.ts +119 -0
  192. package/src/openai/types/api-types.ts +112 -0
  193. package/src/openai/types.ts +194 -0
  194. package/src/qwen/defaults.ts +26 -0
  195. package/src/qwen/index.ts +5 -0
  196. package/src/qwen/model-catalog-refresh.test.ts +91 -0
  197. package/src/qwen/model-catalog-refresh.ts +97 -0
  198. package/src/qwen/provider-capabilities.ts +34 -0
  199. package/src/qwen/provider-definition.test.ts +139 -0
  200. package/src/qwen/provider-definition.ts +173 -0
  201. package/src/qwen/provider-streaming-assembly.ts +40 -0
  202. package/src/qwen/provider.test.ts +640 -0
  203. package/src/qwen/provider.ts +293 -0
  204. package/src/qwen/responses-chat.ts +194 -0
  205. package/src/qwen/responses-converter.ts +104 -0
  206. package/src/qwen/responses-parser.ts +299 -0
  207. package/src/qwen/responses-stream-utils.ts +38 -0
  208. package/src/qwen/types.ts +228 -0
  209. package/src/shared/openai-compatible/endpoint-probe.test.ts +52 -0
  210. package/src/shared/openai-compatible/endpoint-probe.ts +43 -0
  211. package/src/shared/openai-compatible/index.ts +6 -0
  212. package/src/shared/openai-compatible/message-converter.test.ts +111 -0
  213. package/src/shared/openai-compatible/message-converter.ts +84 -0
  214. package/src/shared/openai-compatible/native-payload-observer.test.ts +43 -0
  215. package/src/shared/openai-compatible/native-payload-observer.ts +26 -0
  216. package/src/shared/openai-compatible/response-parser.test.ts +172 -0
  217. package/src/shared/openai-compatible/response-parser.ts +180 -0
  218. package/src/shared/openai-compatible/stream-assembler.test.ts +266 -0
  219. package/src/shared/openai-compatible/stream-assembler.ts +248 -0
  220. package/src/shared/openai-compatible/types.ts +59 -0
@@ -0,0 +1,285 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import type { IToolCall, TTextDeltaCallback, TUniversalMessage } from '@robota-sdk/agent-core';
3
+ import type {
4
+ IOpenAIResponsesErrorEvent,
5
+ IOpenAIResponsesFunctionCallOutputItem,
6
+ IOpenAIResponsesMessageOutputItem,
7
+ IOpenAIResponsesReasoningOutputItem,
8
+ IOpenAIResponsesResponse,
9
+ IOpenAIResponsesUsage,
10
+ TOpenAIResponsesOutputContent,
11
+ TOpenAIResponsesOutputItem,
12
+ TOpenAIResponsesStreamEvent,
13
+ } from './responses-types';
14
+ import { streamWithAbort } from './responses-stream-utils';
15
+
16
+ interface IOpenAIResponsesStreamAssemblyOptions {
17
+ stream: AsyncIterable<TOpenAIResponsesStreamEvent>;
18
+ onTextDelta?: TTextDeltaCallback;
19
+ signal?: AbortSignal;
20
+ }
21
+
22
+ interface IOpenAIResponsesReasoningMetadata {
23
+ reasoningSummaryCount: number;
24
+ reasoningSummaries: string[];
25
+ hasEncryptedReasoning: boolean;
26
+ }
27
+
28
+ interface IOpenAIResponseUsage {
29
+ promptTokens: number;
30
+ completionTokens: number;
31
+ totalTokens: number;
32
+ }
33
+
34
+ interface IOpenAIResponsesStreamState {
35
+ textParts: string[];
36
+ toolCalls: IToolCall[];
37
+ completedResponse?: IOpenAIResponsesResponse;
38
+ reasoning: IOpenAIResponsesReasoningMetadata;
39
+ }
40
+
41
+ export function parseOpenAIResponsesResponse(
42
+ response: IOpenAIResponsesResponse,
43
+ ): TUniversalMessage {
44
+ assertUsableResponse(response);
45
+ const output = response.output ?? [];
46
+ const content = response.output_text ?? extractMessageText(output);
47
+ return buildAssistantMessage({
48
+ content,
49
+ toolCalls: extractFunctionToolCalls(output),
50
+ response,
51
+ reasoning: collectReasoningMetadata(output),
52
+ });
53
+ }
54
+
55
+ export async function assembleOpenAIResponsesStream(
56
+ options: IOpenAIResponsesStreamAssemblyOptions,
57
+ ): Promise<TUniversalMessage> {
58
+ const state: IOpenAIResponsesStreamState = {
59
+ textParts: [],
60
+ toolCalls: [],
61
+ reasoning: createEmptyReasoningMetadata(),
62
+ };
63
+
64
+ for await (const event of streamWithAbort(options.stream, options.signal)) {
65
+ applyStreamEvent(state, event, options.onTextDelta);
66
+ }
67
+
68
+ if (state.completedResponse !== undefined) {
69
+ return buildMessageFromCompletedResponse(state);
70
+ }
71
+
72
+ return buildAssistantMessage({
73
+ content: state.textParts.join(''),
74
+ toolCalls: state.toolCalls,
75
+ reasoning: state.reasoning,
76
+ });
77
+ }
78
+
79
+ function applyStreamEvent(
80
+ state: IOpenAIResponsesStreamState,
81
+ event: TOpenAIResponsesStreamEvent,
82
+ onTextDelta: TTextDeltaCallback | undefined,
83
+ ): void {
84
+ if (event.type === 'response.output_text.delta') {
85
+ state.textParts.push(event.delta);
86
+ onTextDelta?.(event.delta);
87
+ return;
88
+ }
89
+
90
+ if (event.type === 'response.completed') {
91
+ state.completedResponse = event.response;
92
+ mergeReasoningMetadata(state.reasoning, collectReasoningMetadata(event.response.output ?? []));
93
+ return;
94
+ }
95
+
96
+ if (event.type === 'response.output_item.done') {
97
+ applyOutputItem(state, event.item);
98
+ return;
99
+ }
100
+
101
+ if (
102
+ event.type === 'response.error' ||
103
+ event.type === 'response.failed' ||
104
+ event.type === 'response.incomplete'
105
+ ) {
106
+ throw new Error(`OpenAI Responses API failed: ${extractErrorMessage(event)}`);
107
+ }
108
+ }
109
+
110
+ function applyOutputItem(
111
+ state: IOpenAIResponsesStreamState,
112
+ item: TOpenAIResponsesOutputItem,
113
+ ): void {
114
+ if (isFunctionCallOutputItem(item)) {
115
+ state.toolCalls.push(convertFunctionCall(item));
116
+ return;
117
+ }
118
+ if (isReasoningOutputItem(item)) {
119
+ mergeReasoningMetadata(state.reasoning, collectReasoningMetadata([item]));
120
+ }
121
+ }
122
+
123
+ function buildMessageFromCompletedResponse(state: IOpenAIResponsesStreamState): TUniversalMessage {
124
+ const response = state.completedResponse;
125
+ if (response === undefined) {
126
+ throw new Error('OpenAI Responses stream completed without response metadata');
127
+ }
128
+
129
+ assertUsableResponse(response);
130
+ const output = response.output ?? [];
131
+ const responseToolCalls = extractFunctionToolCalls(output);
132
+ const content =
133
+ state.textParts.length > 0
134
+ ? state.textParts.join('')
135
+ : (response.output_text ?? extractMessageText(output));
136
+ const reasoning = collectReasoningMetadata(output);
137
+ mergeReasoningMetadata(reasoning, state.reasoning);
138
+
139
+ return buildAssistantMessage({
140
+ content,
141
+ toolCalls: responseToolCalls.length > 0 ? responseToolCalls : state.toolCalls,
142
+ response,
143
+ reasoning,
144
+ });
145
+ }
146
+
147
+ function buildAssistantMessage(input: {
148
+ content: string;
149
+ toolCalls: IToolCall[];
150
+ response?: IOpenAIResponsesResponse;
151
+ reasoning: IOpenAIResponsesReasoningMetadata;
152
+ }): TUniversalMessage {
153
+ return {
154
+ id: randomUUID(),
155
+ role: 'assistant',
156
+ content: input.content,
157
+ state: 'complete',
158
+ timestamp: new Date(),
159
+ ...(input.toolCalls.length > 0 && { toolCalls: input.toolCalls }),
160
+ ...(input.response?.usage !== undefined && { usage: mapUsage(input.response.usage) }),
161
+ metadata: buildMetadata(input.response, input.reasoning),
162
+ };
163
+ }
164
+
165
+ function buildMetadata(
166
+ response: IOpenAIResponsesResponse | undefined,
167
+ reasoning: IOpenAIResponsesReasoningMetadata,
168
+ ): NonNullable<TUniversalMessage['metadata']> {
169
+ return {
170
+ providerApiSurface: 'responses',
171
+ ...(response?.id !== undefined && { responseId: response.id }),
172
+ ...(response?.model !== undefined && { model: response.model }),
173
+ ...(response?.status !== undefined && { finishReason: response.status }),
174
+ ...(reasoning.reasoningSummaryCount > 0 && {
175
+ reasoningSummaryCount: reasoning.reasoningSummaryCount,
176
+ reasoningSummaries: reasoning.reasoningSummaries,
177
+ }),
178
+ ...(reasoning.hasEncryptedReasoning && { hasEncryptedReasoning: true }),
179
+ };
180
+ }
181
+
182
+ function mapUsage(usage: IOpenAIResponsesUsage): IOpenAIResponseUsage {
183
+ return {
184
+ promptTokens: usage.input_tokens ?? 0,
185
+ completionTokens: usage.output_tokens ?? 0,
186
+ totalTokens: usage.total_tokens ?? 0,
187
+ };
188
+ }
189
+
190
+ function extractFunctionToolCalls(output: readonly TOpenAIResponsesOutputItem[]): IToolCall[] {
191
+ return output.filter(isFunctionCallOutputItem).map((item) => convertFunctionCall(item));
192
+ }
193
+
194
+ function isFunctionCallOutputItem(
195
+ item: TOpenAIResponsesOutputItem,
196
+ ): item is IOpenAIResponsesFunctionCallOutputItem {
197
+ return (
198
+ item.type === 'function_call' && 'call_id' in item && 'name' in item && 'arguments' in item
199
+ );
200
+ }
201
+
202
+ function convertFunctionCall(item: IOpenAIResponsesFunctionCallOutputItem): IToolCall {
203
+ return {
204
+ id: item.call_id,
205
+ type: 'function',
206
+ function: {
207
+ name: item.name,
208
+ arguments: item.arguments,
209
+ },
210
+ };
211
+ }
212
+
213
+ function extractMessageText(output: readonly TOpenAIResponsesOutputItem[]): string {
214
+ return output
215
+ .filter(isMessageOutputItem)
216
+ .flatMap((item) => item.content)
217
+ .map(extractTextContent)
218
+ .join('');
219
+ }
220
+
221
+ function extractTextContent(content: TOpenAIResponsesOutputContent): string {
222
+ if (content.type === 'refusal') {
223
+ return content.refusal;
224
+ }
225
+ return content.text;
226
+ }
227
+
228
+ function isMessageOutputItem(
229
+ item: TOpenAIResponsesOutputItem,
230
+ ): item is IOpenAIResponsesMessageOutputItem {
231
+ return item.type === 'message' && 'content' in item && Array.isArray(item.content);
232
+ }
233
+
234
+ function collectReasoningMetadata(
235
+ output: readonly TOpenAIResponsesOutputItem[],
236
+ ): IOpenAIResponsesReasoningMetadata {
237
+ const metadata = createEmptyReasoningMetadata();
238
+ for (const item of output) {
239
+ if (!isReasoningOutputItem(item)) {
240
+ continue;
241
+ }
242
+ const summaries = item.summary?.map((summary) => summary.text).filter(isString) ?? [];
243
+ metadata.reasoningSummaryCount += summaries.length;
244
+ metadata.reasoningSummaries.push(...summaries);
245
+ metadata.hasEncryptedReasoning = metadata.hasEncryptedReasoning || !!item.encrypted_content;
246
+ }
247
+ return metadata;
248
+ }
249
+
250
+ function isReasoningOutputItem(
251
+ item: TOpenAIResponsesOutputItem,
252
+ ): item is IOpenAIResponsesReasoningOutputItem {
253
+ return item.type === 'reasoning';
254
+ }
255
+
256
+ function createEmptyReasoningMetadata(): IOpenAIResponsesReasoningMetadata {
257
+ return {
258
+ reasoningSummaryCount: 0,
259
+ reasoningSummaries: [],
260
+ hasEncryptedReasoning: false,
261
+ };
262
+ }
263
+
264
+ function mergeReasoningMetadata(
265
+ target: IOpenAIResponsesReasoningMetadata,
266
+ source: IOpenAIResponsesReasoningMetadata,
267
+ ): void {
268
+ target.reasoningSummaryCount += source.reasoningSummaryCount;
269
+ target.reasoningSummaries.push(...source.reasoningSummaries);
270
+ target.hasEncryptedReasoning = target.hasEncryptedReasoning || source.hasEncryptedReasoning;
271
+ }
272
+
273
+ function isString(value: string | undefined): value is string {
274
+ return value !== undefined;
275
+ }
276
+
277
+ function assertUsableResponse(response: IOpenAIResponsesResponse): void {
278
+ if (response.status === 'failed' || response.status === 'incomplete') {
279
+ throw new Error(`OpenAI Responses API failed: ${response.error?.message ?? response.status}`);
280
+ }
281
+ }
282
+
283
+ function extractErrorMessage(event: IOpenAIResponsesErrorEvent): string {
284
+ return event.message ?? event.error?.message ?? event.response?.error?.message ?? 'unknown error';
285
+ }
@@ -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,195 @@
1
+ import type { IToolSchema } from '@robota-sdk/agent-core';
2
+ import type {
3
+ IOpenAIJsonSchemaDefinition,
4
+ IOpenAIResponsesReasoningOptions,
5
+ TOpenAIProviderOptionValue,
6
+ } from './types';
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
23
+ | IOpenAIResponsesInputImageContent;
24
+
25
+ export interface IOpenAIResponsesMessageInput {
26
+ type?: 'message';
27
+ role: TOpenAIResponsesInputRole;
28
+ content: string | TOpenAIResponsesInputContent[];
29
+ }
30
+
31
+ export interface IOpenAIResponsesFunctionCallInput {
32
+ type: 'function_call';
33
+ call_id: string;
34
+ name: string;
35
+ arguments: string;
36
+ }
37
+
38
+ export interface IOpenAIResponsesFunctionCallOutputInput {
39
+ type: 'function_call_output';
40
+ call_id: string;
41
+ output: string;
42
+ }
43
+
44
+ export type TOpenAIResponsesInputItem =
45
+ | IOpenAIResponsesMessageInput
46
+ | IOpenAIResponsesFunctionCallInput
47
+ | IOpenAIResponsesFunctionCallOutputInput;
48
+
49
+ export interface IOpenAIResponsesFunctionTool {
50
+ type: 'function';
51
+ name: string;
52
+ parameters: IToolSchema['parameters'];
53
+ strict: boolean | null;
54
+ description?: string;
55
+ }
56
+
57
+ export type TOpenAIResponsesTool = IOpenAIResponsesFunctionTool;
58
+
59
+ export interface IOpenAIResponsesTextFormatText {
60
+ type: 'text';
61
+ }
62
+
63
+ export interface IOpenAIResponsesTextFormatJsonObject {
64
+ type: 'json_object';
65
+ }
66
+
67
+ export interface IOpenAIResponsesTextFormatJsonSchema extends IOpenAIJsonSchemaDefinition {
68
+ type: 'json_schema';
69
+ schema: Record<string, TOpenAIProviderOptionValue>;
70
+ }
71
+
72
+ export type TOpenAIResponsesTextFormat =
73
+ | IOpenAIResponsesTextFormatText
74
+ | IOpenAIResponsesTextFormatJsonObject
75
+ | IOpenAIResponsesTextFormatJsonSchema;
76
+
77
+ export interface IOpenAIResponsesTextConfig {
78
+ format: TOpenAIResponsesTextFormat;
79
+ }
80
+
81
+ export interface IOpenAIResponsesRequestBase {
82
+ model: string;
83
+ input: TOpenAIResponsesInputItem[];
84
+ tools?: TOpenAIResponsesTool[];
85
+ tool_choice?: 'auto' | 'none' | 'required';
86
+ text?: IOpenAIResponsesTextConfig;
87
+ temperature?: number;
88
+ max_output_tokens?: number;
89
+ reasoning?: IOpenAIResponsesReasoningOptions;
90
+ include?: 'reasoning.encrypted_content'[];
91
+ store?: boolean;
92
+ }
93
+
94
+ export interface IOpenAIResponsesRequestNonStreaming extends IOpenAIResponsesRequestBase {
95
+ stream?: false;
96
+ }
97
+
98
+ export interface IOpenAIResponsesRequestStreaming extends IOpenAIResponsesRequestBase {
99
+ stream: true;
100
+ }
101
+
102
+ export interface IOpenAIResponsesTextOutputContent {
103
+ type: 'output_text' | 'text';
104
+ text: string;
105
+ }
106
+
107
+ export interface IOpenAIResponsesRefusalOutputContent {
108
+ type: 'refusal';
109
+ refusal: string;
110
+ }
111
+
112
+ export type TOpenAIResponsesOutputContent =
113
+ | IOpenAIResponsesTextOutputContent
114
+ | IOpenAIResponsesRefusalOutputContent;
115
+
116
+ export interface IOpenAIResponsesMessageOutputItem {
117
+ type: 'message';
118
+ role?: 'assistant';
119
+ content: TOpenAIResponsesOutputContent[];
120
+ }
121
+
122
+ export interface IOpenAIResponsesFunctionCallOutputItem {
123
+ type: 'function_call';
124
+ call_id: string;
125
+ name: string;
126
+ arguments: string;
127
+ id?: string;
128
+ status?: string;
129
+ }
130
+
131
+ export interface IOpenAIResponsesReasoningOutputItem {
132
+ type: 'reasoning';
133
+ summary?: Array<{ text?: string }>;
134
+ encrypted_content?: string;
135
+ }
136
+
137
+ export interface IOpenAIResponsesGenericOutputItem {
138
+ type: string;
139
+ id?: string;
140
+ status?: string;
141
+ }
142
+
143
+ export type TOpenAIResponsesOutputItem =
144
+ | IOpenAIResponsesMessageOutputItem
145
+ | IOpenAIResponsesFunctionCallOutputItem
146
+ | IOpenAIResponsesReasoningOutputItem
147
+ | IOpenAIResponsesGenericOutputItem;
148
+
149
+ export interface IOpenAIResponsesUsage {
150
+ input_tokens?: number;
151
+ output_tokens?: number;
152
+ total_tokens?: number;
153
+ }
154
+
155
+ export interface IOpenAIResponsesErrorBody {
156
+ message?: string;
157
+ }
158
+
159
+ export interface IOpenAIResponsesResponse {
160
+ id?: string;
161
+ model?: string;
162
+ output_text?: string;
163
+ output?: TOpenAIResponsesOutputItem[];
164
+ usage?: IOpenAIResponsesUsage;
165
+ status?: string;
166
+ error?: IOpenAIResponsesErrorBody | null;
167
+ }
168
+
169
+ export interface IOpenAIResponsesTextDeltaEvent {
170
+ type: 'response.output_text.delta';
171
+ delta: string;
172
+ }
173
+
174
+ export interface IOpenAIResponsesCompletedEvent {
175
+ type: 'response.completed';
176
+ response: IOpenAIResponsesResponse;
177
+ }
178
+
179
+ export interface IOpenAIResponsesOutputItemDoneEvent {
180
+ type: 'response.output_item.done';
181
+ item: TOpenAIResponsesOutputItem;
182
+ }
183
+
184
+ export interface IOpenAIResponsesErrorEvent {
185
+ type: 'response.error' | 'response.failed' | 'response.incomplete';
186
+ message?: string;
187
+ error?: IOpenAIResponsesErrorBody;
188
+ response?: IOpenAIResponsesResponse;
189
+ }
190
+
191
+ export type TOpenAIResponsesStreamEvent =
192
+ | IOpenAIResponsesTextDeltaEvent
193
+ | IOpenAIResponsesCompletedEvent
194
+ | IOpenAIResponsesOutputItemDoneEvent
195
+ | IOpenAIResponsesErrorEvent;
@@ -0,0 +1,3 @@
1
+ import { assembleOpenAICompatibleStream } from '../../shared/openai-compatible/index.js';
2
+
3
+ export { assembleOpenAICompatibleStream as assembleOpenAIStream };