@kenkaiiii/gg-ai 4.3.165 → 4.3.166

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.
package/dist/index.d.cts CHANGED
@@ -292,17 +292,74 @@ declare class ProviderRegistryImpl {
292
292
  /** Global provider registry. Import this to register custom providers. */
293
293
  declare const providerRegistry: ProviderRegistryImpl;
294
294
 
295
+ /**
296
+ * Error model for gg-ai and downstream consumers.
297
+ *
298
+ * Every error users see should answer one question: "is this me or them?"
299
+ * That answer drives whether they retry, switch model, log in, or report a
300
+ * ggcoder bug. The `FormattedError` shape captures it in plain English:
301
+ *
302
+ * ✗ OpenAI returned an error.
303
+ * An error occurred while processing your request...
304
+ * → This is an OpenAI issue, not ggcoder. Retry — if it persists, check status.openai.com.
305
+ *
306
+ * ✗ ggcoder hit an unexpected error.
307
+ * Cannot read property 'foo' of undefined
308
+ * → This is a ggcoder bug — please report it.
309
+ */
310
+ type ErrorSource = "provider" | "ggcoder" | "network" | "auth";
311
+ interface FormattedError {
312
+ /** Plain-English headline, e.g. "OpenAI returned an error." */
313
+ headline: string;
314
+ /** Machine-readable classification. */
315
+ source: ErrorSource;
316
+ /** Detailed message body from the underlying error (no JSON, no tag prefix). */
317
+ message: string;
318
+ /** Action line — tells the user whether to retry, switch model, log in, or report a bug. */
319
+ guidance: string;
320
+ /** Provider name when source === "provider". */
321
+ provider?: string;
322
+ /** HTTP status code if known. */
323
+ statusCode?: number;
324
+ /** Provider request ID, kept for telemetry / debug — not shown by default. */
325
+ requestId?: string;
326
+ }
295
327
  declare class GGAIError extends Error {
296
- constructor(message: string, options?: ErrorOptions);
328
+ readonly source: ErrorSource;
329
+ readonly requestId?: string;
330
+ readonly hint?: string;
331
+ constructor(message: string, options?: {
332
+ source?: ErrorSource;
333
+ requestId?: string;
334
+ hint?: string;
335
+ cause?: unknown;
336
+ });
297
337
  }
298
338
  declare class ProviderError extends GGAIError {
299
339
  readonly provider: string;
300
340
  readonly statusCode?: number;
301
341
  constructor(provider: string, message: string, options?: {
302
342
  statusCode?: number;
343
+ requestId?: string;
344
+ hint?: string;
303
345
  cause?: unknown;
304
346
  });
305
347
  }
348
+ /**
349
+ * Normalise any thrown value into a structured display object. Always returns
350
+ * a non-empty `headline` and `guidance` so the UI never has to second-guess
351
+ * what to show the user.
352
+ */
353
+ declare function formatError(err: unknown): FormattedError;
354
+ /**
355
+ * Render a FormattedError as a multi-line string for terminal display.
356
+ *
357
+ * Format:
358
+ * <headline>
359
+ * <message>
360
+ * → <guidance>
361
+ */
362
+ declare function formatErrorForDisplay(err: unknown): string;
306
363
 
307
364
  interface PalsuProviderState {
308
365
  callCount: number;
@@ -373,4 +430,4 @@ interface PalsuProviderConfig {
373
430
  */
374
431
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
375
432
 
376
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, EventStream, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
433
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, formatError, formatErrorForDisplay, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
package/dist/index.d.ts CHANGED
@@ -292,17 +292,74 @@ declare class ProviderRegistryImpl {
292
292
  /** Global provider registry. Import this to register custom providers. */
293
293
  declare const providerRegistry: ProviderRegistryImpl;
294
294
 
295
+ /**
296
+ * Error model for gg-ai and downstream consumers.
297
+ *
298
+ * Every error users see should answer one question: "is this me or them?"
299
+ * That answer drives whether they retry, switch model, log in, or report a
300
+ * ggcoder bug. The `FormattedError` shape captures it in plain English:
301
+ *
302
+ * ✗ OpenAI returned an error.
303
+ * An error occurred while processing your request...
304
+ * → This is an OpenAI issue, not ggcoder. Retry — if it persists, check status.openai.com.
305
+ *
306
+ * ✗ ggcoder hit an unexpected error.
307
+ * Cannot read property 'foo' of undefined
308
+ * → This is a ggcoder bug — please report it.
309
+ */
310
+ type ErrorSource = "provider" | "ggcoder" | "network" | "auth";
311
+ interface FormattedError {
312
+ /** Plain-English headline, e.g. "OpenAI returned an error." */
313
+ headline: string;
314
+ /** Machine-readable classification. */
315
+ source: ErrorSource;
316
+ /** Detailed message body from the underlying error (no JSON, no tag prefix). */
317
+ message: string;
318
+ /** Action line — tells the user whether to retry, switch model, log in, or report a bug. */
319
+ guidance: string;
320
+ /** Provider name when source === "provider". */
321
+ provider?: string;
322
+ /** HTTP status code if known. */
323
+ statusCode?: number;
324
+ /** Provider request ID, kept for telemetry / debug — not shown by default. */
325
+ requestId?: string;
326
+ }
295
327
  declare class GGAIError extends Error {
296
- constructor(message: string, options?: ErrorOptions);
328
+ readonly source: ErrorSource;
329
+ readonly requestId?: string;
330
+ readonly hint?: string;
331
+ constructor(message: string, options?: {
332
+ source?: ErrorSource;
333
+ requestId?: string;
334
+ hint?: string;
335
+ cause?: unknown;
336
+ });
297
337
  }
298
338
  declare class ProviderError extends GGAIError {
299
339
  readonly provider: string;
300
340
  readonly statusCode?: number;
301
341
  constructor(provider: string, message: string, options?: {
302
342
  statusCode?: number;
343
+ requestId?: string;
344
+ hint?: string;
303
345
  cause?: unknown;
304
346
  });
305
347
  }
348
+ /**
349
+ * Normalise any thrown value into a structured display object. Always returns
350
+ * a non-empty `headline` and `guidance` so the UI never has to second-guess
351
+ * what to show the user.
352
+ */
353
+ declare function formatError(err: unknown): FormattedError;
354
+ /**
355
+ * Render a FormattedError as a multi-line string for terminal display.
356
+ *
357
+ * Format:
358
+ * <headline>
359
+ * <message>
360
+ * → <guidance>
361
+ */
362
+ declare function formatErrorForDisplay(err: unknown): string;
306
363
 
307
364
  interface PalsuProviderState {
308
365
  callCount: number;
@@ -373,4 +430,4 @@ interface PalsuProviderConfig {
373
430
  */
374
431
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
375
432
 
376
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, EventStream, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
433
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, formatError, formatErrorForDisplay, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
package/dist/index.js CHANGED
@@ -1,20 +1,164 @@
1
1
  // src/errors.ts
2
2
  var GGAIError = class extends Error {
3
+ source;
4
+ requestId;
5
+ hint;
3
6
  constructor(message, options) {
4
- super(message, options);
7
+ super(message, { cause: options?.cause });
5
8
  this.name = "GGAIError";
9
+ this.source = options?.source ?? "ggcoder";
10
+ this.requestId = options?.requestId;
11
+ this.hint = options?.hint;
6
12
  }
7
13
  };
8
14
  var ProviderError = class extends GGAIError {
9
15
  provider;
10
16
  statusCode;
11
17
  constructor(provider, message, options) {
12
- super(`[${provider}] ${message}`, { cause: options?.cause });
18
+ super(message, {
19
+ source: "provider",
20
+ requestId: options?.requestId,
21
+ hint: options?.hint,
22
+ cause: options?.cause
23
+ });
13
24
  this.name = "ProviderError";
14
25
  this.provider = provider;
15
26
  this.statusCode = options?.statusCode;
16
27
  }
17
28
  };
29
+ var PROVIDER_DISPLAY = {
30
+ openai: "OpenAI",
31
+ anthropic: "Anthropic",
32
+ glm: "Z.AI (GLM)",
33
+ moonshot: "Moonshot",
34
+ deepseek: "DeepSeek",
35
+ openrouter: "OpenRouter",
36
+ xiaomi: "Xiaomi (MiMo)",
37
+ minimax: "MiniMax"
38
+ };
39
+ var PROVIDER_STATUS_URL = {
40
+ openai: "status.openai.com",
41
+ anthropic: "status.anthropic.com"
42
+ };
43
+ function providerDisplayName(provider) {
44
+ return PROVIDER_DISPLAY[provider] ?? provider;
45
+ }
46
+ function formatError(err) {
47
+ if (err instanceof ProviderError) {
48
+ const name = providerDisplayName(err.provider);
49
+ const cleanMessage = cleanProviderMessage(err.message);
50
+ return {
51
+ headline: `${name} returned an error.`,
52
+ source: "provider",
53
+ message: cleanMessage,
54
+ provider: err.provider,
55
+ statusCode: err.statusCode,
56
+ requestId: err.requestId,
57
+ guidance: err.hint ?? providerGuidance(err.provider, cleanMessage, err.statusCode)
58
+ };
59
+ }
60
+ if (err instanceof GGAIError) {
61
+ return finaliseBySource(err.source, err.message, err.requestId, err.hint);
62
+ }
63
+ if (err instanceof Error) {
64
+ const source = inferSource(err);
65
+ return finaliseBySource(source, err.message, void 0, void 0);
66
+ }
67
+ return finaliseBySource("ggcoder", String(err), void 0, void 0);
68
+ }
69
+ function finaliseBySource(source, message, requestId, hint) {
70
+ switch (source) {
71
+ case "network":
72
+ return {
73
+ headline: "Network error \u2014 couldn't reach the provider.",
74
+ source,
75
+ message,
76
+ guidance: hint ?? "Check your internet connection. Not a ggcoder issue \u2014 retry shortly.",
77
+ ...requestId ? { requestId } : {}
78
+ };
79
+ case "auth":
80
+ return {
81
+ headline: "Authentication issue.",
82
+ source,
83
+ message,
84
+ guidance: hint ?? "Run `ggcoder login` to refresh your credentials.",
85
+ ...requestId ? { requestId } : {}
86
+ };
87
+ case "provider":
88
+ return {
89
+ headline: "Provider returned an error.",
90
+ source,
91
+ message,
92
+ guidance: hint ?? providerGuidance(void 0, message, void 0),
93
+ ...requestId ? { requestId } : {}
94
+ };
95
+ case "ggcoder":
96
+ return {
97
+ headline: "ggcoder hit an unexpected error.",
98
+ source,
99
+ message,
100
+ guidance: hint ?? "This looks like a ggcoder bug \u2014 please report it to the developer (see /help).",
101
+ ...requestId ? { requestId } : {}
102
+ };
103
+ }
104
+ }
105
+ function formatErrorForDisplay(err) {
106
+ const f = formatError(err);
107
+ const lines = [f.headline];
108
+ if (f.message && f.message !== f.headline) lines.push(` ${f.message}`);
109
+ lines.push(` \u2192 ${f.guidance}`);
110
+ return lines.join("\n");
111
+ }
112
+ function cleanProviderMessage(message) {
113
+ return message.replace(/^\[[^\]]+\]\s*/, "").trim();
114
+ }
115
+ function inferSource(err) {
116
+ const msg = err.message.toLowerCase();
117
+ const code = err.code ?? "";
118
+ if (code === "ECONNREFUSED" || code === "ETIMEDOUT" || code === "ENOTFOUND" || code === "ECONNRESET" || msg.includes("fetch failed") || msg.includes("network request failed")) {
119
+ return "network";
120
+ }
121
+ if (msg.includes("not logged in") || msg.includes("token exchange failed") || msg.includes("token refresh failed") || msg.includes("invalid_grant")) {
122
+ return "auth";
123
+ }
124
+ return "ggcoder";
125
+ }
126
+ function providerGuidance(provider, message, statusCode) {
127
+ const name = provider ? providerDisplayName(provider) : "the provider";
128
+ const status = provider ? PROVIDER_STATUS_URL[provider] : void 0;
129
+ const lower = message.toLowerCase();
130
+ if (statusCode === 401 || lower.includes("unauthorized") || lower.includes("invalid api key")) {
131
+ return `Authentication failed with ${name}. Run \`ggcoder login\` to refresh your credentials.`;
132
+ }
133
+ if (lower.includes("overloaded") || lower.includes("engine_overloaded")) {
134
+ return `${name}'s servers are overloaded right now. Retry in a moment \u2014 not a ggcoder issue.`;
135
+ }
136
+ if (lower.includes("insufficient balance") || lower.includes("quota exceeded") || lower.includes("recharge") || lower.includes("no resource package")) {
137
+ return `Your ${name} account has a billing or quota issue \u2014 check your balance. Not a ggcoder issue.`;
138
+ }
139
+ if (statusCode === 429 || lower.includes("rate limit") || lower.includes("too many requests")) {
140
+ return `${name} rate limit hit. Wait a moment then retry \u2014 not a ggcoder issue.`;
141
+ }
142
+ if (statusCode === 502 || lower.includes("bad gateway")) {
143
+ return `${name} returned a bad gateway. Retry \u2014 this is on their side, not ggcoder.`;
144
+ }
145
+ if (statusCode === 503 || lower.includes("service unavailable")) {
146
+ return `${name} is temporarily unavailable. Retry shortly \u2014 not a ggcoder issue.`;
147
+ }
148
+ if (statusCode === 500 || lower.includes("server_error") || lower.includes("500") && lower.includes("internal server error")) {
149
+ return status ? `This is an error from ${name}, not ggcoder. Retry \u2014 if it keeps happening, check ${status}.` : `This is an error from ${name}, not ggcoder. Retry \u2014 if it keeps happening, try a different model with /model.`;
150
+ }
151
+ if (lower.includes("timeout") || lower.includes("timed out")) {
152
+ return `Request to ${name} timed out. Their servers may be slow \u2014 retry. Not a ggcoder issue.`;
153
+ }
154
+ if (lower.includes("does not recognize the requested model") || lower.includes("model") && (lower.includes("not exist") || lower.includes("not found") || lower.includes("no access"))) {
155
+ return `${name} doesn't recognise this model on your account. Use /model to switch, or check your subscription tier.`;
156
+ }
157
+ if (lower.includes("context_length_exceeded") || lower.includes("prompt is too long")) {
158
+ return `Context window for this ${name} model is full. Run /compact to shrink history, or start a new session.`;
159
+ }
160
+ return status ? `This is an error from ${name}, not ggcoder. Retry \u2014 if it persists, check ${status}.` : `This is an error from ${name}, not ggcoder. Retry \u2014 if it persists, try a different model with /model.`;
161
+ }
18
162
 
19
163
  // src/providers/anthropic.ts
20
164
  import Anthropic from "@anthropic-ai/sdk";
@@ -953,8 +1097,10 @@ function messageToResponse(message) {
953
1097
  }
954
1098
  function toError(err) {
955
1099
  if (err instanceof Anthropic.APIError) {
1100
+ const requestId = err.request_id ?? err.error?.request_id;
956
1101
  return new ProviderError("anthropic", err.message, {
957
1102
  statusCode: err.status,
1103
+ ...requestId ? { requestId } : {},
958
1104
  cause: err
959
1105
  });
960
1106
  }
@@ -1246,19 +1392,19 @@ function completionToResponse(completion) {
1246
1392
  }
1247
1393
  function toError2(err, provider = "openai") {
1248
1394
  if (err instanceof OpenAI.APIError) {
1249
- let msg = err.message;
1250
1395
  const body = err.error;
1251
- if (body) {
1252
- const modelName = body.model || "";
1253
- const _code = body.code || "";
1254
- const message = body.message || "";
1255
- if (modelName === "codex-mini-latest" || message.includes("codex-mini-latest")) {
1256
- msg = `codex-mini-latest requires an OpenAI Pro or Max subscription. You currently have access to GPT-5.4 and GPT-5.4 Mini with your account.`;
1257
- }
1258
- msg += ` | body: ${JSON.stringify(body)}`;
1259
- }
1260
- return new ProviderError(provider, msg, {
1396
+ const bodyMessage = typeof body?.message === "string" && body.message.trim() ? body.message.trim() : void 0;
1397
+ const modelName = typeof body?.model === "string" ? body.model : "";
1398
+ const cleanMessage = bodyMessage ?? err.message;
1399
+ let hint;
1400
+ if (modelName === "codex-mini-latest" || cleanMessage.includes("codex-mini-latest")) {
1401
+ hint = "codex-mini-latest requires an OpenAI Pro or Max subscription. Your account currently has access to GPT-5.4 and GPT-5.4 Mini.";
1402
+ }
1403
+ const requestId = err.request_id ?? (typeof body?.request_id === "string" ? body.request_id : void 0);
1404
+ return new ProviderError(provider, cleanMessage, {
1261
1405
  statusCode: err.status,
1406
+ ...requestId ? { requestId } : {},
1407
+ ...hint ? { hint } : {},
1262
1408
  cause: err
1263
1409
  });
1264
1410
  }
@@ -1320,19 +1466,19 @@ async function* runStream3(options) {
1320
1466
  });
1321
1467
  if (!response.ok) {
1322
1468
  const text = await response.text().catch(() => "");
1323
- let message = `Codex API error (${response.status}): ${text}`;
1469
+ const parsed = parseCodexErrorBody(text);
1470
+ const message = parsed.message ?? `Codex API returned HTTP ${response.status}.`;
1471
+ const requestId = parsed.requestId ?? response.headers.get("x-request-id") ?? response.headers.get("openai-request-id") ?? void 0;
1472
+ let hint;
1324
1473
  if (response.status === 400 && text.includes("not supported")) {
1325
- message += `
1326
-
1327
- Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription. The "codex-spark" variants require ChatGPT Pro. Ensure your account has an active subscription at https://chatgpt.com/settings`;
1328
- }
1329
- if (response.status === 404 && text.includes("does not exist")) {
1330
- message += `
1331
-
1332
- Hint: codex-mini-latest requires an OpenAI Pro ($200/mo) or Max subscription. GPT-5.4 and GPT-5.4 Mini work with any active ChatGPT plan.`;
1474
+ hint = 'Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription. The "codex-spark" variants require ChatGPT Pro. Check your subscription at https://chatgpt.com/settings.';
1475
+ } else if (response.status === 404 && text.includes("does not exist")) {
1476
+ hint = "codex-mini-latest requires an OpenAI Pro ($200/mo) or Max subscription. GPT-5.4 and GPT-5.4 Mini work with any active ChatGPT plan.";
1333
1477
  }
1334
1478
  throw new ProviderError("openai", message, {
1335
- statusCode: response.status
1479
+ statusCode: response.status,
1480
+ ...requestId ? { requestId } : {},
1481
+ ...hint ? { hint } : {}
1336
1482
  });
1337
1483
  }
1338
1484
  if (!response.body) {
@@ -1347,12 +1493,22 @@ Hint: codex-mini-latest requires an OpenAI Pro ($200/mo) or Max subscription. GP
1347
1493
  const type = event.type;
1348
1494
  if (!type) continue;
1349
1495
  if (type === "error") {
1350
- const msg = event.message || JSON.stringify(event);
1351
- throw new ProviderError("openai", `Codex error: ${msg}`);
1496
+ const nested = event.error ?? void 0;
1497
+ const message = nested?.message ?? event.message ?? "Codex stream emitted an error chunk without a message.";
1498
+ const code = nested?.code ?? nested?.type ?? event.code ?? "server_error";
1499
+ const requestId = extractCodexRequestId(message) ?? event.request_id;
1500
+ throw new ProviderError("openai", message, {
1501
+ ...requestId != null ? { requestId } : {},
1502
+ ...code === "server_error" ? { statusCode: 500 } : {}
1503
+ });
1352
1504
  }
1353
1505
  if (type === "response.failed") {
1354
- const msg = event.error?.message || "Codex response failed";
1355
- throw new ProviderError("openai", msg);
1506
+ const nested = event.error;
1507
+ const message = nested?.message ?? "Codex response failed.";
1508
+ const requestId = extractCodexRequestId(message) ?? event.request_id;
1509
+ throw new ProviderError("openai", message, {
1510
+ ...requestId != null ? { requestId } : {}
1511
+ });
1356
1512
  }
1357
1513
  if (type === "response.output_text.delta") {
1358
1514
  const delta = event.delta;
@@ -1597,6 +1753,23 @@ function toCodexTools(tools) {
1597
1753
  strict: null
1598
1754
  }));
1599
1755
  }
1756
+ function extractCodexRequestId(message) {
1757
+ const match = message.match(/request ID ([a-z0-9-]{8,})/i);
1758
+ return match?.[1];
1759
+ }
1760
+ function parseCodexErrorBody(text) {
1761
+ if (!text) return {};
1762
+ try {
1763
+ const parsed = JSON.parse(text);
1764
+ const error = parsed.error;
1765
+ const message = error?.message ?? parsed.message;
1766
+ const requestId = parsed.request_id ?? error?.request_id ?? (message ? extractCodexRequestId(message) : void 0);
1767
+ return { ...message ? { message } : {}, ...requestId ? { requestId } : {} };
1768
+ } catch {
1769
+ const trimmed = text.trim().slice(0, 240);
1770
+ return trimmed ? { message: trimmed } : {};
1771
+ }
1772
+ }
1600
1773
 
1601
1774
  // src/provider-registry.ts
1602
1775
  var ProviderRegistryImpl = class {
@@ -1856,6 +2029,8 @@ export {
1856
2029
  GGAIError,
1857
2030
  ProviderError,
1858
2031
  StreamResult,
2032
+ formatError,
2033
+ formatErrorForDisplay,
1859
2034
  palsuAssistantMessage,
1860
2035
  palsuText,
1861
2036
  palsuThinking,