@opencode-ai/ai 0.0.0-beta-18387 → 0.0.0-beta-18593

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 (54) hide show
  1. package/README.md +29 -11
  2. package/dist/image.js +5 -4
  3. package/dist/llm.d.ts +2 -0
  4. package/dist/llm.js +4 -7
  5. package/dist/protocols/anthropic-messages.js +7 -5
  6. package/dist/protocols/bedrock-converse.d.ts +1 -0
  7. package/dist/protocols/bedrock-converse.js +17 -7
  8. package/dist/protocols/bedrock-event-stream.js +16 -6
  9. package/dist/protocols/gemini.d.ts +1 -0
  10. package/dist/protocols/gemini.js +13 -1
  11. package/dist/protocols/google-images.js +8 -18
  12. package/dist/protocols/open-responses-channel.js +20 -9
  13. package/dist/protocols/open-responses-continuation.js +9 -8
  14. package/dist/protocols/open-responses.d.ts +9 -3
  15. package/dist/protocols/open-responses.js +139 -78
  16. package/dist/protocols/openai-chat.d.ts +3 -1
  17. package/dist/protocols/openai-chat.js +39 -28
  18. package/dist/protocols/openai-compatible-chat.js +1 -2
  19. package/dist/protocols/openai-images.js +11 -16
  20. package/dist/protocols/openai-responses.js +1 -1
  21. package/dist/protocols/shared.d.ts +11 -7
  22. package/dist/protocols/shared.js +31 -18
  23. package/dist/protocols/utils/image-input.d.ts +4 -4
  24. package/dist/protocols/utils/image-input.js +6 -8
  25. package/dist/protocols/utils/lifecycle.d.ts +6 -2
  26. package/dist/protocols/utils/lifecycle.js +11 -7
  27. package/dist/protocols/utils/tool-stream.d.ts +6 -0
  28. package/dist/protocols/xai-images.js +7 -12
  29. package/dist/protocols/zai-images.js +5 -10
  30. package/dist/provider-error.d.ts +4 -4
  31. package/dist/provider-error.js +39 -55
  32. package/dist/providers/groq.d.ts +1 -1
  33. package/dist/providers/groq.js +1 -2
  34. package/dist/providers/openrouter.d.ts +1 -1
  35. package/dist/providers/openrouter.js +1 -2
  36. package/dist/route/auth.js +3 -5
  37. package/dist/route/client.d.ts +2 -0
  38. package/dist/route/client.js +29 -11
  39. package/dist/route/executor.d.ts +9 -5
  40. package/dist/route/executor.js +33 -66
  41. package/dist/route/framing.d.ts +6 -2
  42. package/dist/route/framing.js +5 -0
  43. package/dist/route/transport/http.js +7 -2
  44. package/dist/route/transport/index.d.ts +3 -1
  45. package/dist/route/transport/websocket-channel.d.ts +2 -1
  46. package/dist/route/transport/websocket.d.ts +2 -1
  47. package/dist/route/transport/websocket.js +70 -30
  48. package/dist/schema/errors.d.ts +71 -89
  49. package/dist/schema/errors.js +35 -87
  50. package/dist/schema/events.d.ts +2835 -351
  51. package/dist/schema/events.js +32 -14
  52. package/dist/testing.d.ts +41 -2
  53. package/dist/testing.js +39 -18
  54. package/package.json +5 -5
@@ -1,14 +1,14 @@
1
1
  import { Cause, Effect, Queue, Stream } from "effect";
2
2
  import { Headers } from "effect/unstable/http";
3
3
  import { Socket } from "effect/unstable/socket";
4
- import { AIError, TransportReason } from "../../schema/index.js";
4
+ import { AIError, AIErrorReason, TransportError, } from "../../schema/index.js";
5
5
  import * as HttpTransport from "./http.js";
6
6
  const MAX_FRAME_BYTES = 16 * 1024 * 1024;
7
- const transportError = (method, message, input) => new AIError({
8
- module: "WebSocketConnector",
9
- method,
10
- reason: new TransportReason({
7
+ const transportError = (message, input) => new AIError({
8
+ reason: new TransportError({
11
9
  message,
10
+ body: input.body,
11
+ cause: input.cause,
12
12
  transport: "websocket",
13
13
  operation: input.operation,
14
14
  url: input.url,
@@ -19,18 +19,12 @@ const transportError = (method, message, input) => new AIError({
19
19
  });
20
20
  const annotateTransportError = (error, input) => error.reason._tag === "Transport"
21
21
  ? new AIError({
22
- module: error.module,
23
- method: error.method,
24
- reason: new TransportReason({
22
+ reason: new TransportError({
23
+ ...error.reason,
25
24
  message: error.reason.message,
26
- transport: error.reason.transport,
27
- operation: error.reason.operation,
28
- code: error.reason.code,
29
- url: error.reason.url,
30
- http: error.reason.http,
25
+ cause: error.reason.cause,
31
26
  phase: input.phase,
32
27
  delivery: input.delivery,
33
- recovery: error.reason.recovery,
34
28
  }),
35
29
  })
36
30
  : error;
@@ -52,7 +46,7 @@ const waitOpen = (ws, input) => {
52
46
  if (ws.readyState === globalThis.WebSocket.OPEN)
53
47
  return Effect.void;
54
48
  if (ws.readyState === globalThis.WebSocket.CLOSING || ws.readyState === globalThis.WebSocket.CLOSED) {
55
- return Effect.fail(transportError("open", `WebSocket closed before opening (state ${ws.readyState})`, {
49
+ return Effect.fail(transportError(`WebSocket closed before opening (state ${ws.readyState})`, {
56
50
  url: input.url,
57
51
  operation: "request",
58
52
  code: "closed",
@@ -78,7 +72,8 @@ const waitOpen = (ws, input) => {
78
72
  };
79
73
  const onError = (event) => {
80
74
  cleanup();
81
- resume(Effect.fail(transportError("open", `Failed to open WebSocket: ${eventMessage(event)}`, {
75
+ resume(Effect.fail(transportError(`Failed to open WebSocket: ${eventMessage(event)}`, {
76
+ cause: "error" in event ? (event.error ?? event) : event,
82
77
  url: input.url,
83
78
  operation: "request",
84
79
  phase: "connect",
@@ -87,7 +82,9 @@ const waitOpen = (ws, input) => {
87
82
  };
88
83
  const onClose = (event) => {
89
84
  cleanup();
90
- resume(Effect.fail(transportError("open", `WebSocket closed before opening with code ${event.code}`, {
85
+ resume(Effect.fail(transportError(`WebSocket closed before opening with code ${event.code}`, {
86
+ body: event.reason,
87
+ cause: event,
91
88
  url: input.url,
92
89
  operation: "request",
93
90
  code: String(event.code),
@@ -114,7 +111,8 @@ export const toWebSocketUrl = (value) => Effect.try({
114
111
  }
115
112
  throw new Error(`Unsupported WebSocket URL protocol ${url.protocol}`);
116
113
  },
117
- catch: (error) => transportError("prepare", error instanceof Error ? error.message : "Invalid WebSocket URL", {
114
+ catch: (error) => transportError(error instanceof Error ? error.message : "Invalid WebSocket URL", {
115
+ cause: error,
118
116
  url: value,
119
117
  operation: "request",
120
118
  code: "invalid-url",
@@ -131,7 +129,8 @@ export const open = (input) => Effect.gen(function* () {
131
129
  constructor(input.url, {
132
130
  headers: input.headers,
133
131
  }),
134
- catch: (error) => transportError("open", error instanceof Error ? error.message : "Failed to construct WebSocket", {
132
+ catch: (error) => transportError(error instanceof Error ? error.message : "Failed to construct WebSocket", {
133
+ cause: error,
135
134
  url: input.url,
136
135
  operation: "request",
137
136
  phase: "connect",
@@ -147,7 +146,8 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
147
146
  const rejectOversized = (message) => {
148
147
  if (!oversized(message))
149
148
  return false;
150
- Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", "WebSocket message exceeds the 16 MiB limit", {
149
+ Queue.failCauseUnsafe(messages, Cause.fail(transportError("WebSocket message exceeds the 16 MiB limit", {
150
+ body: typeof message === "string" ? message : new TextDecoder().decode(message),
151
151
  url: input.url,
152
152
  operation: "read",
153
153
  code: "message-too-large",
@@ -162,7 +162,8 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
162
162
  return;
163
163
  if (Queue.offerUnsafe(messages, message))
164
164
  return;
165
- Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", "WebSocket inbound queue overflow", {
165
+ Queue.failCauseUnsafe(messages, Cause.fail(transportError("WebSocket inbound queue overflow", {
166
+ body: typeof message === "string" ? message : new TextDecoder().decode(message),
166
167
  url: input.url,
167
168
  operation: "read",
168
169
  code: "queue-overflow",
@@ -175,7 +176,8 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
175
176
  const binary = binaryMessage(event.data);
176
177
  if (binary)
177
178
  return offer(binary);
178
- Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", "Unsupported WebSocket message payload", {
179
+ Queue.failCauseUnsafe(messages, Cause.fail(transportError("Unsupported WebSocket message payload", {
180
+ cause: event,
179
181
  url: input.url,
180
182
  operation: "read",
181
183
  code: "message",
@@ -183,7 +185,8 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
183
185
  })));
184
186
  };
185
187
  const onError = (event) => {
186
- Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", `WebSocket error: ${eventMessage(event)}`, {
188
+ Queue.failCauseUnsafe(messages, Cause.fail(transportError(`WebSocket error: ${eventMessage(event)}`, {
189
+ cause: "error" in event ? (event.error ?? event) : event,
187
190
  url: input.url,
188
191
  operation: "read",
189
192
  code: "message",
@@ -191,7 +194,9 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
191
194
  })));
192
195
  };
193
196
  const onClose = (event) => {
194
- Queue.failCauseUnsafe(messages, Cause.fail(transportError("message", `WebSocket closed with code ${event.code}`, {
197
+ Queue.failCauseUnsafe(messages, Cause.fail(transportError(`WebSocket closed with code ${event.code}`, {
198
+ body: event.reason,
199
+ cause: event,
195
200
  url: input.url,
196
201
  operation: "read",
197
202
  code: String(event.code),
@@ -209,7 +214,7 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
209
214
  return {
210
215
  sendText: (message) => Effect.suspend(() => {
211
216
  if (ws.readyState !== globalThis.WebSocket.OPEN)
212
- return Effect.fail(transportError("sendText", `WebSocket is not open (state ${ws.readyState})`, {
217
+ return Effect.fail(transportError(`WebSocket is not open (state ${ws.readyState})`, {
213
218
  url: input.url,
214
219
  operation: "write",
215
220
  phase: "send",
@@ -217,7 +222,8 @@ export const fromWebSocket = (ws, input) => Effect.gen(function* () {
217
222
  }));
218
223
  return Effect.try({
219
224
  try: () => ws.send(message),
220
- catch: (error) => transportError("sendText", error instanceof Error ? error.message : "Failed to send WebSocket message", {
225
+ catch: (error) => transportError(error instanceof Error ? error.message : "Failed to send WebSocket message", {
226
+ cause: error,
221
227
  url: input.url,
222
228
  operation: "write",
223
229
  phase: "send",
@@ -246,17 +252,51 @@ export const makeDirect = (connector) => ({
246
252
  .open(exchange.connect)
247
253
  .pipe(Effect.mapError((error) => annotateTransportError(error, { phase: "connect", delivery: "not-sent" }))), (connection) => connection.close);
248
254
  const create = yield* exchange.driver.create(undefined);
249
- yield* connection.sendText(create.message);
255
+ yield* connection.sendText(create.message).pipe(Effect.mapError((error) => new AIError({
256
+ reason: AIErrorReason.make({
257
+ ...error.reason,
258
+ message: error.reason.message,
259
+ cause: error.reason.cause,
260
+ http: error.reason.http ?? connection.http,
261
+ }),
262
+ })));
250
263
  const decoder = new TextDecoder();
251
264
  let observed = false;
252
265
  return {
266
+ http: connection.http,
253
267
  frames: connection.messages.pipe(Stream.map((message) => {
254
268
  observed = true;
255
269
  return messageText(message, decoder);
256
270
  }), Stream.mapError((error) => annotateTransportError(error, {
257
271
  phase: error.reason._tag === "Transport" && error.reason.phase === "close" ? "close" : "receive",
258
272
  delivery: observed ? "accepted" : "ambiguous",
259
- })), Stream.mapEffect((frame) => exchange.driver.observe(create, frame)), Stream.takeUntil(observationTerminal), Stream.mapEffect(observationFrame)),
273
+ })), Stream.mapEffect((frame) => exchange.driver.observe(create, frame).pipe(Effect.mapError((error) => new AIError({
274
+ reason: AIErrorReason.make({
275
+ ...error.reason,
276
+ message: error.reason.message,
277
+ cause: error.reason.cause,
278
+ body: frame,
279
+ }),
280
+ })), Effect.map((observation) => "error" in observation
281
+ ? {
282
+ ...observation,
283
+ error: new AIError({
284
+ reason: AIErrorReason.make({
285
+ ...observation.error.reason,
286
+ message: observation.error.reason.message,
287
+ cause: observation.error.reason.cause,
288
+ body: frame,
289
+ }),
290
+ }),
291
+ }
292
+ : observation))), Stream.takeUntil(observationTerminal), Stream.mapEffect(observationFrame), Stream.mapError((error) => new AIError({
293
+ reason: AIErrorReason.make({
294
+ ...error.reason,
295
+ message: error.reason.message,
296
+ cause: error.reason.cause,
297
+ http: error.reason.http ?? connection.http,
298
+ }),
299
+ }))),
260
300
  complete: Effect.void,
261
301
  };
262
302
  }),
@@ -283,7 +323,7 @@ export const json = (input) => ({
283
323
  execute: (prepared, request, _runtime, options) => {
284
324
  const webSocket = options?.webSocket;
285
325
  if (!webSocket) {
286
- return Effect.fail(transportError("json", "WebSocket JSON transport requires StreamOptions.webSocket", {
326
+ return Effect.fail(transportError("WebSocket JSON transport requires StreamOptions.webSocket", {
287
327
  url: prepared.url,
288
328
  operation: "request",
289
329
  code: "unavailable",
@@ -298,7 +338,7 @@ export const json = (input) => ({
298
338
  const exchange = {
299
339
  id: request.id ?? "request",
300
340
  connect: { url: prepared.url, headers: prepared.headers },
301
- fallback: () => Stream.fail(transportError("fallback", "WebSocket JSON transport does not provide HTTP fallback", {
341
+ fallback: () => Stream.fail(transportError("WebSocket JSON transport does not provide HTTP fallback", {
302
342
  url: prepared.url,
303
343
  operation: "request",
304
344
  code: "websocket",
@@ -2,18 +2,12 @@ import { Schema } from "effect";
2
2
  import { Tool } from "@opencode-ai/schema/tool";
3
3
  export declare const ProviderFailureClassification: Schema.Literals<readonly ["context-overflow", "payload-too-large"]>;
4
4
  export type ProviderFailureClassification = typeof ProviderFailureClassification.Type;
5
- declare const HttpRequestDetails_base: Schema.Class<HttpRequestDetails, Schema.Struct<{
6
- readonly method: Schema.String;
5
+ declare const HttpContext_base: Schema.Class<HttpContext, Schema.Struct<{
7
6
  readonly url: Schema.String;
7
+ readonly status: Schema.Int;
8
8
  readonly headers: Schema.$Record<Schema.String, Schema.String>;
9
9
  }>, {}>;
10
- export declare class HttpRequestDetails extends HttpRequestDetails_base {
11
- }
12
- declare const HttpResponseDetails_base: Schema.Class<HttpResponseDetails, Schema.Struct<{
13
- readonly status: Schema.Number;
14
- readonly headers: Schema.$Record<Schema.String, Schema.String>;
15
- }>, {}>;
16
- export declare class HttpResponseDetails extends HttpResponseDetails_base {
10
+ export declare class HttpContext extends HttpContext_base {
17
11
  }
18
12
  declare const HttpRateLimitDetails_base: Schema.Class<HttpRateLimitDetails, Schema.Struct<{
19
13
  readonly retryAfterMs: Schema.optional<Schema.Number>;
@@ -23,126 +17,114 @@ declare const HttpRateLimitDetails_base: Schema.Class<HttpRateLimitDetails, Sche
23
17
  }>, {}>;
24
18
  export declare class HttpRateLimitDetails extends HttpRateLimitDetails_base {
25
19
  }
26
- declare const HttpContext_base: Schema.Class<HttpContext, Schema.Struct<{
27
- readonly request: typeof HttpRequestDetails;
28
- readonly response: Schema.optional<typeof HttpResponseDetails>;
29
- readonly body: Schema.optional<Schema.String>;
30
- readonly bodyTruncated: Schema.optional<Schema.Boolean>;
31
- readonly rateLimit: Schema.optional<typeof HttpRateLimitDetails>;
32
- }>, {}>;
33
- export declare class HttpContext extends HttpContext_base {
34
- }
35
- declare const InvalidRequestReason_base: Schema.Class<InvalidRequestReason, Schema.Struct<{
36
- readonly _tag: Schema.tag<"InvalidRequest">;
37
- readonly message: Schema.String;
20
+ declare const InvalidRequestError_base: Schema.Class<InvalidRequestError, Schema.TaggedStruct<"InvalidRequest", {
38
21
  readonly parameter: Schema.optional<Schema.String>;
39
22
  readonly classification: Schema.optional<Schema.Literals<readonly ["context-overflow", "payload-too-large"]>>;
40
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
23
+ readonly message: Schema.String;
24
+ readonly body: Schema.optional<Schema.String>;
41
25
  readonly http: Schema.optional<typeof HttpContext>;
42
- }>, {}>;
43
- export declare class InvalidRequestReason extends InvalidRequestReason_base {
26
+ readonly cause: Schema.optional<Schema.Defect>;
27
+ }>, import("effect/Cause").YieldableError>;
28
+ export declare class InvalidRequestError extends InvalidRequestError_base {
44
29
  }
45
- declare const NoRouteReason_base: Schema.Class<NoRouteReason, Schema.Struct<{
46
- readonly _tag: Schema.tag<"NoRoute">;
30
+ declare const NoRouteError_base: Schema.Class<NoRouteError, Schema.TaggedStruct<"NoRoute", {
47
31
  readonly route: Schema.String;
48
32
  readonly provider: Schema.brand<Schema.String, "AI.ProviderID">;
49
33
  readonly model: Schema.brand<Schema.String, "AI.ModelID">;
50
- }>, {}>;
51
- export declare class NoRouteReason extends NoRouteReason_base {
52
- get message(): string;
53
- }
54
- declare const AuthenticationReason_base: Schema.Class<AuthenticationReason, Schema.Struct<{
55
- readonly _tag: Schema.tag<"Authentication">;
56
34
  readonly message: Schema.String;
57
- readonly kind: Schema.Literals<readonly ["missing", "invalid", "expired", "insufficient-permissions", "unknown"]>;
58
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
35
+ readonly body: Schema.optional<Schema.String>;
59
36
  readonly http: Schema.optional<typeof HttpContext>;
60
- }>, {}>;
61
- export declare class AuthenticationReason extends AuthenticationReason_base {
37
+ readonly cause: Schema.optional<Schema.Defect>;
38
+ }>, import("effect/Cause").YieldableError>;
39
+ export declare class NoRouteError extends NoRouteError_base {
62
40
  }
63
- declare const RateLimitReason_base: Schema.Class<RateLimitReason, Schema.Struct<{
64
- readonly _tag: Schema.tag<"RateLimit">;
65
- readonly message: Schema.String;
41
+ declare const AuthenticationError_base: Schema.Class<AuthenticationError, Schema.TaggedStruct<"Authentication", {
42
+ message: Schema.String;
43
+ body: Schema.optional<Schema.String>;
44
+ http: Schema.optional<typeof HttpContext>;
45
+ cause: Schema.optional<Schema.Defect>;
46
+ }>, import("effect/Cause").YieldableError>;
47
+ export declare class AuthenticationError extends AuthenticationError_base {
48
+ }
49
+ declare const RateLimitError_base: Schema.Class<RateLimitError, Schema.TaggedStruct<"RateLimit", {
66
50
  readonly retryAfterMs: Schema.optional<Schema.Number>;
67
51
  readonly rateLimit: Schema.optional<typeof HttpRateLimitDetails>;
68
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
69
- readonly http: Schema.optional<typeof HttpContext>;
70
- }>, {}>;
71
- export declare class RateLimitReason extends RateLimitReason_base {
72
- }
73
- declare const QuotaExceededReason_base: Schema.Class<QuotaExceededReason, Schema.Struct<{
74
- readonly _tag: Schema.tag<"QuotaExceeded">;
75
52
  readonly message: Schema.String;
76
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
53
+ readonly body: Schema.optional<Schema.String>;
77
54
  readonly http: Schema.optional<typeof HttpContext>;
78
- }>, {}>;
79
- export declare class QuotaExceededReason extends QuotaExceededReason_base {
55
+ readonly cause: Schema.optional<Schema.Defect>;
56
+ }>, import("effect/Cause").YieldableError>;
57
+ export declare class RateLimitError extends RateLimitError_base {
80
58
  }
81
- declare const ContentPolicyReason_base: Schema.Class<ContentPolicyReason, Schema.Struct<{
82
- readonly _tag: Schema.tag<"ContentPolicy">;
83
- readonly message: Schema.String;
84
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
85
- readonly http: Schema.optional<typeof HttpContext>;
86
- }>, {}>;
87
- export declare class ContentPolicyReason extends ContentPolicyReason_base {
59
+ declare const QuotaExceededError_base: Schema.Class<QuotaExceededError, Schema.TaggedStruct<"QuotaExceeded", {
60
+ message: Schema.String;
61
+ body: Schema.optional<Schema.String>;
62
+ http: Schema.optional<typeof HttpContext>;
63
+ cause: Schema.optional<Schema.Defect>;
64
+ }>, import("effect/Cause").YieldableError>;
65
+ export declare class QuotaExceededError extends QuotaExceededError_base {
88
66
  }
89
- declare const ProviderInternalReason_base: Schema.Class<ProviderInternalReason, Schema.Struct<{
90
- readonly _tag: Schema.tag<"ProviderInternal">;
91
- readonly message: Schema.String;
92
- readonly status: Schema.optional<Schema.Number>;
67
+ declare const ContentPolicyError_base: Schema.Class<ContentPolicyError, Schema.TaggedStruct<"ContentPolicy", {
68
+ message: Schema.String;
69
+ body: Schema.optional<Schema.String>;
70
+ http: Schema.optional<typeof HttpContext>;
71
+ cause: Schema.optional<Schema.Defect>;
72
+ }>, import("effect/Cause").YieldableError>;
73
+ export declare class ContentPolicyError extends ContentPolicyError_base {
74
+ }
75
+ declare const ProviderInternalError_base: Schema.Class<ProviderInternalError, Schema.TaggedStruct<"ProviderInternal", {
93
76
  readonly retryAfterMs: Schema.optional<Schema.Number>;
94
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
77
+ readonly message: Schema.String;
78
+ readonly body: Schema.optional<Schema.String>;
95
79
  readonly http: Schema.optional<typeof HttpContext>;
96
- }>, {}>;
97
- export declare class ProviderInternalReason extends ProviderInternalReason_base {
80
+ readonly cause: Schema.optional<Schema.Defect>;
81
+ }>, import("effect/Cause").YieldableError>;
82
+ export declare class ProviderInternalError extends ProviderInternalError_base {
98
83
  }
99
84
  export declare const TransportType: Schema.Literals<readonly ["http", "websocket"]>;
100
85
  export type TransportType = typeof TransportType.Type;
101
86
  export declare const TransportOperation: Schema.Literals<readonly ["request", "read", "write"]>;
102
87
  export type TransportOperation = typeof TransportOperation.Type;
103
- declare const TransportReason_base: Schema.Class<TransportReason, Schema.Struct<{
104
- readonly _tag: Schema.tag<"Transport">;
105
- readonly message: Schema.String;
88
+ declare const TransportError_base: Schema.Class<TransportError, Schema.TaggedStruct<"Transport", {
106
89
  readonly transport: Schema.Literals<readonly ["http", "websocket"]>;
107
90
  readonly operation: Schema.Literals<readonly ["request", "read", "write"]>;
108
91
  readonly code: Schema.optional<Schema.String>;
109
92
  readonly url: Schema.optional<Schema.String>;
110
- readonly http: Schema.optional<typeof HttpContext>;
111
93
  readonly phase: Schema.optional<Schema.Literals<readonly ["prepare", "queue", "connect", "send", "receive", "decode", "complete", "fallback", "close"]>>;
112
94
  readonly delivery: Schema.optional<Schema.Literals<readonly ["not-sent", "rejected", "ambiguous", "accepted"]>>;
113
95
  readonly recovery: Schema.optional<Schema.Literals<readonly ["retry-connect", "retry-full", "rotate-and-retry-full", "fallback-http", "fail"]>>;
114
- }>, {}>;
115
- export declare class TransportReason extends TransportReason_base {
116
- }
117
- declare const InvalidProviderOutputReason_base: Schema.Class<InvalidProviderOutputReason, Schema.Struct<{
118
- readonly _tag: Schema.tag<"InvalidProviderOutput">;
119
96
  readonly message: Schema.String;
97
+ readonly body: Schema.optional<Schema.String>;
98
+ readonly http: Schema.optional<typeof HttpContext>;
99
+ readonly cause: Schema.optional<Schema.Defect>;
100
+ }>, import("effect/Cause").YieldableError>;
101
+ export declare class TransportError extends TransportError_base {
102
+ }
103
+ declare const InvalidProviderOutputError_base: Schema.Class<InvalidProviderOutputError, Schema.TaggedStruct<"InvalidProviderOutput", {
120
104
  readonly classification: Schema.optional<Schema.Literals<readonly ["incomplete-stream"]>>;
121
105
  readonly route: Schema.optional<Schema.String>;
122
- readonly raw: Schema.optional<Schema.String>;
123
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
124
- }>, {}>;
125
- export declare class InvalidProviderOutputReason extends InvalidProviderOutputReason_base {
126
- }
127
- declare const UnknownProviderReason_base: Schema.Class<UnknownProviderReason, Schema.Struct<{
128
- readonly _tag: Schema.tag<"UnknownProvider">;
129
106
  readonly message: Schema.String;
130
- readonly status: Schema.optional<Schema.Number>;
131
- readonly providerMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>>;
107
+ readonly body: Schema.optional<Schema.String>;
132
108
  readonly http: Schema.optional<typeof HttpContext>;
133
- }>, {}>;
134
- export declare class UnknownProviderReason extends UnknownProviderReason_base {
109
+ readonly cause: Schema.optional<Schema.Defect>;
110
+ }>, import("effect/Cause").YieldableError>;
111
+ export declare class InvalidProviderOutputError extends InvalidProviderOutputError_base {
135
112
  }
136
- export declare const AIErrorReason: Schema.toTaggedUnion<"_tag", readonly [typeof InvalidRequestReason, typeof NoRouteReason, typeof AuthenticationReason, typeof RateLimitReason, typeof QuotaExceededReason, typeof ContentPolicyReason, typeof ProviderInternalReason, typeof TransportReason, typeof InvalidProviderOutputReason, typeof UnknownProviderReason]>;
113
+ declare const UnknownProviderError_base: Schema.Class<UnknownProviderError, Schema.TaggedStruct<"UnknownProvider", {
114
+ message: Schema.String;
115
+ body: Schema.optional<Schema.String>;
116
+ http: Schema.optional<typeof HttpContext>;
117
+ cause: Schema.optional<Schema.Defect>;
118
+ }>, import("effect/Cause").YieldableError>;
119
+ export declare class UnknownProviderError extends UnknownProviderError_base {
120
+ }
121
+ export declare const AIErrorReason: Schema.toTaggedUnion<"_tag", readonly [typeof InvalidRequestError, typeof NoRouteError, typeof AuthenticationError, typeof RateLimitError, typeof QuotaExceededError, typeof ContentPolicyError, typeof ProviderInternalError, typeof TransportError, typeof InvalidProviderOutputError, typeof UnknownProviderError]>;
137
122
  export type AIErrorReason = Schema.Schema.Type<typeof AIErrorReason>;
138
123
  declare const AIError_base: Schema.Class<AIError, Schema.TaggedStruct<"AI.Error", {
139
- readonly module: Schema.String;
140
- readonly method: Schema.String;
141
- readonly reason: Schema.toTaggedUnion<"_tag", readonly [typeof InvalidRequestReason, typeof NoRouteReason, typeof AuthenticationReason, typeof RateLimitReason, typeof QuotaExceededReason, typeof ContentPolicyReason, typeof ProviderInternalReason, typeof TransportReason, typeof InvalidProviderOutputReason, typeof UnknownProviderReason]>;
142
- readonly body: Schema.optional<Schema.String>;
124
+ readonly reason: Schema.toTaggedUnion<"_tag", readonly [typeof InvalidRequestError, typeof NoRouteError, typeof AuthenticationError, typeof RateLimitError, typeof QuotaExceededError, typeof ContentPolicyError, typeof ProviderInternalError, typeof TransportError, typeof InvalidProviderOutputError, typeof UnknownProviderError]>;
143
125
  }>, import("effect/Cause").YieldableError>;
144
126
  export declare class AIError extends AIError_base {
145
- readonly cause: InvalidRequestReason | NoRouteReason | AuthenticationReason | RateLimitReason | QuotaExceededReason | ContentPolicyReason | ProviderInternalReason | TransportReason | InvalidProviderOutputReason | UnknownProviderReason;
127
+ readonly cause: InvalidRequestError | NoRouteError | AuthenticationError | RateLimitError | QuotaExceededError | ContentPolicyError | ProviderInternalError | TransportError | InvalidProviderOutputError | UnknownProviderError;
146
128
  get message(): string;
147
129
  }
148
130
  /**
@@ -1,16 +1,10 @@
1
1
  import { Schema } from "effect";
2
2
  import { Tool } from "@opencode-ai/schema/tool";
3
3
  import { ModelID, ProviderID, RouteID } from "./ids.js";
4
- import { ProviderMetadata } from "./messages.js";
5
4
  export const ProviderFailureClassification = Schema.Literals(["context-overflow", "payload-too-large"]);
6
- export class HttpRequestDetails extends Schema.Class("AI.HttpRequestDetails")({
7
- method: Schema.String,
5
+ export class HttpContext extends Schema.Class("AI.HttpContext")({
8
6
  url: Schema.String,
9
- headers: Schema.Record(Schema.String, Schema.String),
10
- }) {
11
- }
12
- export class HttpResponseDetails extends Schema.Class("AI.HttpResponseDetails")({
13
- status: Schema.Number,
7
+ status: Schema.Int.check(Schema.isBetween({ minimum: 100, maximum: 599 })),
14
8
  headers: Schema.Record(Schema.String, Schema.String),
15
9
  }) {
16
10
  }
@@ -21,128 +15,82 @@ export class HttpRateLimitDetails extends Schema.Class("AI.HttpRateLimitDetails"
21
15
  reset: Schema.optional(Schema.Record(Schema.String, Schema.String)),
22
16
  }) {
23
17
  }
24
- export class HttpContext extends Schema.Class("AI.HttpContext")({
25
- request: HttpRequestDetails,
26
- response: Schema.optional(HttpResponseDetails),
27
- body: Schema.optional(Schema.String),
28
- bodyTruncated: Schema.optional(Schema.Boolean),
29
- rateLimit: Schema.optional(HttpRateLimitDetails),
30
- }) {
31
- }
32
- export class InvalidRequestReason extends Schema.Class("AI.Error.InvalidRequest")({
33
- _tag: Schema.tag("InvalidRequest"),
18
+ const ReasonFields = {
34
19
  message: Schema.String,
20
+ // Preserve the complete original response or triggering event before decoding narrows it.
21
+ body: Schema.optional(Schema.String),
22
+ http: Schema.optional(HttpContext),
23
+ cause: Schema.optional(Schema.Defect({ includeStack: true })),
24
+ };
25
+ export class InvalidRequestError extends Schema.TaggedError("AI.Error.InvalidRequest")("InvalidRequest", {
26
+ ...ReasonFields,
35
27
  parameter: Schema.optional(Schema.String),
36
28
  classification: Schema.optional(ProviderFailureClassification),
37
- providerMetadata: Schema.optional(ProviderMetadata),
38
- http: Schema.optional(HttpContext),
39
29
  }) {
40
30
  }
41
- export class NoRouteReason extends Schema.Class("AI.Error.NoRoute")({
42
- _tag: Schema.tag("NoRoute"),
31
+ export class NoRouteError extends Schema.TaggedError("AI.Error.NoRoute")("NoRoute", {
32
+ ...ReasonFields,
43
33
  route: RouteID,
44
34
  provider: ProviderID,
45
35
  model: ModelID,
46
36
  }) {
47
- get message() {
48
- return `No AI route for ${this.provider}/${this.model} using ${this.route}`;
49
- }
50
37
  }
51
- export class AuthenticationReason extends Schema.Class("AI.Error.Authentication")({
52
- _tag: Schema.tag("Authentication"),
53
- message: Schema.String,
54
- kind: Schema.Literals(["missing", "invalid", "expired", "insufficient-permissions", "unknown"]),
55
- providerMetadata: Schema.optional(ProviderMetadata),
56
- http: Schema.optional(HttpContext),
57
- }) {
38
+ export class AuthenticationError extends Schema.TaggedError("AI.Error.Authentication")("Authentication", ReasonFields) {
58
39
  }
59
- export class RateLimitReason extends Schema.Class("AI.Error.RateLimit")({
60
- _tag: Schema.tag("RateLimit"),
61
- message: Schema.String,
40
+ export class RateLimitError extends Schema.TaggedError("AI.Error.RateLimit")("RateLimit", {
41
+ ...ReasonFields,
62
42
  retryAfterMs: Schema.optional(Schema.Number),
63
43
  rateLimit: Schema.optional(HttpRateLimitDetails),
64
- providerMetadata: Schema.optional(ProviderMetadata),
65
- http: Schema.optional(HttpContext),
66
44
  }) {
67
45
  }
68
- export class QuotaExceededReason extends Schema.Class("AI.Error.QuotaExceeded")({
69
- _tag: Schema.tag("QuotaExceeded"),
70
- message: Schema.String,
71
- providerMetadata: Schema.optional(ProviderMetadata),
72
- http: Schema.optional(HttpContext),
73
- }) {
46
+ export class QuotaExceededError extends Schema.TaggedError("AI.Error.QuotaExceeded")("QuotaExceeded", ReasonFields) {
74
47
  }
75
- export class ContentPolicyReason extends Schema.Class("AI.Error.ContentPolicy")({
76
- _tag: Schema.tag("ContentPolicy"),
77
- message: Schema.String,
78
- providerMetadata: Schema.optional(ProviderMetadata),
79
- http: Schema.optional(HttpContext),
80
- }) {
48
+ export class ContentPolicyError extends Schema.TaggedError("AI.Error.ContentPolicy")("ContentPolicy", ReasonFields) {
81
49
  }
82
- export class ProviderInternalReason extends Schema.Class("AI.Error.ProviderInternal")({
83
- _tag: Schema.tag("ProviderInternal"),
84
- message: Schema.String,
85
- status: Schema.optional(Schema.Number),
50
+ export class ProviderInternalError extends Schema.TaggedError("AI.Error.ProviderInternal")("ProviderInternal", {
51
+ ...ReasonFields,
86
52
  retryAfterMs: Schema.optional(Schema.Number),
87
- providerMetadata: Schema.optional(ProviderMetadata),
88
- http: Schema.optional(HttpContext),
89
53
  }) {
90
54
  }
91
55
  export const TransportType = Schema.Literals(["http", "websocket"]);
92
56
  export const TransportOperation = Schema.Literals(["request", "read", "write"]);
93
- export class TransportReason extends Schema.Class("AI.Error.Transport")({
94
- _tag: Schema.tag("Transport"),
95
- message: Schema.String,
57
+ export class TransportError extends Schema.TaggedError("AI.Error.Transport")("Transport", {
58
+ ...ReasonFields,
96
59
  transport: TransportType,
97
60
  operation: TransportOperation,
98
61
  code: Schema.optional(Schema.String),
99
62
  url: Schema.optional(Schema.String),
100
- http: Schema.optional(HttpContext),
101
63
  phase: Schema.optional(Schema.Literals(["prepare", "queue", "connect", "send", "receive", "decode", "complete", "fallback", "close"])),
102
64
  delivery: Schema.optional(Schema.Literals(["not-sent", "rejected", "ambiguous", "accepted"])),
103
65
  recovery: Schema.optional(Schema.Literals(["retry-connect", "retry-full", "rotate-and-retry-full", "fallback-http", "fail"])),
104
66
  }) {
105
67
  }
106
- export class InvalidProviderOutputReason extends Schema.Class("AI.Error.InvalidProviderOutput")({
107
- _tag: Schema.tag("InvalidProviderOutput"),
108
- message: Schema.String,
68
+ export class InvalidProviderOutputError extends Schema.TaggedError("AI.Error.InvalidProviderOutput")("InvalidProviderOutput", {
69
+ ...ReasonFields,
109
70
  classification: Schema.optional(Schema.Literals(["incomplete-stream"])),
110
71
  route: Schema.optional(Schema.String),
111
- raw: Schema.optional(Schema.String),
112
- providerMetadata: Schema.optional(ProviderMetadata),
113
72
  }) {
114
73
  }
115
- export class UnknownProviderReason extends Schema.Class("AI.Error.UnknownProvider")({
116
- _tag: Schema.tag("UnknownProvider"),
117
- message: Schema.String,
118
- status: Schema.optional(Schema.Number),
119
- providerMetadata: Schema.optional(ProviderMetadata),
120
- http: Schema.optional(HttpContext),
121
- }) {
74
+ export class UnknownProviderError extends Schema.TaggedError("AI.Error.UnknownProvider")("UnknownProvider", ReasonFields) {
122
75
  }
123
76
  export const AIErrorReason = Schema.Union([
124
- InvalidRequestReason,
125
- NoRouteReason,
126
- AuthenticationReason,
127
- RateLimitReason,
128
- QuotaExceededReason,
129
- ContentPolicyReason,
130
- ProviderInternalReason,
131
- TransportReason,
132
- InvalidProviderOutputReason,
133
- UnknownProviderReason,
77
+ InvalidRequestError,
78
+ NoRouteError,
79
+ AuthenticationError,
80
+ RateLimitError,
81
+ QuotaExceededError,
82
+ ContentPolicyError,
83
+ ProviderInternalError,
84
+ TransportError,
85
+ InvalidProviderOutputError,
86
+ UnknownProviderError,
134
87
  ]).pipe(Schema.toTaggedUnion("_tag"));
135
88
  export class AIError extends Schema.TaggedError()("AI.Error", {
136
- module: Schema.String,
137
- method: Schema.String,
138
89
  reason: AIErrorReason,
139
- // Raw provider payload as a string, so classified failures never lose the
140
- // original error detail even when the pretty message is a summary.
141
- body: Schema.optional(Schema.String),
142
90
  }) {
143
91
  cause = this.reason;
144
92
  get message() {
145
- return `${this.module}.${this.method}: ${this.reason.message}`;
93
+ return this.reason.message;
146
94
  }
147
95
  }
148
96
  /**