@zyraxon-ai/llm 19.0.5

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 (218) hide show
  1. package/README.md +131 -0
  2. package/dist/cache-policy.d.ts +3 -0
  3. package/dist/cache-policy.d.ts.map +1 -0
  4. package/dist/cache-policy.js +109 -0
  5. package/dist/cache-policy.js.map +1 -0
  6. package/dist/index.d.ts +13 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +9 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/llm.d.ts +205 -0
  11. package/dist/llm.d.ts.map +1 -0
  12. package/dist/llm.js +82 -0
  13. package/dist/llm.js.map +1 -0
  14. package/dist/protocols/anthropic-messages.d.ts +340 -0
  15. package/dist/protocols/anthropic-messages.d.ts.map +1 -0
  16. package/dist/protocols/anthropic-messages.js +719 -0
  17. package/dist/protocols/anthropic-messages.js.map +1 -0
  18. package/dist/protocols/bedrock-converse.d.ts +472 -0
  19. package/dist/protocols/bedrock-converse.d.ts.map +1 -0
  20. package/dist/protocols/bedrock-converse.js +529 -0
  21. package/dist/protocols/bedrock-converse.js.map +1 -0
  22. package/dist/protocols/bedrock-event-stream.d.ts +10 -0
  23. package/dist/protocols/bedrock-event-stream.d.ts.map +1 -0
  24. package/dist/protocols/bedrock-event-stream.js +64 -0
  25. package/dist/protocols/bedrock-event-stream.js.map +1 -0
  26. package/dist/protocols/gemini.d.ts +165 -0
  27. package/dist/protocols/gemini.d.ts.map +1 -0
  28. package/dist/protocols/gemini.js +420 -0
  29. package/dist/protocols/gemini.js.map +1 -0
  30. package/dist/protocols/index.d.ts +7 -0
  31. package/dist/protocols/index.d.ts.map +1 -0
  32. package/dist/protocols/index.js +7 -0
  33. package/dist/protocols/index.js.map +1 -0
  34. package/dist/protocols/openai-chat.d.ts +297 -0
  35. package/dist/protocols/openai-chat.d.ts.map +1 -0
  36. package/dist/protocols/openai-chat.js +426 -0
  37. package/dist/protocols/openai-chat.js.map +1 -0
  38. package/dist/protocols/openai-compatible-chat.d.ts +12 -0
  39. package/dist/protocols/openai-compatible-chat.d.ts.map +1 -0
  40. package/dist/protocols/openai-compatible-chat.js +20 -0
  41. package/dist/protocols/openai-compatible-chat.js.map +1 -0
  42. package/dist/protocols/openai-responses.d.ts +615 -0
  43. package/dist/protocols/openai-responses.d.ts.map +1 -0
  44. package/dist/protocols/openai-responses.js +828 -0
  45. package/dist/protocols/openai-responses.js.map +1 -0
  46. package/dist/protocols/shared.d.ts +193 -0
  47. package/dist/protocols/shared.d.ts.map +1 -0
  48. package/dist/protocols/shared.js +237 -0
  49. package/dist/protocols/shared.js.map +1 -0
  50. package/dist/protocols/utils/bedrock-auth.d.ts +19 -0
  51. package/dist/protocols/utils/bedrock-auth.d.ts.map +1 -0
  52. package/dist/protocols/utils/bedrock-auth.js +42 -0
  53. package/dist/protocols/utils/bedrock-auth.js.map +1 -0
  54. package/dist/protocols/utils/bedrock-cache.d.ts +16 -0
  55. package/dist/protocols/utils/bedrock-cache.d.ts.map +1 -0
  56. package/dist/protocols/utils/bedrock-cache.js +30 -0
  57. package/dist/protocols/utils/bedrock-cache.js.map +1 -0
  58. package/dist/protocols/utils/bedrock-media.d.ts +50 -0
  59. package/dist/protocols/utils/bedrock-media.d.ts.map +1 -0
  60. package/dist/protocols/utils/bedrock-media.js +69 -0
  61. package/dist/protocols/utils/bedrock-media.js.map +1 -0
  62. package/dist/protocols/utils/cache.d.ts +7 -0
  63. package/dist/protocols/utils/cache.d.ts.map +1 -0
  64. package/dist/protocols/utils/cache.js +9 -0
  65. package/dist/protocols/utils/cache.js.map +1 -0
  66. package/dist/protocols/utils/gemini-tool-schema.d.ts +3 -0
  67. package/dist/protocols/utils/gemini-tool-schema.d.ts.map +1 -0
  68. package/dist/protocols/utils/gemini-tool-schema.js +84 -0
  69. package/dist/protocols/utils/gemini-tool-schema.js.map +1 -0
  70. package/dist/protocols/utils/lifecycle.d.ts +20 -0
  71. package/dist/protocols/utils/lifecycle.d.ts.map +1 -0
  72. package/dist/protocols/utils/lifecycle.js +66 -0
  73. package/dist/protocols/utils/lifecycle.js.map +1 -0
  74. package/dist/protocols/utils/openai-options.d.ts +23 -0
  75. package/dist/protocols/utils/openai-options.d.ts.map +1 -0
  76. package/dist/protocols/utils/openai-options.js +68 -0
  77. package/dist/protocols/utils/openai-options.js.map +1 -0
  78. package/dist/protocols/utils/tool-schema.d.ts +8 -0
  79. package/dist/protocols/utils/tool-schema.d.ts.map +1 -0
  80. package/dist/protocols/utils/tool-schema.js +80 -0
  81. package/dist/protocols/utils/tool-schema.js.map +1 -0
  82. package/dist/protocols/utils/tool-stream.d.ts +156 -0
  83. package/dist/protocols/utils/tool-stream.d.ts.map +1 -0
  84. package/dist/protocols/utils/tool-stream.js +137 -0
  85. package/dist/protocols/utils/tool-stream.js.map +1 -0
  86. package/dist/provider-error.d.ts +3 -0
  87. package/dist/provider-error.d.ts.map +1 -0
  88. package/dist/provider-error.js +29 -0
  89. package/dist/provider-error.js.map +1 -0
  90. package/dist/provider.d.ts +24 -0
  91. package/dist/provider.d.ts.map +1 -0
  92. package/dist/provider.js +3 -0
  93. package/dist/provider.js.map +1 -0
  94. package/dist/providers/amazon-bedrock.d.ts +142 -0
  95. package/dist/providers/amazon-bedrock.d.ts.map +1 -0
  96. package/dist/providers/amazon-bedrock.js +27 -0
  97. package/dist/providers/amazon-bedrock.js.map +1 -0
  98. package/dist/providers/anthropic.d.ts +24 -0
  99. package/dist/providers/anthropic.d.ts.map +1 -0
  100. package/dist/providers/anthropic.js +27 -0
  101. package/dist/providers/anthropic.js.map +1 -0
  102. package/dist/providers/azure.d.ts +36 -0
  103. package/dist/providers/azure.d.ts.map +1 -0
  104. package/dist/providers/azure.js +70 -0
  105. package/dist/providers/azure.js.map +1 -0
  106. package/dist/providers/cloudflare.d.ts +47 -0
  107. package/dist/providers/cloudflare.d.ts.map +1 -0
  108. package/dist/providers/cloudflare.js +88 -0
  109. package/dist/providers/cloudflare.js.map +1 -0
  110. package/dist/providers/github-copilot.d.ts +30 -0
  111. package/dist/providers/github-copilot.d.ts.map +1 -0
  112. package/dist/providers/github-copilot.js +48 -0
  113. package/dist/providers/github-copilot.js.map +1 -0
  114. package/dist/providers/google.d.ts +24 -0
  115. package/dist/providers/google.d.ts.map +1 -0
  116. package/dist/providers/google.js +27 -0
  117. package/dist/providers/google.js.map +1 -0
  118. package/dist/providers/index.d.ts +12 -0
  119. package/dist/providers/index.d.ts.map +1 -0
  120. package/dist/providers/index.js +12 -0
  121. package/dist/providers/index.js.map +1 -0
  122. package/dist/providers/openai-compatible-profile.d.ts +44 -0
  123. package/dist/providers/openai-compatible-profile.d.ts.map +1 -0
  124. package/dist/providers/openai-compatible-profile.js +13 -0
  125. package/dist/providers/openai-compatible-profile.js.map +1 -0
  126. package/dist/providers/openai-compatible.d.ts +62 -0
  127. package/dist/providers/openai-compatible.d.ts.map +1 -0
  128. package/dist/providers/openai-compatible.js +48 -0
  129. package/dist/providers/openai-compatible.js.map +1 -0
  130. package/dist/providers/openai-options.d.ts +31 -0
  131. package/dist/providers/openai-options.d.ts.map +1 -0
  132. package/dist/providers/openai-options.js +43 -0
  133. package/dist/providers/openai-options.js.map +1 -0
  134. package/dist/providers/openai.d.ts +116 -0
  135. package/dist/providers/openai.d.ts.map +1 -0
  136. package/dist/providers/openai.js +39 -0
  137. package/dist/providers/openai.js.map +1 -0
  138. package/dist/providers/openrouter.d.ts +199 -0
  139. package/dist/providers/openrouter.d.ts.map +1 -0
  140. package/dist/providers/openrouter.js +66 -0
  141. package/dist/providers/openrouter.js.map +1 -0
  142. package/dist/providers/xai.d.ts +32 -0
  143. package/dist/providers/xai.d.ts.map +1 -0
  144. package/dist/providers/xai.js +44 -0
  145. package/dist/providers/xai.js.map +1 -0
  146. package/dist/route/auth-options.d.ts +35 -0
  147. package/dist/route/auth-options.d.ts.map +1 -0
  148. package/dist/route/auth-options.js +15 -0
  149. package/dist/route/auth-options.js.map +1 -0
  150. package/dist/route/auth.js +90 -0
  151. package/dist/route/auth.js.map +1 -0
  152. package/dist/route/client.d.ts +306 -0
  153. package/dist/route/client.d.ts.map +1 -0
  154. package/dist/route/client.js +197 -0
  155. package/dist/route/client.js.map +1 -0
  156. package/dist/route/endpoint.js +22 -0
  157. package/dist/route/endpoint.js.map +1 -0
  158. package/dist/route/executor.d.ts +13 -0
  159. package/dist/route/executor.d.ts.map +1 -0
  160. package/dist/route/executor.js +287 -0
  161. package/dist/route/executor.js.map +1 -0
  162. package/dist/route/framing.js +5 -0
  163. package/dist/route/framing.js.map +1 -0
  164. package/dist/route/index.d.ts +17 -0
  165. package/dist/route/index.d.ts.map +1 -0
  166. package/dist/route/index.js +10 -0
  167. package/dist/route/index.js.map +1 -0
  168. package/dist/route/protocol.d.ts +77 -0
  169. package/dist/route/protocol.d.ts.map +1 -0
  170. package/dist/route/protocol.js +18 -0
  171. package/dist/route/protocol.js.map +1 -0
  172. package/dist/route/transport/http.d.ts +34 -0
  173. package/dist/route/transport/http.d.ts.map +1 -0
  174. package/dist/route/transport/http.js +98 -0
  175. package/dist/route/transport/http.js.map +1 -0
  176. package/dist/route/transport/index.d.ts +28 -0
  177. package/dist/route/transport/index.d.ts.map +1 -0
  178. package/dist/route/transport/index.js +3 -0
  179. package/dist/route/transport/index.js.map +1 -0
  180. package/dist/route/transport/websocket.d.ts +57 -0
  181. package/dist/route/transport/websocket.d.ts.map +1 -0
  182. package/dist/route/transport/websocket.js +181 -0
  183. package/dist/route/transport/websocket.js.map +1 -0
  184. package/dist/schema/errors.d.ts +166 -0
  185. package/dist/schema/errors.d.ts.map +1 -0
  186. package/dist/schema/errors.js +187 -0
  187. package/dist/schema/errors.js.map +1 -0
  188. package/dist/schema/events.d.ts +3821 -0
  189. package/dist/schema/events.d.ts.map +1 -0
  190. package/dist/schema/events.js +484 -0
  191. package/dist/schema/events.js.map +1 -0
  192. package/dist/schema/ids.d.ts +31 -0
  193. package/dist/schema/ids.d.ts.map +1 -0
  194. package/dist/schema/ids.js +19 -0
  195. package/dist/schema/ids.js.map +1 -0
  196. package/dist/schema/index.d.ts +6 -0
  197. package/dist/schema/index.d.ts.map +1 -0
  198. package/dist/schema/index.js +6 -0
  199. package/dist/schema/index.js.map +1 -0
  200. package/dist/schema/messages.d.ts +294 -0
  201. package/dist/schema/messages.d.ts.map +1 -0
  202. package/dist/schema/messages.js +247 -0
  203. package/dist/schema/messages.js.map +1 -0
  204. package/dist/schema/options.d.ts +144 -0
  205. package/dist/schema/options.d.ts.map +1 -0
  206. package/dist/schema/options.js +196 -0
  207. package/dist/schema/options.js.map +1 -0
  208. package/dist/tool-runtime.d.ts +16 -0
  209. package/dist/tool-runtime.d.ts.map +1 -0
  210. package/dist/tool-runtime.js +35 -0
  211. package/dist/tool-runtime.js.map +1 -0
  212. package/dist/tool.js +67 -0
  213. package/dist/tool.js.map +1 -0
  214. package/dist/utils/record.d.ts +3 -0
  215. package/dist/utils/record.d.ts.map +1 -0
  216. package/dist/utils/record.js +3 -0
  217. package/dist/utils/record.js.map +1 -0
  218. package/package.json +37 -0
@@ -0,0 +1,828 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Route } from "../route/client";
3
+ import { Auth } from "../route/auth";
4
+ import { Endpoint } from "../route/endpoint";
5
+ import { HttpTransport, WebSocketTransport } from "../route/transport";
6
+ import { Protocol } from "../route/protocol";
7
+ import { LLMEvent, Usage, } from "../schema";
8
+ import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared";
9
+ import { isContextOverflow } from "../provider-error";
10
+ import { OpenAIOptions } from "./utils/openai-options";
11
+ import { Lifecycle } from "./utils/lifecycle";
12
+ import { ToolSchemaProjection } from "./utils/tool-schema";
13
+ import { ToolStream } from "./utils/tool-stream";
14
+ const ADAPTER = "openai-responses";
15
+ export const DEFAULT_BASE_URL = "https://api.openai.com/v1";
16
+ export const PATH = "/responses";
17
+ // =============================================================================
18
+ // Request Body Schema
19
+ // =============================================================================
20
+ const OpenAIResponsesInputText = Schema.Struct({
21
+ type: Schema.tag("input_text"),
22
+ text: Schema.String,
23
+ });
24
+ const OpenAIResponsesInputImage = Schema.Struct({
25
+ type: Schema.tag("input_image"),
26
+ image_url: Schema.String,
27
+ });
28
+ const OpenAIResponsesInputContent = Schema.Union([OpenAIResponsesInputText, OpenAIResponsesInputImage]);
29
+ const OpenAIResponsesOutputText = Schema.Struct({
30
+ type: Schema.tag("output_text"),
31
+ text: Schema.String,
32
+ });
33
+ const OpenAIResponsesReasoningSummaryText = Schema.Struct({
34
+ type: Schema.tag("summary_text"),
35
+ text: Schema.String,
36
+ });
37
+ const OpenAIResponsesReasoningItem = Schema.Struct({
38
+ type: Schema.tag("reasoning"),
39
+ id: Schema.optionalKey(Schema.String),
40
+ summary: Schema.Array(OpenAIResponsesReasoningSummaryText),
41
+ encrypted_content: optionalNull(Schema.String),
42
+ });
43
+ const OpenAIResponsesItemReference = Schema.Struct({
44
+ type: Schema.tag("item_reference"),
45
+ id: Schema.String,
46
+ });
47
+ // `function_call_output.output` accepts either a plain string or an ordered
48
+ // array of content items so tools can return images in addition to text.
49
+ // https://platform.openai.com/docs/api-reference/responses/object
50
+ const OpenAIResponsesFunctionCallOutputContent = Schema.Union([OpenAIResponsesInputText, OpenAIResponsesInputImage]);
51
+ const OpenAIResponsesFunctionCallOutput = Schema.Union([
52
+ Schema.String,
53
+ Schema.Array(OpenAIResponsesFunctionCallOutputContent),
54
+ ]);
55
+ const OpenAIResponsesInputItem = Schema.Union([
56
+ Schema.Struct({ role: Schema.tag("system"), content: Schema.String }),
57
+ Schema.Struct({ role: Schema.tag("user"), content: Schema.Array(OpenAIResponsesInputContent) }),
58
+ Schema.Struct({ role: Schema.tag("assistant"), content: Schema.Array(OpenAIResponsesOutputText) }),
59
+ OpenAIResponsesReasoningItem,
60
+ OpenAIResponsesItemReference,
61
+ Schema.Struct({
62
+ type: Schema.tag("function_call"),
63
+ call_id: Schema.String,
64
+ name: Schema.String,
65
+ arguments: Schema.String,
66
+ }),
67
+ Schema.Struct({
68
+ type: Schema.tag("function_call_output"),
69
+ call_id: Schema.String,
70
+ output: OpenAIResponsesFunctionCallOutput,
71
+ }),
72
+ ]);
73
+ const OpenAIResponsesTool = Schema.Struct({
74
+ type: Schema.tag("function"),
75
+ name: Schema.String,
76
+ description: Schema.String,
77
+ parameters: JsonObject,
78
+ strict: Schema.optional(Schema.Boolean),
79
+ });
80
+ const OpenAIResponsesToolChoice = Schema.Union([
81
+ Schema.Literals(["auto", "none", "required"]),
82
+ Schema.Struct({ type: Schema.tag("function"), name: Schema.String }),
83
+ ]);
84
+ // Fields shared between the HTTP body and the WebSocket `response.create`
85
+ // message. The HTTP body adds `stream: true`; the WebSocket message adds
86
+ // `type: "response.create"`. Defining the shared shape once keeps the two
87
+ // transports in sync without a destructure-and-strip dance.
88
+ const OpenAIResponsesCoreFields = {
89
+ model: Schema.String,
90
+ input: Schema.Array(OpenAIResponsesInputItem),
91
+ instructions: Schema.optional(Schema.String),
92
+ tools: optionalArray(OpenAIResponsesTool),
93
+ tool_choice: Schema.optional(OpenAIResponsesToolChoice),
94
+ store: Schema.optional(Schema.Boolean),
95
+ service_tier: Schema.optional(OpenAIOptions.OpenAIServiceTier),
96
+ prompt_cache_key: Schema.optional(Schema.String),
97
+ include: optionalArray(OpenAIOptions.OpenAIResponseIncludable),
98
+ reasoning: Schema.optional(Schema.Struct({
99
+ effort: Schema.optional(OpenAIOptions.OpenAIReasoningEffort),
100
+ summary: Schema.optional(Schema.Literal("auto")),
101
+ })),
102
+ text: Schema.optional(Schema.Struct({
103
+ verbosity: Schema.optional(OpenAIOptions.OpenAITextVerbosity),
104
+ })),
105
+ max_output_tokens: Schema.optional(Schema.Number),
106
+ temperature: Schema.optional(Schema.Number),
107
+ top_p: Schema.optional(Schema.Number),
108
+ };
109
+ const OpenAIResponsesBody = Schema.Struct({
110
+ ...OpenAIResponsesCoreFields,
111
+ stream: Schema.Literal(true),
112
+ });
113
+ const OpenAIResponsesWebSocketMessage = Schema.StructWithRest(Schema.Struct({
114
+ type: Schema.tag("response.create"),
115
+ ...OpenAIResponsesCoreFields,
116
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
117
+ const encodeWebSocketMessage = Schema.encodeSync(Schema.fromJsonString(OpenAIResponsesWebSocketMessage));
118
+ const OpenAIResponsesUsage = Schema.Struct({
119
+ input_tokens: Schema.optional(Schema.Number),
120
+ input_tokens_details: optionalNull(Schema.Struct({ cached_tokens: Schema.optional(Schema.Number) })),
121
+ output_tokens: Schema.optional(Schema.Number),
122
+ output_tokens_details: optionalNull(Schema.Struct({ reasoning_tokens: Schema.optional(Schema.Number) })),
123
+ total_tokens: Schema.optional(Schema.Number),
124
+ });
125
+ const OpenAIResponsesStreamItem = Schema.Struct({
126
+ type: Schema.String,
127
+ id: Schema.optional(Schema.String),
128
+ call_id: Schema.optional(Schema.String),
129
+ name: Schema.optional(Schema.String),
130
+ arguments: Schema.optional(Schema.String),
131
+ // Hosted (provider-executed) tool fields. Each hosted tool item carries its
132
+ // own subset of these — we capture them generically so we can surface the
133
+ // call's typed input portion and round-trip the full result payload without
134
+ // hand-rolling a per-tool schema.
135
+ status: Schema.optional(Schema.String),
136
+ action: Schema.optional(Schema.Unknown),
137
+ queries: Schema.optional(Schema.Unknown),
138
+ results: Schema.optional(Schema.Unknown),
139
+ code: Schema.optional(Schema.String),
140
+ container_id: Schema.optional(Schema.String),
141
+ outputs: Schema.optional(Schema.Unknown),
142
+ server_label: Schema.optional(Schema.String),
143
+ output: Schema.optional(Schema.Unknown),
144
+ error: Schema.optional(Schema.Unknown),
145
+ encrypted_content: optionalNull(Schema.String),
146
+ });
147
+ // OpenAI Responses surfaces provider failures in two related shapes. The
148
+ // streaming `error` event carries the details at the top level
149
+ // (`{ type: "error", code, message, param, sequence_number }`), while
150
+ // `response.failed` carries them under `response.error`. We capture both so
151
+ // the parser can surface a useful provider-error message in either path.
152
+ const OpenAIResponsesErrorPayload = Schema.Struct({
153
+ code: optionalNull(Schema.String),
154
+ message: optionalNull(Schema.String),
155
+ param: optionalNull(Schema.String),
156
+ });
157
+ const OpenAIResponsesEvent = Schema.Struct({
158
+ type: Schema.String,
159
+ delta: Schema.optional(Schema.String),
160
+ item_id: Schema.optional(Schema.String),
161
+ summary_index: Schema.optional(Schema.Number),
162
+ item: Schema.optional(OpenAIResponsesStreamItem),
163
+ response: Schema.optional(Schema.StructWithRest(Schema.Struct({
164
+ id: Schema.optional(Schema.String),
165
+ service_tier: optionalNull(Schema.String),
166
+ incomplete_details: optionalNull(Schema.Struct({ reason: Schema.String })),
167
+ usage: optionalNull(OpenAIResponsesUsage),
168
+ error: optionalNull(OpenAIResponsesErrorPayload),
169
+ }), [Schema.Record(Schema.String, Schema.Unknown)])),
170
+ code: Schema.optional(Schema.String),
171
+ message: Schema.optional(Schema.String),
172
+ param: Schema.optional(Schema.String),
173
+ });
174
+ const invalid = ProviderShared.invalidRequest;
175
+ // =============================================================================
176
+ // Request Lowering
177
+ // =============================================================================
178
+ const lowerTool = (tool, inputSchema) => ({
179
+ type: "function",
180
+ name: tool.name,
181
+ description: tool.description,
182
+ parameters: ToolSchemaProjection.openAI(inputSchema),
183
+ // TODO: Read this from OpenAI-specific tool options so direct LLM callers can opt into strict schemas.
184
+ strict: false,
185
+ });
186
+ const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("OpenAI Responses", toolChoice, {
187
+ auto: () => "auto",
188
+ none: () => "none",
189
+ required: () => "required",
190
+ tool: (name) => ({ type: "function", name }),
191
+ });
192
+ const lowerToolCall = (part) => ({
193
+ type: "function_call",
194
+ call_id: part.id,
195
+ name: part.name,
196
+ arguments: ProviderShared.encodeJson(part.input),
197
+ });
198
+ const lowerReasoning = (part) => {
199
+ const openai = part.providerMetadata?.openai;
200
+ if (!ProviderShared.isRecord(openai) || typeof openai.itemId !== "string" || openai.itemId.length === 0)
201
+ return undefined;
202
+ const encryptedContent = typeof openai.reasoningEncryptedContent === "string"
203
+ ? openai.reasoningEncryptedContent
204
+ : openai.reasoningEncryptedContent === null
205
+ ? null
206
+ : undefined;
207
+ return {
208
+ type: "reasoning",
209
+ id: openai.itemId,
210
+ summary: part.text.length > 0 ? [{ type: "summary_text", text: part.text }] : [],
211
+ encrypted_content: encryptedContent,
212
+ };
213
+ };
214
+ const hostedToolItemID = (part) => {
215
+ const openai = part.providerMetadata?.openai;
216
+ return ProviderShared.isRecord(openai) && typeof openai.itemId === "string" && openai.itemId.length > 0
217
+ ? openai.itemId
218
+ : undefined;
219
+ };
220
+ const lowerUserContent = Effect.fn("OpenAIResponses.lowerUserContent")(function* (part) {
221
+ if (part.type === "text")
222
+ return { type: "input_text", text: part.text };
223
+ if (part.type === "media") {
224
+ const media = yield* ProviderShared.validateMedia("OpenAI Responses", part, new Set(ProviderShared.IMAGE_MIMES));
225
+ return { type: "input_image", image_url: media.dataUrl };
226
+ }
227
+ return yield* ProviderShared.unsupportedContent("OpenAI Responses", "user", ["text", "media"]);
228
+ });
229
+ // Tool results may carry structured text/images. Keep media as provider-native
230
+ // content instead of JSON-stringifying base64 into a prompt string.
231
+ const lowerToolResultContentItem = Effect.fn("OpenAIResponses.lowerToolResultContentItem")(function* (item) {
232
+ if (item.type === "text")
233
+ return { type: "input_text", text: item.text };
234
+ const media = yield* ProviderShared.validateToolFile("OpenAI Responses", item, new Set(ProviderShared.IMAGE_MIMES));
235
+ return { type: "input_image", image_url: media.dataUrl };
236
+ });
237
+ const lowerToolResultOutput = Effect.fn("OpenAIResponses.lowerToolResultOutput")(function* (part) {
238
+ // Text/json/error results are encoded as a plain string for backward
239
+ // compatibility with existing cassettes and provider expectations.
240
+ if (part.result.type !== "content")
241
+ return ProviderShared.toolResultText(part);
242
+ // Preserve the narrowed array element type when compiled through a consumer package.
243
+ const content = part.result.value;
244
+ return yield* Effect.forEach(content, lowerToolResultContentItem);
245
+ });
246
+ const lowerMessages = Effect.fn("OpenAIResponses.lowerMessages")(function* (request) {
247
+ const system = request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }];
248
+ const input = [...system];
249
+ const store = OpenAIOptions.store(request);
250
+ for (const message of request.messages) {
251
+ if (message.role === "system") {
252
+ const part = yield* ProviderShared.wrappedSystemUpdate("OpenAI Responses", message);
253
+ const previous = input.at(-1);
254
+ if (previous && "role" in previous && previous.role === "user")
255
+ input[input.length - 1] = {
256
+ role: "user",
257
+ content: [...previous.content, { type: "input_text", text: part.text }],
258
+ };
259
+ else
260
+ input.push({ role: "user", content: [{ type: "input_text", text: part.text }] });
261
+ continue;
262
+ }
263
+ if (message.role === "user") {
264
+ input.push({ role: "user", content: yield* Effect.forEach(message.content, lowerUserContent) });
265
+ continue;
266
+ }
267
+ if (message.role === "assistant") {
268
+ const content = [];
269
+ const reasoningItems = {};
270
+ const reasoningReferences = new Set();
271
+ const hostedToolReferences = new Set();
272
+ const flushText = () => {
273
+ if (content.length === 0)
274
+ return;
275
+ input.push({ role: "assistant", content: content.map((part) => ({ type: "output_text", text: part.text })) });
276
+ content.splice(0, content.length);
277
+ };
278
+ for (const part of message.content) {
279
+ if (part.type === "text") {
280
+ content.push(part);
281
+ continue;
282
+ }
283
+ if (part.type === "reasoning") {
284
+ flushText();
285
+ const reasoning = lowerReasoning(part);
286
+ if (!reasoning)
287
+ continue;
288
+ if (store !== false) {
289
+ if (!reasoningReferences.has(reasoning.id))
290
+ input.push({ type: "item_reference", id: reasoning.id });
291
+ reasoningReferences.add(reasoning.id);
292
+ continue;
293
+ }
294
+ const existing = reasoningItems[reasoning.id];
295
+ if (existing) {
296
+ existing.summary.push(...reasoning.summary);
297
+ if (typeof reasoning.encrypted_content === "string")
298
+ existing.encrypted_content = reasoning.encrypted_content;
299
+ continue;
300
+ }
301
+ const replay = {
302
+ type: reasoning.type,
303
+ summary: reasoning.summary,
304
+ encrypted_content: reasoning.encrypted_content,
305
+ };
306
+ reasoningItems[reasoning.id] = replay;
307
+ input.push(replay);
308
+ continue;
309
+ }
310
+ if (part.type === "tool-call") {
311
+ flushText();
312
+ if (part.providerExecuted === true)
313
+ continue;
314
+ input.push(lowerToolCall(part));
315
+ continue;
316
+ }
317
+ if (part.type === "tool-result" && part.providerExecuted === true) {
318
+ flushText();
319
+ const itemID = hostedToolItemID(part);
320
+ if (store !== false && itemID && !hostedToolReferences.has(itemID))
321
+ input.push({ type: "item_reference", id: itemID });
322
+ if (itemID)
323
+ hostedToolReferences.add(itemID);
324
+ continue;
325
+ }
326
+ return yield* ProviderShared.unsupportedContent("OpenAI Responses", "assistant", [
327
+ "text",
328
+ "reasoning",
329
+ "tool-call",
330
+ "tool-result",
331
+ ]);
332
+ }
333
+ flushText();
334
+ continue;
335
+ }
336
+ for (const part of message.content) {
337
+ if (!ProviderShared.supportsContent(part, ["tool-result"]))
338
+ return yield* ProviderShared.unsupportedContent("OpenAI Responses", "tool", ["tool-result"]);
339
+ input.push({
340
+ type: "function_call_output",
341
+ call_id: part.id,
342
+ output: yield* lowerToolResultOutput(part),
343
+ });
344
+ }
345
+ }
346
+ // With store:false, OpenAI only accepts previous reasoning items when the
347
+ // complete item has encrypted state. Summary blocks for one item may carry
348
+ // that state only on the last block, so filter after they have been joined.
349
+ return store === false
350
+ ? input.filter((item) => !("type" in item) || item.type !== "reasoning" || typeof item.encrypted_content === "string")
351
+ : input;
352
+ });
353
+ const lowerOptions = Effect.fn("OpenAIResponses.lowerOptions")(function* (request) {
354
+ const store = OpenAIOptions.store(request);
355
+ const promptCacheKey = OpenAIOptions.promptCacheKey(request);
356
+ const effort = OpenAIOptions.reasoningEffort(request);
357
+ if (effort && !OpenAIOptions.isReasoningEffort(effort))
358
+ return yield* invalid(`OpenAI Responses does not support reasoning effort ${effort}`);
359
+ const summary = OpenAIOptions.reasoningSummary(request);
360
+ const include = OpenAIOptions.include(request);
361
+ const verbosity = OpenAIOptions.textVerbosity(request);
362
+ const instructions = OpenAIOptions.instructions(request);
363
+ const serviceTier = OpenAIOptions.serviceTier(request);
364
+ return {
365
+ ...(instructions ? { instructions } : {}),
366
+ ...(store !== undefined ? { store } : {}),
367
+ ...(promptCacheKey ? { prompt_cache_key: promptCacheKey } : {}),
368
+ ...(include ? { include } : {}),
369
+ ...(effort || summary ? { reasoning: { effort, summary } } : {}),
370
+ ...(verbosity ? { text: { verbosity } } : {}),
371
+ ...(serviceTier ? { service_tier: serviceTier } : {}),
372
+ };
373
+ });
374
+ const fromRequest = Effect.fn("OpenAIResponses.fromRequest")(function* (request) {
375
+ const generation = request.generation;
376
+ const options = yield* lowerOptions(request);
377
+ const toolSchemaCompatibility = request.model.compatibility?.toolSchema;
378
+ return {
379
+ model: request.model.id,
380
+ input: yield* lowerMessages(request),
381
+ tools: request.tools.length === 0
382
+ ? undefined
383
+ : request.tools.map((tool) => lowerTool(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility))),
384
+ tool_choice: request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined,
385
+ stream: true,
386
+ max_output_tokens: generation?.maxTokens,
387
+ temperature: generation?.temperature,
388
+ top_p: generation?.topP,
389
+ ...options,
390
+ };
391
+ });
392
+ // =============================================================================
393
+ // Stream Parsing
394
+ // =============================================================================
395
+ // OpenAI Responses reports `input_tokens` (inclusive total) with a
396
+ // `cached_tokens` subset, and `output_tokens` (inclusive total) with a
397
+ // `reasoning_tokens` subset. Pass the totals through and derive the
398
+ // non-cached breakdown.
399
+ const mapUsage = (usage) => {
400
+ if (!usage)
401
+ return undefined;
402
+ const cached = usage.input_tokens_details?.cached_tokens;
403
+ const reasoning = usage.output_tokens_details?.reasoning_tokens;
404
+ const nonCached = ProviderShared.subtractTokens(usage.input_tokens, cached);
405
+ return new Usage({
406
+ inputTokens: usage.input_tokens,
407
+ outputTokens: usage.output_tokens,
408
+ nonCachedInputTokens: nonCached,
409
+ cacheReadInputTokens: cached,
410
+ reasoningTokens: reasoning,
411
+ totalTokens: ProviderShared.totalTokens(usage.input_tokens, usage.output_tokens, usage.total_tokens),
412
+ providerMetadata: { openai: usage },
413
+ });
414
+ };
415
+ const mapFinishReason = (event, hasFunctionCall) => {
416
+ const reason = event.response?.incomplete_details?.reason;
417
+ if (reason === undefined || reason === null)
418
+ return hasFunctionCall ? "tool-calls" : "stop";
419
+ if (reason === "max_output_tokens")
420
+ return "length";
421
+ if (reason === "content_filter")
422
+ return "content-filter";
423
+ return hasFunctionCall ? "tool-calls" : "unknown";
424
+ };
425
+ const openaiMetadata = (metadata) => ({ openai: metadata });
426
+ // Hosted tool items (provider-executed) ship their typed input + status +
427
+ // result fields all in one item. We expose them as a `tool-call` +
428
+ // `tool-result` pair so consumers can treat them uniformly with client tools,
429
+ // only differentiated by `providerExecuted: true`.
430
+ //
431
+ // One record per OpenAI Responses item type that represents a hosted
432
+ // (provider-executed) tool call: the common name we surface, plus an `input`
433
+ // extractor that picks the fields the model actually populated for that tool.
434
+ // Falling back to `{}` when an entry isn't fully typed keeps unknown tools
435
+ // observable without rolling a per-tool schema.
436
+ const HOSTED_TOOLS = {
437
+ web_search_call: { name: "web_search", input: (item) => item.action ?? {} },
438
+ web_search_preview_call: { name: "web_search_preview", input: (item) => item.action ?? {} },
439
+ file_search_call: { name: "file_search", input: (item) => ({ queries: item.queries ?? [] }) },
440
+ code_interpreter_call: {
441
+ name: "code_interpreter",
442
+ input: (item) => ({ code: item.code, container_id: item.container_id }),
443
+ },
444
+ computer_use_call: { name: "computer_use", input: (item) => item.action ?? {} },
445
+ image_generation_call: { name: "image_generation", input: () => ({}) },
446
+ mcp_call: {
447
+ name: "mcp",
448
+ input: (item) => ({ server_label: item.server_label, name: item.name, arguments: item.arguments }),
449
+ },
450
+ local_shell_call: { name: "local_shell", input: (item) => item.action ?? {} },
451
+ };
452
+ const isHostedToolItem = (item) => item.type in HOSTED_TOOLS && typeof item.id === "string" && item.id.length > 0;
453
+ const isReasoningItem = (item) => item.type === "reasoning" && typeof item.id === "string" && item.id.length > 0;
454
+ // Round-trip the full item as the structured result so consumers can extract
455
+ // outputs / sources / status without re-decoding.
456
+ const hostedToolResult = (item) => {
457
+ const isError = typeof item.error !== "undefined" && item.error !== null;
458
+ return isError ? { type: "error", value: item.error } : { type: "json", value: item };
459
+ };
460
+ const hostedToolEvents = (item) => {
461
+ const tool = HOSTED_TOOLS[item.type];
462
+ const providerMetadata = openaiMetadata({ itemId: item.id });
463
+ return [
464
+ LLMEvent.toolCall({
465
+ id: item.id,
466
+ name: tool.name,
467
+ input: tool.input(item),
468
+ providerExecuted: true,
469
+ providerMetadata,
470
+ }),
471
+ LLMEvent.toolResult({
472
+ id: item.id,
473
+ name: tool.name,
474
+ result: hostedToolResult(item),
475
+ providerExecuted: true,
476
+ providerMetadata,
477
+ }),
478
+ ];
479
+ };
480
+ const NO_EVENTS = [];
481
+ // `response.completed` / `response.incomplete` are clean finishes that emit a
482
+ // `finish` event; `response.failed` is a hard failure that emits a
483
+ // `provider-error`. All three end the stream — kept in one set so `step` and
484
+ // the protocol's `terminal` predicate stay in sync.
485
+ const TERMINAL_TYPES = new Set(["response.completed", "response.incomplete", "response.failed"]);
486
+ const onOutputTextDelta = (state, event) => {
487
+ if (!event.delta)
488
+ return [state, NO_EVENTS];
489
+ const events = [];
490
+ return [
491
+ { ...state, lifecycle: Lifecycle.textDelta(state.lifecycle, events, event.item_id ?? "text-0", event.delta) },
492
+ events,
493
+ ];
494
+ };
495
+ const onReasoningDelta = (state, event) => {
496
+ if (!event.delta)
497
+ return [state, NO_EVENTS];
498
+ const events = [];
499
+ const itemID = event.item_id ?? "reasoning-0";
500
+ const id = event.summary_index !== undefined || state.reasoningItems[itemID] ? `${itemID}:${event.summary_index ?? 0}` : itemID;
501
+ return [
502
+ {
503
+ ...state,
504
+ lifecycle: Lifecycle.reasoningDelta(state.lifecycle, events, id, event.delta),
505
+ },
506
+ events,
507
+ ];
508
+ };
509
+ const onReasoningDone = (state, _event) => [state, NO_EVENTS];
510
+ const reasoningMetadata = (item) => openaiMetadata({ itemId: item.id, reasoningEncryptedContent: item.encrypted_content ?? null });
511
+ // OpenAI Responses streams reasoning items in a stable order:
512
+ // `output_item.added` (reasoning) →
513
+ // `reasoning_summary_part.added` (index=0) →
514
+ // `reasoning_summary_text.delta` →
515
+ // `reasoning_summary_part.done` (index=0) →
516
+ // (repeat for index>0) →
517
+ // `output_item.done` (reasoning).
518
+ // The handlers below rely on this ordering: `onOutputItemAdded` seeds the
519
+ // per-item entry, `onReasoningSummaryPartAdded` for `summary_index === 0`
520
+ // short-circuits when the entry already exists, and higher-index handlers
521
+ // fold against the same entry. Behaviour for out-of-order events is
522
+ // best-effort, not guaranteed.
523
+ const onOutputItemAdded = (state, event) => {
524
+ const item = event.item;
525
+ if (item && isReasoningItem(item)) {
526
+ const events = [];
527
+ return [
528
+ {
529
+ ...state,
530
+ lifecycle: Lifecycle.reasoningStart(state.lifecycle, events, `${item.id}:0`, reasoningMetadata(item)),
531
+ reasoningItems: {
532
+ ...state.reasoningItems,
533
+ [item.id]: { encryptedContent: item.encrypted_content, summaryParts: { 0: "active" } },
534
+ },
535
+ },
536
+ events,
537
+ ];
538
+ }
539
+ if (item?.type !== "function_call" || !item.id)
540
+ return [state, NO_EVENTS];
541
+ const providerMetadata = openaiMetadata({ itemId: item.id });
542
+ const events = [];
543
+ const lifecycle = Lifecycle.stepStart(state.lifecycle, events);
544
+ return [
545
+ {
546
+ ...state,
547
+ lifecycle,
548
+ hasFunctionCall: state.hasFunctionCall,
549
+ tools: ToolStream.start(state.tools, item.id, {
550
+ id: item.call_id ?? item.id,
551
+ name: item.name ?? "",
552
+ input: item.arguments ?? "",
553
+ providerMetadata,
554
+ }),
555
+ },
556
+ [...events, LLMEvent.toolInputStart({ id: item.call_id ?? item.id, name: item.name ?? "", providerMetadata })],
557
+ ];
558
+ };
559
+ const onReasoningSummaryPartAdded = (state, event) => {
560
+ if (!event.item_id || event.summary_index === undefined)
561
+ return [state, NO_EVENTS];
562
+ const item = state.reasoningItems[event.item_id] ?? { encryptedContent: undefined, summaryParts: {} };
563
+ if (event.summary_index === 0) {
564
+ if (state.reasoningItems[event.item_id])
565
+ return [state, NO_EVENTS];
566
+ const events = [];
567
+ return [
568
+ {
569
+ ...state,
570
+ lifecycle: Lifecycle.reasoningStart(state.lifecycle, events, `${event.item_id}:0`, openaiMetadata({ itemId: event.item_id, reasoningEncryptedContent: null })),
571
+ reasoningItems: {
572
+ ...state.reasoningItems,
573
+ [event.item_id]: { ...item, summaryParts: { 0: "active" } },
574
+ },
575
+ },
576
+ events,
577
+ ];
578
+ }
579
+ const events = [];
580
+ const closed = Object.entries(item.summaryParts)
581
+ .filter((entry) => entry[1] === "can-conclude")
582
+ .reduce((lifecycle, entry) => Lifecycle.reasoningEnd(lifecycle, events, `${event.item_id}:${entry[0]}`, openaiMetadata({ itemId: event.item_id })), state.lifecycle);
583
+ return [
584
+ {
585
+ ...state,
586
+ lifecycle: Lifecycle.reasoningStart(closed, events, `${event.item_id}:${event.summary_index}`, openaiMetadata({ itemId: event.item_id, reasoningEncryptedContent: item.encryptedContent ?? null })),
587
+ reasoningItems: {
588
+ ...state.reasoningItems,
589
+ [event.item_id]: {
590
+ ...item,
591
+ summaryParts: {
592
+ ...Object.fromEntries(Object.entries(item.summaryParts).map((entry) => entry[1] === "can-conclude" ? [entry[0], "concluded"] : entry)),
593
+ [event.summary_index]: "active",
594
+ },
595
+ },
596
+ },
597
+ },
598
+ events,
599
+ ];
600
+ };
601
+ const onReasoningSummaryPartDone = (state, event) => {
602
+ if (!event.item_id || event.summary_index === undefined)
603
+ return [state, NO_EVENTS];
604
+ const item = state.reasoningItems[event.item_id];
605
+ if (!item)
606
+ return [state, NO_EVENTS];
607
+ const events = [];
608
+ return [
609
+ {
610
+ ...state,
611
+ lifecycle: state.store !== false
612
+ ? Lifecycle.reasoningEnd(state.lifecycle, events, `${event.item_id}:${event.summary_index}`, openaiMetadata({ itemId: event.item_id }))
613
+ : state.lifecycle,
614
+ reasoningItems: {
615
+ ...state.reasoningItems,
616
+ [event.item_id]: {
617
+ ...item,
618
+ summaryParts: {
619
+ ...item.summaryParts,
620
+ [event.summary_index]: state.store !== false ? "concluded" : "can-conclude",
621
+ },
622
+ },
623
+ },
624
+ },
625
+ events,
626
+ ];
627
+ };
628
+ const onFunctionCallArgumentsDelta = Effect.fn("OpenAIResponses.onFunctionCallArgumentsDelta")(function* (state, event) {
629
+ if (!event.item_id || !event.delta)
630
+ return [state, NO_EVENTS];
631
+ const result = ToolStream.appendExisting(ADAPTER, state.tools, event.item_id, event.delta, "OpenAI Responses tool argument delta is missing its tool call");
632
+ if (ToolStream.isError(result))
633
+ return yield* result;
634
+ const events = [];
635
+ const lifecycle = result.events.length ? Lifecycle.stepStart(state.lifecycle, events) : state.lifecycle;
636
+ events.push(...result.events);
637
+ return [{ ...state, lifecycle, tools: result.tools }, events];
638
+ });
639
+ const onOutputItemDone = Effect.fn("OpenAIResponses.onOutputItemDone")(function* (state, event) {
640
+ const item = event.item;
641
+ if (!item)
642
+ return [state, NO_EVENTS];
643
+ if (item.type === "function_call") {
644
+ if (!item.id || !item.call_id || !item.name)
645
+ return [state, NO_EVENTS];
646
+ const tools = state.tools[item.id]
647
+ ? state.tools
648
+ : ToolStream.start(state.tools, item.id, { id: item.call_id, name: item.name });
649
+ const result = item.arguments === undefined
650
+ ? yield* ToolStream.finish(ADAPTER, tools, item.id)
651
+ : yield* ToolStream.finishWithInput(ADAPTER, tools, item.id, item.arguments);
652
+ const events = [];
653
+ const resultEvents = result.events ?? [];
654
+ const lifecycle = resultEvents.length ? Lifecycle.stepStart(state.lifecycle, events) : state.lifecycle;
655
+ events.push(...resultEvents);
656
+ return [
657
+ {
658
+ ...state,
659
+ lifecycle,
660
+ hasFunctionCall: resultEvents.some(LLMEvent.is.toolCall) ? true : state.hasFunctionCall,
661
+ tools: result.tools,
662
+ },
663
+ events,
664
+ ];
665
+ }
666
+ if (isHostedToolItem(item)) {
667
+ const events = [];
668
+ const lifecycle = Lifecycle.stepStart(state.lifecycle, events);
669
+ events.push(...hostedToolEvents(item));
670
+ return [{ ...state, lifecycle }, events];
671
+ }
672
+ if (isReasoningItem(item)) {
673
+ const events = [];
674
+ const providerMetadata = reasoningMetadata(item);
675
+ const reasoningItem = state.reasoningItems[item.id];
676
+ if (reasoningItem) {
677
+ const lifecycle = Object.entries(reasoningItem.summaryParts)
678
+ .filter((entry) => entry[1] === "active" || entry[1] === "can-conclude")
679
+ .reduce((lifecycle, entry) => Lifecycle.reasoningEnd(lifecycle, events, `${item.id}:${entry[0]}`, providerMetadata), state.lifecycle);
680
+ const { [item.id]: _removed, ...reasoningItems } = state.reasoningItems;
681
+ return [{ ...state, lifecycle, reasoningItems }, events];
682
+ }
683
+ if (!state.lifecycle.reasoning.has(item.id)) {
684
+ const lifecycle = Lifecycle.stepStart(state.lifecycle, events);
685
+ events.push(LLMEvent.reasoningStart({ id: item.id, providerMetadata }));
686
+ events.push(LLMEvent.reasoningEnd({ id: item.id, providerMetadata }));
687
+ return [{ ...state, lifecycle }, events];
688
+ }
689
+ return [
690
+ { ...state, lifecycle: Lifecycle.reasoningEnd(state.lifecycle, events, item.id, providerMetadata) },
691
+ events,
692
+ ];
693
+ }
694
+ return [state, NO_EVENTS];
695
+ });
696
+ const onResponseFinish = (state, event) => {
697
+ const events = [];
698
+ const lifecycle = Lifecycle.finish(state.lifecycle, events, {
699
+ reason: mapFinishReason(event, state.hasFunctionCall),
700
+ usage: mapUsage(event.response?.usage),
701
+ providerMetadata: event.response?.id || event.response?.service_tier
702
+ ? openaiMetadata({
703
+ responseId: event.response.id,
704
+ serviceTier: event.response.service_tier,
705
+ })
706
+ : undefined,
707
+ });
708
+ return [{ ...state, lifecycle }, events];
709
+ };
710
+ // Build a single human-readable message from whatever the provider supplied.
711
+ // When both code and message are present, prefix the code so consumers see
712
+ // the failure mode (e.g. `rate_limit_exceeded: Slow down`) instead of just
713
+ // the bare message — production rate limits and context-length failures used
714
+ // to be indistinguishable from generic stream drops.
715
+ const providerErrorMessage = (event, fallback) => {
716
+ const nested = event.response?.error ?? undefined;
717
+ const message = event.message || nested?.message || undefined;
718
+ const code = event.code || nested?.code || undefined;
719
+ if (message && code)
720
+ return `${code}: ${message}`;
721
+ return message || code || fallback;
722
+ };
723
+ const providerError = (event, fallback) => {
724
+ const code = event.code || event.response?.error?.code || undefined;
725
+ const message = providerErrorMessage(event, fallback);
726
+ return LLMEvent.providerError({
727
+ message,
728
+ classification: code === "context_length_exceeded" || isContextOverflow(message) ? "context-overflow" : undefined,
729
+ });
730
+ };
731
+ const onResponseFailed = (state, event) => [
732
+ state,
733
+ [providerError(event, "OpenAI Responses response failed")],
734
+ ];
735
+ const onError = (state, event) => [
736
+ state,
737
+ [providerError(event, "OpenAI Responses stream error")],
738
+ ];
739
+ const step = (state, event) => {
740
+ if (event.type === "response.output_text.delta")
741
+ return Effect.succeed(onOutputTextDelta(state, event));
742
+ if (event.type === "response.reasoning_text.delta" ||
743
+ event.type === "response.reasoning_summary.delta" ||
744
+ event.type === "response.reasoning_summary_text.delta")
745
+ return Effect.succeed(onReasoningDelta(state, event));
746
+ if (event.type === "response.reasoning_text.done" ||
747
+ event.type === "response.reasoning_summary.done" ||
748
+ event.type === "response.reasoning_summary_text.done")
749
+ return Effect.succeed(onReasoningDone(state, event));
750
+ if (event.type === "response.reasoning_summary_part.added")
751
+ return Effect.succeed(onReasoningSummaryPartAdded(state, event));
752
+ if (event.type === "response.reasoning_summary_part.done")
753
+ return Effect.succeed(onReasoningSummaryPartDone(state, event));
754
+ if (event.type === "response.output_item.added")
755
+ return Effect.succeed(onOutputItemAdded(state, event));
756
+ if (event.type === "response.function_call_arguments.delta")
757
+ return onFunctionCallArgumentsDelta(state, event);
758
+ if (event.type === "response.output_item.done")
759
+ return onOutputItemDone(state, event);
760
+ if (event.type === "response.completed" || event.type === "response.incomplete")
761
+ return Effect.succeed(onResponseFinish(state, event));
762
+ if (event.type === "response.failed")
763
+ return Effect.succeed(onResponseFailed(state, event));
764
+ if (event.type === "error")
765
+ return Effect.succeed(onError(state, event));
766
+ return Effect.succeed([state, NO_EVENTS]);
767
+ };
768
+ // =============================================================================
769
+ // Protocol And OpenAI Route
770
+ // =============================================================================
771
+ /**
772
+ * The OpenAI Responses protocol — request body construction, body schema, and
773
+ * the streaming-event state machine. Used by native OpenAI and (once
774
+ * registered) Azure OpenAI Responses.
775
+ */
776
+ export const protocol = Protocol.make({
777
+ id: ADAPTER,
778
+ body: {
779
+ schema: OpenAIResponsesBody,
780
+ from: fromRequest,
781
+ },
782
+ stream: {
783
+ event: Protocol.jsonEvent(OpenAIResponsesEvent),
784
+ initial: (request) => ({
785
+ hasFunctionCall: false,
786
+ tools: ToolStream.empty(),
787
+ lifecycle: Lifecycle.initial(),
788
+ reasoningItems: {},
789
+ store: OpenAIOptions.store(request),
790
+ }),
791
+ step,
792
+ terminal: (event) => TERMINAL_TYPES.has(event.type),
793
+ },
794
+ });
795
+ const endpoint = Endpoint.path(PATH, { baseURL: DEFAULT_BASE_URL });
796
+ const auth = Auth.none;
797
+ export const httpTransport = HttpTransport.sseJson.with();
798
+ export const route = Route.make({
799
+ id: ADAPTER,
800
+ provider: "openai",
801
+ protocol,
802
+ endpoint,
803
+ auth,
804
+ transport: httpTransport,
805
+ defaults: { providerOptions: { openai: { store: false } } },
806
+ });
807
+ const decodeWebSocketMessage = ProviderShared.validateWith(Schema.decodeUnknownEffect(OpenAIResponsesWebSocketMessage));
808
+ const webSocketMessage = (body) => Effect.gen(function* () {
809
+ if (!ProviderShared.isRecord(body))
810
+ return yield* ProviderShared.invalidRequest("OpenAI Responses WebSocket body must be a JSON object");
811
+ const { stream: _stream, ...message } = body;
812
+ return yield* decodeWebSocketMessage({ ...message, type: "response.create" });
813
+ });
814
+ export const webSocketTransport = WebSocketTransport.jsonTransport.with({
815
+ toMessage: webSocketMessage,
816
+ encodeMessage: encodeWebSocketMessage,
817
+ });
818
+ export const webSocketRoute = Route.make({
819
+ id: `${ADAPTER}-websocket`,
820
+ provider: "openai",
821
+ protocol,
822
+ endpoint,
823
+ auth,
824
+ transport: webSocketTransport,
825
+ defaults: { providerOptions: { openai: { store: false } } },
826
+ });
827
+ export * as OpenAIResponses from "./openai-responses";
828
+ //# sourceMappingURL=openai-responses.js.map