@opencode/ai 0.0.0-reserved → 2.0.0

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 (288) hide show
  1. package/README.md +879 -2
  2. package/dist/cache-policy.d.ts +2 -0
  3. package/dist/cache-policy.js +129 -0
  4. package/dist/image-client.d.ts +19 -0
  5. package/dist/image-client.js +28 -0
  6. package/dist/image.d.ts +110 -0
  7. package/dist/image.js +103 -0
  8. package/dist/index.d.ts +18 -0
  9. package/dist/index.js +12 -0
  10. package/dist/llm.d.ts +252 -0
  11. package/dist/llm.js +74 -0
  12. package/dist/protocols/alibaba-chat.d.ts +225 -0
  13. package/dist/protocols/alibaba-chat.js +75 -0
  14. package/dist/protocols/alibaba-messages.d.ts +350 -0
  15. package/dist/protocols/alibaba-messages.js +40 -0
  16. package/dist/protocols/alibaba-responses.d.ts +255 -0
  17. package/dist/protocols/alibaba-responses.js +80 -0
  18. package/dist/protocols/anthropic-messages.d.ts +980 -0
  19. package/dist/protocols/anthropic-messages.js +1460 -0
  20. package/dist/protocols/bedrock-converse.d.ts +499 -0
  21. package/dist/protocols/bedrock-converse.js +643 -0
  22. package/dist/protocols/bedrock-event-stream.d.ts +9 -0
  23. package/dist/protocols/bedrock-event-stream.js +97 -0
  24. package/dist/protocols/gemini.d.ts +285 -0
  25. package/dist/protocols/gemini.js +671 -0
  26. package/dist/protocols/google-images.d.ts +30 -0
  27. package/dist/protocols/google-images.js +181 -0
  28. package/dist/protocols/index.d.ts +12 -0
  29. package/dist/protocols/index.js +12 -0
  30. package/dist/protocols/meta-images.d.ts +26 -0
  31. package/dist/protocols/meta-images.js +89 -0
  32. package/dist/protocols/meta-messages.d.ts +356 -0
  33. package/dist/protocols/meta-messages.js +41 -0
  34. package/dist/protocols/meta-responses.d.ts +473 -0
  35. package/dist/protocols/meta-responses.js +173 -0
  36. package/dist/protocols/mistral-chat.d.ts +540 -0
  37. package/dist/protocols/mistral-chat.js +624 -0
  38. package/dist/protocols/open-responses-channel.d.ts +25 -0
  39. package/dist/protocols/open-responses-channel.js +141 -0
  40. package/dist/protocols/open-responses-continuation.d.ts +16 -0
  41. package/dist/protocols/open-responses-continuation.js +170 -0
  42. package/dist/protocols/open-responses.d.ts +1715 -0
  43. package/dist/protocols/open-responses.js +1228 -0
  44. package/dist/protocols/openai-chat.d.ts +860 -0
  45. package/dist/protocols/openai-chat.js +966 -0
  46. package/dist/protocols/openai-compatible-chat.d.ts +109 -0
  47. package/dist/protocols/openai-compatible-chat.js +19 -0
  48. package/dist/protocols/openai-compatible-responses.d.ts +172 -0
  49. package/dist/protocols/openai-compatible-responses.js +18 -0
  50. package/dist/protocols/openai-images.d.ts +32 -0
  51. package/dist/protocols/openai-images.js +183 -0
  52. package/dist/protocols/openai-responses.d.ts +1389 -0
  53. package/dist/protocols/openai-responses.js +260 -0
  54. package/dist/protocols/shared.d.ts +193 -0
  55. package/dist/protocols/shared.js +290 -0
  56. package/dist/protocols/utils/bedrock-auth.d.ts +60 -0
  57. package/dist/protocols/utils/bedrock-auth.js +85 -0
  58. package/dist/protocols/utils/bedrock-cache.d.ts +19 -0
  59. package/dist/protocols/utils/bedrock-cache.js +49 -0
  60. package/dist/protocols/utils/bedrock-media.d.ts +55 -0
  61. package/dist/protocols/utils/bedrock-media.js +73 -0
  62. package/dist/protocols/utils/cache.d.ts +6 -0
  63. package/dist/protocols/utils/cache.js +5 -0
  64. package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
  65. package/dist/protocols/utils/gemini-tool-schema.js +103 -0
  66. package/dist/protocols/utils/image-input.d.ts +21 -0
  67. package/dist/protocols/utils/image-input.js +20 -0
  68. package/dist/protocols/utils/lifecycle.d.ts +24 -0
  69. package/dist/protocols/utils/lifecycle.js +72 -0
  70. package/dist/protocols/utils/meta-image.d.ts +2 -0
  71. package/dist/protocols/utils/meta-image.js +13 -0
  72. package/dist/protocols/utils/open-responses-options.d.ts +56 -0
  73. package/dist/protocols/utils/open-responses-options.js +61 -0
  74. package/dist/protocols/utils/openai-image.d.ts +5 -0
  75. package/dist/protocols/utils/openai-image.js +18 -0
  76. package/dist/protocols/utils/openai-options.d.ts +16 -0
  77. package/dist/protocols/utils/openai-options.js +14 -0
  78. package/dist/protocols/utils/partial-json-options.d.ts +62 -0
  79. package/dist/protocols/utils/partial-json-options.js +52 -0
  80. package/dist/protocols/utils/partial-json.d.ts +8 -0
  81. package/dist/protocols/utils/partial-json.js +279 -0
  82. package/dist/protocols/utils/responses-checkpoint.d.ts +4 -0
  83. package/dist/protocols/utils/responses-checkpoint.js +107 -0
  84. package/dist/protocols/utils/responses-compaction.d.ts +4 -0
  85. package/dist/protocols/utils/responses-compaction.js +129 -0
  86. package/dist/protocols/utils/responses-hosted-tools.d.ts +26 -0
  87. package/dist/protocols/utils/responses-hosted-tools.js +32 -0
  88. package/dist/protocols/utils/tool-schema.d.ts +8 -0
  89. package/dist/protocols/utils/tool-schema.js +54 -0
  90. package/dist/protocols/utils/tool-stream.d.ts +710 -0
  91. package/dist/protocols/utils/tool-stream.js +155 -0
  92. package/dist/protocols/xai-images.d.ts +26 -0
  93. package/dist/protocols/xai-images.js +106 -0
  94. package/dist/protocols/xai-responses.d.ts +250 -0
  95. package/dist/protocols/xai-responses.js +81 -0
  96. package/dist/protocols/zai-chat.d.ts +202 -0
  97. package/dist/protocols/zai-chat.js +49 -0
  98. package/dist/protocols/zai-images.d.ts +22 -0
  99. package/dist/protocols/zai-images.js +79 -0
  100. package/dist/protocols/zai-messages.d.ts +344 -0
  101. package/dist/protocols/zai-messages.js +27 -0
  102. package/dist/protocols.d.ts +1 -0
  103. package/dist/protocols.js +1 -0
  104. package/dist/provider-error.d.ts +15 -0
  105. package/dist/provider-error.js +125 -0
  106. package/dist/provider-package.d.ts +15 -0
  107. package/dist/provider-package.js +1 -0
  108. package/dist/provider.d.ts +23 -0
  109. package/dist/provider.js +2 -0
  110. package/dist/providers/alibaba/chat.d.ts +1 -0
  111. package/dist/providers/alibaba/chat.js +1 -0
  112. package/dist/providers/alibaba/messages.d.ts +3 -0
  113. package/dist/providers/alibaba/messages.js +1 -0
  114. package/dist/providers/alibaba/responses.d.ts +3 -0
  115. package/dist/providers/alibaba/responses.js +1 -0
  116. package/dist/providers/alibaba.d.ts +711 -0
  117. package/dist/providers/alibaba.js +94 -0
  118. package/dist/providers/amazon-bedrock/mantle/chat.d.ts +2 -0
  119. package/dist/providers/amazon-bedrock/mantle/chat.js +1 -0
  120. package/dist/providers/amazon-bedrock/mantle/responses.d.ts +2 -0
  121. package/dist/providers/amazon-bedrock/mantle/responses.js +1 -0
  122. package/dist/providers/amazon-bedrock/mantle.d.ts +2 -0
  123. package/dist/providers/amazon-bedrock/mantle.js +1 -0
  124. package/dist/providers/amazon-bedrock-mantle.d.ts +313 -0
  125. package/dist/providers/amazon-bedrock-mantle.js +79 -0
  126. package/dist/providers/amazon-bedrock.d.ts +173 -0
  127. package/dist/providers/amazon-bedrock.js +41 -0
  128. package/dist/providers/anthropic-compatible.d.ts +309 -0
  129. package/dist/providers/anthropic-compatible.js +50 -0
  130. package/dist/providers/anthropic.d.ts +307 -0
  131. package/dist/providers/anthropic.js +42 -0
  132. package/dist/providers/azure/chat.d.ts +2 -0
  133. package/dist/providers/azure/chat.js +1 -0
  134. package/dist/providers/azure/responses.d.ts +2 -0
  135. package/dist/providers/azure/responses.js +1 -0
  136. package/dist/providers/azure.d.ts +598 -0
  137. package/dist/providers/azure.js +115 -0
  138. package/dist/providers/baseten.d.ts +228 -0
  139. package/dist/providers/baseten.js +38 -0
  140. package/dist/providers/cerebras.d.ts +227 -0
  141. package/dist/providers/cerebras.js +40 -0
  142. package/dist/providers/cloudflare-ai-gateway.d.ts +237 -0
  143. package/dist/providers/cloudflare-ai-gateway.js +65 -0
  144. package/dist/providers/cloudflare-workers-ai.d.ts +231 -0
  145. package/dist/providers/cloudflare-workers-ai.js +51 -0
  146. package/dist/providers/deepinfra.d.ts +227 -0
  147. package/dist/providers/deepinfra.js +43 -0
  148. package/dist/providers/deepseek.d.ts +228 -0
  149. package/dist/providers/deepseek.js +41 -0
  150. package/dist/providers/fireworks.d.ts +228 -0
  151. package/dist/providers/fireworks.js +38 -0
  152. package/dist/providers/google-vertex/chat.d.ts +2 -0
  153. package/dist/providers/google-vertex/chat.js +1 -0
  154. package/dist/providers/google-vertex/gemini.d.ts +2 -0
  155. package/dist/providers/google-vertex/gemini.js +1 -0
  156. package/dist/providers/google-vertex/messages.d.ts +2 -0
  157. package/dist/providers/google-vertex/messages.js +1 -0
  158. package/dist/providers/google-vertex/responses.d.ts +2 -0
  159. package/dist/providers/google-vertex/responses.js +1 -0
  160. package/dist/providers/google-vertex-chat.d.ts +132 -0
  161. package/dist/providers/google-vertex-chat.js +55 -0
  162. package/dist/providers/google-vertex-messages.d.ts +306 -0
  163. package/dist/providers/google-vertex-messages.js +75 -0
  164. package/dist/providers/google-vertex-responses.d.ts +197 -0
  165. package/dist/providers/google-vertex-responses.js +56 -0
  166. package/dist/providers/google-vertex-shared.d.ts +22 -0
  167. package/dist/providers/google-vertex-shared.js +72 -0
  168. package/dist/providers/google-vertex.d.ts +119 -0
  169. package/dist/providers/google-vertex.js +98 -0
  170. package/dist/providers/google.d.ts +114 -0
  171. package/dist/providers/google.js +42 -0
  172. package/dist/providers/groq.d.ts +314 -0
  173. package/dist/providers/groq.js +81 -0
  174. package/dist/providers/index.d.ts +31 -0
  175. package/dist/providers/index.js +31 -0
  176. package/dist/providers/meta/chat.d.ts +2 -0
  177. package/dist/providers/meta/chat.js +1 -0
  178. package/dist/providers/meta/messages.d.ts +2 -0
  179. package/dist/providers/meta/messages.js +1 -0
  180. package/dist/providers/meta/responses.d.ts +2 -0
  181. package/dist/providers/meta/responses.js +1 -0
  182. package/dist/providers/meta.d.ts +636 -0
  183. package/dist/providers/meta.js +113 -0
  184. package/dist/providers/minimax/chat.d.ts +4 -0
  185. package/dist/providers/minimax/chat.js +8 -0
  186. package/dist/providers/minimax/messages.d.ts +1 -0
  187. package/dist/providers/minimax/messages.js +1 -0
  188. package/dist/providers/minimax/responses.d.ts +4 -0
  189. package/dist/providers/minimax/responses.js +8 -0
  190. package/dist/providers/minimax.d.ts +598 -0
  191. package/dist/providers/minimax.js +89 -0
  192. package/dist/providers/mistral.d.ts +207 -0
  193. package/dist/providers/mistral.js +28 -0
  194. package/dist/providers/moonshot/chat.d.ts +1 -0
  195. package/dist/providers/moonshot/chat.js +1 -0
  196. package/dist/providers/moonshot/messages.d.ts +4 -0
  197. package/dist/providers/moonshot/messages.js +8 -0
  198. package/dist/providers/moonshot/responses.d.ts +4 -0
  199. package/dist/providers/moonshot/responses.js +8 -0
  200. package/dist/providers/moonshot.d.ts +596 -0
  201. package/dist/providers/moonshot.js +90 -0
  202. package/dist/providers/open-responses-options.d.ts +6 -0
  203. package/dist/providers/open-responses-options.js +1 -0
  204. package/dist/providers/openai/chat.d.ts +2 -0
  205. package/dist/providers/openai/chat.js +1 -0
  206. package/dist/providers/openai/responses.d.ts +2 -0
  207. package/dist/providers/openai/responses.js +1 -0
  208. package/dist/providers/openai-compatible/responses.d.ts +1 -0
  209. package/dist/providers/openai-compatible/responses.js +1 -0
  210. package/dist/providers/openai-compatible-responses.d.ts +195 -0
  211. package/dist/providers/openai-compatible-responses.js +32 -0
  212. package/dist/providers/openai-compatible.d.ts +130 -0
  213. package/dist/providers/openai-compatible.js +33 -0
  214. package/dist/providers/openai-options.d.ts +26 -0
  215. package/dist/providers/openai-options.js +41 -0
  216. package/dist/providers/openai.d.ts +404 -0
  217. package/dist/providers/openai.js +82 -0
  218. package/dist/providers/openrouter.d.ts +563 -0
  219. package/dist/providers/openrouter.js +114 -0
  220. package/dist/providers/togetherai.d.ts +227 -0
  221. package/dist/providers/togetherai.js +40 -0
  222. package/dist/providers/xai.d.ts +163 -0
  223. package/dist/providers/xai.js +88 -0
  224. package/dist/providers/zai/chat.d.ts +1 -0
  225. package/dist/providers/zai/chat.js +1 -0
  226. package/dist/providers/zai-coding-plan/chat.d.ts +1 -0
  227. package/dist/providers/zai-coding-plan/chat.js +1 -0
  228. package/dist/providers/zai-coding-plan/messages.d.ts +4 -0
  229. package/dist/providers/zai-coding-plan/messages.js +8 -0
  230. package/dist/providers/zai-coding-plan/responses.d.ts +4 -0
  231. package/dist/providers/zai-coding-plan/responses.js +8 -0
  232. package/dist/providers/zai-coding-plan.d.ts +577 -0
  233. package/dist/providers/zai-coding-plan.js +63 -0
  234. package/dist/providers/zai.d.ts +149 -0
  235. package/dist/providers/zai.js +53 -0
  236. package/dist/providers.d.ts +1 -0
  237. package/dist/providers.js +1 -0
  238. package/dist/route/auth-options.d.ts +34 -0
  239. package/dist/route/auth-options.js +14 -0
  240. package/dist/route/auth.d.ts +51 -0
  241. package/dist/route/auth.js +87 -0
  242. package/dist/route/client.d.ts +430 -0
  243. package/dist/route/client.js +307 -0
  244. package/dist/route/endpoint.d.ts +28 -0
  245. package/dist/route/endpoint.js +21 -0
  246. package/dist/route/executor.d.ts +27 -0
  247. package/dist/route/executor.js +183 -0
  248. package/dist/route/framing.d.ts +29 -0
  249. package/dist/route/framing.js +14 -0
  250. package/dist/route/index.d.ts +16 -0
  251. package/dist/route/index.js +9 -0
  252. package/dist/route/protocol.d.ts +76 -0
  253. package/dist/route/protocol.js +16 -0
  254. package/dist/route/transport/http.d.ts +34 -0
  255. package/dist/route/transport/http.js +68 -0
  256. package/dist/route/transport/index.d.ts +41 -0
  257. package/dist/route/transport/index.js +4 -0
  258. package/dist/route/transport/websocket-channel.d.ts +57 -0
  259. package/dist/route/transport/websocket-channel.js +1 -0
  260. package/dist/route/transport/websocket.d.ts +56 -0
  261. package/dist/route/transport/websocket.js +370 -0
  262. package/dist/route.d.ts +1 -0
  263. package/dist/route.js +1 -0
  264. package/dist/schema/errors.d.ts +170 -0
  265. package/dist/schema/errors.js +131 -0
  266. package/dist/schema/events.d.ts +8123 -0
  267. package/dist/schema/events.js +550 -0
  268. package/dist/schema/ids.d.ts +17 -0
  269. package/dist/schema/ids.js +10 -0
  270. package/dist/schema/index.d.ts +5 -0
  271. package/dist/schema/index.js +5 -0
  272. package/dist/schema/messages.d.ts +646 -0
  273. package/dist/schema/messages.js +301 -0
  274. package/dist/schema/options.d.ts +159 -0
  275. package/dist/schema/options.js +189 -0
  276. package/dist/testing.d.ts +1693 -0
  277. package/dist/testing.js +129 -0
  278. package/dist/tool-history.d.ts +2 -0
  279. package/dist/tool-history.js +84 -0
  280. package/dist/tool-runtime.d.ts +15 -0
  281. package/dist/tool-runtime.js +62 -0
  282. package/dist/tool.d.ts +136 -0
  283. package/dist/tool.js +66 -0
  284. package/dist/utils/record.d.ts +2 -0
  285. package/dist/utils/record.js +2 -0
  286. package/dist/utils/sanitize.d.ts +1 -0
  287. package/dist/utils/sanitize.js +12 -0
  288. package/package.json +43 -10
@@ -0,0 +1,141 @@
1
+ import { Effect, Schema, Stream } from "effect";
2
+ import { Headers } from "effect/unstable/http";
3
+ import { Framing } from "../route/framing.js";
4
+ import { HttpTransport, WebSocketTransport, } from "../route/transport/index.js";
5
+ import * as ProviderShared from "./shared.js";
6
+ import { OpenResponses } from "./open-responses.js";
7
+ import { OpenResponsesContinuation } from "./open-responses-continuation.js";
8
+ const WebSocketResponseCreate = Schema.StructWithRest(Schema.Struct({ type: Schema.tag("response.create") }), [
9
+ Schema.Record(Schema.String, Schema.Unknown),
10
+ ]);
11
+ const decodeMessage = ProviderShared.validateWith(Schema.decodeUnknownEffect(WebSocketResponseCreate));
12
+ const encodeMessage = Schema.encodeSync(Schema.fromJsonString(WebSocketResponseCreate));
13
+ const message = (body) => Effect.gen(function* () {
14
+ if (!ProviderShared.isRecord(body))
15
+ return yield* ProviderShared.invalidRequest("Open Responses WebSocket body must be a JSON object");
16
+ const { stream: _stream, stream_options: _streamOptions, background: _background, ...request } = body;
17
+ const decoded = yield* decodeMessage({ ...request, type: "response.create" });
18
+ return { request: decoded, message: encodeMessage(decoded) };
19
+ });
20
+ const driver = (options, body) => {
21
+ let responseID;
22
+ let terminal = false;
23
+ return {
24
+ create: () => Effect.sync(() => {
25
+ responseID = undefined;
26
+ terminal = false;
27
+ return { message: body, mode: "full" };
28
+ }),
29
+ observe: (_create, frame) => Effect.gen(function* () {
30
+ const event = yield* OpenResponses.decodeChannelEvent(frame).pipe(Effect.mapError((cause) => ProviderShared.eventError(options.id, `Invalid ${options.name} WebSocket event`, frame, cause)));
31
+ if (terminal)
32
+ return yield* ProviderShared.eventError(options.id, `${options.name} emitted ${event.type} after a terminal event`, frame);
33
+ if (event.type === "error") {
34
+ terminal = true;
35
+ yield* OpenResponses.decodeKnownErrorEvent(event).pipe(Effect.mapError((cause) => ProviderShared.eventError(options.id, `${options.name} returned a malformed error event`, frame, cause)));
36
+ return {
37
+ type: "provider-failure",
38
+ error: OpenResponses.providerFailure(event, `${options.name} stream error`, frame),
39
+ };
40
+ }
41
+ if (event.type === "response.failed") {
42
+ terminal = true;
43
+ if (responseID && event.response?.id && event.response.id !== responseID)
44
+ return yield* ProviderShared.eventError(options.id, `${options.name} response ID changed during execution`, frame);
45
+ return {
46
+ type: "provider-failure",
47
+ error: OpenResponses.providerFailure(event, `${options.name} response failed`, frame),
48
+ };
49
+ }
50
+ if (event.type === "response.created") {
51
+ const created = event.response?.id;
52
+ if (responseID)
53
+ return yield* ProviderShared.eventError(options.id, `${options.name} emitted duplicate response.created`, frame);
54
+ if (!created)
55
+ return yield* ProviderShared.eventError(options.id, `${options.name} response.created is missing response.id`, frame);
56
+ responseID = created;
57
+ return { type: "frame", frame };
58
+ }
59
+ // Keepalives and provider notifications carry no response state and may precede response.created.
60
+ if (!event.type.startsWith("response."))
61
+ return { type: "frame", frame };
62
+ if (!responseID)
63
+ return yield* ProviderShared.eventError(options.id, `${options.name} emitted ${event.type} before response.created`, frame);
64
+ if (event.response?.id && event.response.id !== responseID)
65
+ return yield* ProviderShared.eventError(options.id, `${options.name} response ID changed during execution`, frame);
66
+ if (event.type === "response.completed") {
67
+ terminal = true;
68
+ return { type: "completed", frame };
69
+ }
70
+ if (event.type === "response.incomplete") {
71
+ terminal = true;
72
+ return { type: "incomplete", frame };
73
+ }
74
+ return { type: "frame", frame };
75
+ }),
76
+ };
77
+ };
78
+ export const transport = (options) => {
79
+ const http = HttpTransport.sseJson.with();
80
+ return {
81
+ id: http.id,
82
+ prepare: (input) => Effect.gen(function* () {
83
+ const parts = yield* HttpTransport.jsonRequestParts(input);
84
+ const headers = Headers.remove(options.headers?.(parts.headers) ?? parts.headers, "content-length");
85
+ const channel = input.webSocket && (options.enabled?.(parts.url) ?? true)
86
+ ? yield* Effect.gen(function* () {
87
+ const create = yield* message(parts.jsonBody);
88
+ const base = driver(options, create.message);
89
+ return {
90
+ url: yield* WebSocketTransport.toWebSocketUrl(options.url?.(parts.url) ?? parts.url),
91
+ headers,
92
+ rotateAfterMs: options.rotateAfterMs,
93
+ driver: OpenResponsesContinuation.driver({
94
+ id: options.id,
95
+ name: options.name,
96
+ request: create.request,
97
+ message: create.message,
98
+ base,
99
+ continuation: options.continuation,
100
+ }),
101
+ };
102
+ })
103
+ : undefined;
104
+ return {
105
+ http: {
106
+ request: ProviderShared.jsonPost({ url: parts.url, body: parts.bodyText, headers: parts.headers }),
107
+ framing: Framing.sse,
108
+ middleware: input.middleware,
109
+ },
110
+ channel,
111
+ };
112
+ }),
113
+ execute: (prepared, request, runtime, executeOptions) => Effect.gen(function* () {
114
+ if (!executeOptions?.webSocket || !prepared.channel)
115
+ return yield* http.execute(prepared.http, request, runtime);
116
+ let fallbackHttp;
117
+ const exchange = {
118
+ id: request.id ?? "request",
119
+ connect: {
120
+ url: prepared.channel.url,
121
+ headers: prepared.channel.headers,
122
+ rotateAfterMs: prepared.channel.rotateAfterMs,
123
+ },
124
+ fallback: () => Stream.unwrap(http.execute(prepared.http, request, runtime).pipe(Effect.map((execution) => {
125
+ fallbackHttp = execution.http;
126
+ return execution.frames;
127
+ }))),
128
+ driver: prepared.channel.driver,
129
+ };
130
+ const execution = yield* executeOptions.webSocket.execute(exchange);
131
+ return {
132
+ frames: execution.frames,
133
+ complete: execution.complete,
134
+ get http() {
135
+ return fallbackHttp ?? execution.http;
136
+ },
137
+ };
138
+ }),
139
+ };
140
+ };
141
+ export const OpenResponsesChannel = { transport };
@@ -0,0 +1,16 @@
1
+ import type { WebSocketChannelDriver } from "../route/transport/index.js";
2
+ /**
3
+ * Fields to send next to `previous_response_id` on an incremental step, or undefined to send the step in full.
4
+ * Whether omitted fields carry over from the continued response is provider behavior the route must know.
5
+ */
6
+ export type Shape = (request: Readonly<Record<string, unknown>>) => Readonly<Record<string, unknown>> | undefined;
7
+ export interface DriverInput {
8
+ readonly id: string;
9
+ readonly name: string;
10
+ readonly request: Readonly<Record<string, unknown>>;
11
+ readonly message: string;
12
+ readonly base: WebSocketChannelDriver;
13
+ readonly continuation?: Shape;
14
+ }
15
+ export declare const driver: (input: DriverInput) => WebSocketChannelDriver;
16
+ export * as OpenResponsesContinuation from "./open-responses-continuation.js";
@@ -0,0 +1,170 @@
1
+ import { AIError, TransportError } from "../schema/index.js";
2
+ import { Effect, Option, Schema } from "effect";
3
+ import * as ProviderShared from "./shared.js";
4
+ import { OpenResponses } from "./open-responses.js";
5
+ const PROTOCOL = "open-responses.websocket.v1";
6
+ const VERSION = 1;
7
+ const checkpointValue = (checkpoint) => {
8
+ if (checkpoint?.protocol !== PROTOCOL || !ProviderShared.isRecord(checkpoint.value))
9
+ return undefined;
10
+ if (checkpoint.value.version !== VERSION)
11
+ return undefined;
12
+ if (typeof checkpoint.value.responseID !== "string" || checkpoint.value.responseID.trim().length === 0)
13
+ return undefined;
14
+ if (!ProviderShared.isRecord(checkpoint.value.request) || !Array.isArray(checkpoint.value.output))
15
+ return undefined;
16
+ return {
17
+ version: VERSION,
18
+ responseID: checkpoint.value.responseID,
19
+ request: checkpoint.value.request,
20
+ output: checkpoint.value.output,
21
+ };
22
+ };
23
+ const canonical = (value) => {
24
+ if (value === undefined)
25
+ return "undefined";
26
+ if (Array.isArray(value))
27
+ return `[${value.map(canonical).join(",")}]`;
28
+ if (!ProviderShared.isRecord(value))
29
+ return ProviderShared.encodeJson(value);
30
+ return `{${Object.keys(value)
31
+ .filter((key) => value[key] !== undefined)
32
+ .sort()
33
+ .map((key) => `${ProviderShared.encodeJson(key)}:${canonical(value[key])}`)
34
+ .join(",")}}`;
35
+ };
36
+ const json = (value) => {
37
+ if (typeof value !== "string")
38
+ return value;
39
+ return Option.getOrElse(Schema.decodeUnknownOption(ProviderShared.Json)(value), () => value);
40
+ };
41
+ const comparable = (value) => {
42
+ if (!ProviderShared.isRecord(value))
43
+ return value;
44
+ if (value.type === "message" && value.role === "assistant")
45
+ return {
46
+ role: "assistant",
47
+ // Annotations and logprobs describe the response, not the text replayed in model input.
48
+ content: Array.isArray(value.content)
49
+ ? value.content.map((part) => ProviderShared.isRecord(part) && part.type === "output_text" ? { type: part.type, text: part.text } : part)
50
+ : value.content,
51
+ ...(value.phase === undefined ? {} : { phase: value.phase }),
52
+ };
53
+ if (value.type === "function_call")
54
+ return {
55
+ type: value.type,
56
+ call_id: value.call_id,
57
+ name: value.name,
58
+ arguments: json(value.arguments),
59
+ };
60
+ if (value.type === "reasoning")
61
+ return {
62
+ type: value.type,
63
+ summary: value.summary,
64
+ encrypted_content: value.encrypted_content,
65
+ };
66
+ return value;
67
+ };
68
+ const invariant = (request) => {
69
+ const { type: _type, input: _input, previous_response_id: _previousResponseID, ...rest } = request;
70
+ return rest;
71
+ };
72
+ const incremental = (request, checkpoint) => {
73
+ const input = request.input;
74
+ const previousInput = checkpoint.request.input;
75
+ if (!Array.isArray(input) || !Array.isArray(previousInput))
76
+ return undefined;
77
+ if (canonical(invariant(request)) !== canonical(invariant(checkpoint.request)))
78
+ return undefined;
79
+ const baseline = [...previousInput, ...checkpoint.output];
80
+ if (input.length <= baseline.length)
81
+ return undefined;
82
+ if (!baseline.every((item, index) => canonical(comparable(item)) === canonical(comparable(input[index]))))
83
+ return undefined;
84
+ return input.slice(baseline.length);
85
+ };
86
+ const code = (event) => event.code || event.error?.code || event.response?.error?.code || undefined;
87
+ const rejected = (observation, recovery) => ({
88
+ type: "rejected",
89
+ recovery,
90
+ error: new AIError({
91
+ reason: new TransportError({
92
+ message: observation.error.message,
93
+ body: observation.error.reason.body,
94
+ http: observation.error.reason.http,
95
+ cause: observation.error.reason.cause,
96
+ transport: "websocket",
97
+ operation: "read",
98
+ phase: "receive",
99
+ delivery: "rejected",
100
+ recovery,
101
+ }),
102
+ }),
103
+ });
104
+ export const driver = (input) => {
105
+ const { previous_response_id: _previousResponseID, ...request } = input.request;
106
+ const shape = input.continuation ?? ((fields) => fields);
107
+ let output = [];
108
+ return {
109
+ create: (checkpoint) => Effect.sync(() => {
110
+ output = [];
111
+ const previous = checkpointValue(checkpoint);
112
+ // Ask the route first: diffing the whole history is wasted when it declines the continuation.
113
+ const fields = previous ? shape(request) : undefined;
114
+ const delta = previous && fields ? incremental(request, previous) : undefined;
115
+ if (!previous || !fields || !delta)
116
+ return { message: ProviderShared.encodeJson(request), mode: "full" };
117
+ return {
118
+ message: ProviderShared.encodeJson({ ...fields, input: delta, previous_response_id: previous.responseID }),
119
+ mode: "incremental",
120
+ };
121
+ }),
122
+ observe: (create, frame) => Effect.gen(function* () {
123
+ const event = yield* OpenResponses.decodeChannelEvent(frame).pipe(Effect.mapError((cause) => ProviderShared.eventError(input.id, `Invalid ${input.name} WebSocket event`, frame, cause)));
124
+ const observation = yield* input.base.observe(create, frame);
125
+ if (event.type === "response.output_item.done" && event.item)
126
+ output.push(event.item);
127
+ if (observation.type === "provider-failure") {
128
+ const rejection = code(event);
129
+ if (rejection === "previous_response_not_found")
130
+ return rejected(observation, "retry-full");
131
+ if (rejection === "websocket_connection_limit_reached")
132
+ return rejected(observation, "rotate-and-retry-full");
133
+ // Only the continuation distinguishes an incremental send from a full one, so an unclassified
134
+ // invalid request there is retried full; Codex reports a stale previous_response_id that way, with
135
+ // no code. Classified failures such as context overflow keep their runner-owned recovery.
136
+ if (create.mode === "incremental" &&
137
+ observation.error.reason._tag === "InvalidRequest" &&
138
+ observation.error.reason.classification === undefined)
139
+ return rejected(observation, "retry-full");
140
+ }
141
+ if (observation.type !== "completed")
142
+ return observation;
143
+ // A trigger installs a different context window. Clear the append baseline, retaining the socket.
144
+ if (Array.isArray(request.input) &&
145
+ request.input.some((item) => ProviderShared.isRecord(item) && item.type === "compaction_trigger"))
146
+ return observation;
147
+ const responseID = event.response?.id;
148
+ if (!responseID || responseID.trim().length === 0)
149
+ return observation;
150
+ return {
151
+ ...observation,
152
+ checkpoint: {
153
+ protocol: PROTOCOL,
154
+ value: {
155
+ version: VERSION,
156
+ responseID,
157
+ request,
158
+ // Completion can re-encrypt reasoning. Callers replay the item already emitted by output_item.done.
159
+ output: event.response?.output?.length
160
+ ? event.response.output.map((item) => item.type === "reasoning" && item.id !== undefined
161
+ ? (output.find((done) => done.type === item.type && done.id === item.id) ?? item)
162
+ : item)
163
+ : output.slice(),
164
+ },
165
+ },
166
+ };
167
+ }),
168
+ };
169
+ };
170
+ export * as OpenResponsesContinuation from "./open-responses-continuation.js";