@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.cjs CHANGED
@@ -34,6 +34,8 @@ __export(index_exports, {
34
34
  GGAIError: () => GGAIError,
35
35
  ProviderError: () => ProviderError,
36
36
  StreamResult: () => StreamResult,
37
+ formatError: () => formatError,
38
+ formatErrorForDisplay: () => formatErrorForDisplay,
37
39
  palsuAssistantMessage: () => palsuAssistantMessage,
38
40
  palsuText: () => palsuText,
39
41
  palsuThinking: () => palsuThinking,
@@ -46,21 +48,165 @@ module.exports = __toCommonJS(index_exports);
46
48
 
47
49
  // src/errors.ts
48
50
  var GGAIError = class extends Error {
51
+ source;
52
+ requestId;
53
+ hint;
49
54
  constructor(message, options) {
50
- super(message, options);
55
+ super(message, { cause: options?.cause });
51
56
  this.name = "GGAIError";
57
+ this.source = options?.source ?? "ggcoder";
58
+ this.requestId = options?.requestId;
59
+ this.hint = options?.hint;
52
60
  }
53
61
  };
54
62
  var ProviderError = class extends GGAIError {
55
63
  provider;
56
64
  statusCode;
57
65
  constructor(provider, message, options) {
58
- super(`[${provider}] ${message}`, { cause: options?.cause });
66
+ super(message, {
67
+ source: "provider",
68
+ requestId: options?.requestId,
69
+ hint: options?.hint,
70
+ cause: options?.cause
71
+ });
59
72
  this.name = "ProviderError";
60
73
  this.provider = provider;
61
74
  this.statusCode = options?.statusCode;
62
75
  }
63
76
  };
77
+ var PROVIDER_DISPLAY = {
78
+ openai: "OpenAI",
79
+ anthropic: "Anthropic",
80
+ glm: "Z.AI (GLM)",
81
+ moonshot: "Moonshot",
82
+ deepseek: "DeepSeek",
83
+ openrouter: "OpenRouter",
84
+ xiaomi: "Xiaomi (MiMo)",
85
+ minimax: "MiniMax"
86
+ };
87
+ var PROVIDER_STATUS_URL = {
88
+ openai: "status.openai.com",
89
+ anthropic: "status.anthropic.com"
90
+ };
91
+ function providerDisplayName(provider) {
92
+ return PROVIDER_DISPLAY[provider] ?? provider;
93
+ }
94
+ function formatError(err) {
95
+ if (err instanceof ProviderError) {
96
+ const name = providerDisplayName(err.provider);
97
+ const cleanMessage = cleanProviderMessage(err.message);
98
+ return {
99
+ headline: `${name} returned an error.`,
100
+ source: "provider",
101
+ message: cleanMessage,
102
+ provider: err.provider,
103
+ statusCode: err.statusCode,
104
+ requestId: err.requestId,
105
+ guidance: err.hint ?? providerGuidance(err.provider, cleanMessage, err.statusCode)
106
+ };
107
+ }
108
+ if (err instanceof GGAIError) {
109
+ return finaliseBySource(err.source, err.message, err.requestId, err.hint);
110
+ }
111
+ if (err instanceof Error) {
112
+ const source = inferSource(err);
113
+ return finaliseBySource(source, err.message, void 0, void 0);
114
+ }
115
+ return finaliseBySource("ggcoder", String(err), void 0, void 0);
116
+ }
117
+ function finaliseBySource(source, message, requestId, hint) {
118
+ switch (source) {
119
+ case "network":
120
+ return {
121
+ headline: "Network error \u2014 couldn't reach the provider.",
122
+ source,
123
+ message,
124
+ guidance: hint ?? "Check your internet connection. Not a ggcoder issue \u2014 retry shortly.",
125
+ ...requestId ? { requestId } : {}
126
+ };
127
+ case "auth":
128
+ return {
129
+ headline: "Authentication issue.",
130
+ source,
131
+ message,
132
+ guidance: hint ?? "Run `ggcoder login` to refresh your credentials.",
133
+ ...requestId ? { requestId } : {}
134
+ };
135
+ case "provider":
136
+ return {
137
+ headline: "Provider returned an error.",
138
+ source,
139
+ message,
140
+ guidance: hint ?? providerGuidance(void 0, message, void 0),
141
+ ...requestId ? { requestId } : {}
142
+ };
143
+ case "ggcoder":
144
+ return {
145
+ headline: "ggcoder hit an unexpected error.",
146
+ source,
147
+ message,
148
+ guidance: hint ?? "This looks like a ggcoder bug \u2014 please report it to the developer (see /help).",
149
+ ...requestId ? { requestId } : {}
150
+ };
151
+ }
152
+ }
153
+ function formatErrorForDisplay(err) {
154
+ const f = formatError(err);
155
+ const lines = [f.headline];
156
+ if (f.message && f.message !== f.headline) lines.push(` ${f.message}`);
157
+ lines.push(` \u2192 ${f.guidance}`);
158
+ return lines.join("\n");
159
+ }
160
+ function cleanProviderMessage(message) {
161
+ return message.replace(/^\[[^\]]+\]\s*/, "").trim();
162
+ }
163
+ function inferSource(err) {
164
+ const msg = err.message.toLowerCase();
165
+ const code = err.code ?? "";
166
+ if (code === "ECONNREFUSED" || code === "ETIMEDOUT" || code === "ENOTFOUND" || code === "ECONNRESET" || msg.includes("fetch failed") || msg.includes("network request failed")) {
167
+ return "network";
168
+ }
169
+ if (msg.includes("not logged in") || msg.includes("token exchange failed") || msg.includes("token refresh failed") || msg.includes("invalid_grant")) {
170
+ return "auth";
171
+ }
172
+ return "ggcoder";
173
+ }
174
+ function providerGuidance(provider, message, statusCode) {
175
+ const name = provider ? providerDisplayName(provider) : "the provider";
176
+ const status = provider ? PROVIDER_STATUS_URL[provider] : void 0;
177
+ const lower = message.toLowerCase();
178
+ if (statusCode === 401 || lower.includes("unauthorized") || lower.includes("invalid api key")) {
179
+ return `Authentication failed with ${name}. Run \`ggcoder login\` to refresh your credentials.`;
180
+ }
181
+ if (lower.includes("overloaded") || lower.includes("engine_overloaded")) {
182
+ return `${name}'s servers are overloaded right now. Retry in a moment \u2014 not a ggcoder issue.`;
183
+ }
184
+ if (lower.includes("insufficient balance") || lower.includes("quota exceeded") || lower.includes("recharge") || lower.includes("no resource package")) {
185
+ return `Your ${name} account has a billing or quota issue \u2014 check your balance. Not a ggcoder issue.`;
186
+ }
187
+ if (statusCode === 429 || lower.includes("rate limit") || lower.includes("too many requests")) {
188
+ return `${name} rate limit hit. Wait a moment then retry \u2014 not a ggcoder issue.`;
189
+ }
190
+ if (statusCode === 502 || lower.includes("bad gateway")) {
191
+ return `${name} returned a bad gateway. Retry \u2014 this is on their side, not ggcoder.`;
192
+ }
193
+ if (statusCode === 503 || lower.includes("service unavailable")) {
194
+ return `${name} is temporarily unavailable. Retry shortly \u2014 not a ggcoder issue.`;
195
+ }
196
+ if (statusCode === 500 || lower.includes("server_error") || lower.includes("500") && lower.includes("internal server error")) {
197
+ 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.`;
198
+ }
199
+ if (lower.includes("timeout") || lower.includes("timed out")) {
200
+ return `Request to ${name} timed out. Their servers may be slow \u2014 retry. Not a ggcoder issue.`;
201
+ }
202
+ if (lower.includes("does not recognize the requested model") || lower.includes("model") && (lower.includes("not exist") || lower.includes("not found") || lower.includes("no access"))) {
203
+ return `${name} doesn't recognise this model on your account. Use /model to switch, or check your subscription tier.`;
204
+ }
205
+ if (lower.includes("context_length_exceeded") || lower.includes("prompt is too long")) {
206
+ return `Context window for this ${name} model is full. Run /compact to shrink history, or start a new session.`;
207
+ }
208
+ 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.`;
209
+ }
64
210
 
65
211
  // src/providers/anthropic.ts
66
212
  var import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
@@ -999,8 +1145,10 @@ function messageToResponse(message) {
999
1145
  }
1000
1146
  function toError(err) {
1001
1147
  if (err instanceof import_sdk.default.APIError) {
1148
+ const requestId = err.request_id ?? err.error?.request_id;
1002
1149
  return new ProviderError("anthropic", err.message, {
1003
1150
  statusCode: err.status,
1151
+ ...requestId ? { requestId } : {},
1004
1152
  cause: err
1005
1153
  });
1006
1154
  }
@@ -1292,19 +1440,19 @@ function completionToResponse(completion) {
1292
1440
  }
1293
1441
  function toError2(err, provider = "openai") {
1294
1442
  if (err instanceof import_openai.default.APIError) {
1295
- let msg = err.message;
1296
1443
  const body = err.error;
1297
- if (body) {
1298
- const modelName = body.model || "";
1299
- const _code = body.code || "";
1300
- const message = body.message || "";
1301
- if (modelName === "codex-mini-latest" || message.includes("codex-mini-latest")) {
1302
- 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.`;
1303
- }
1304
- msg += ` | body: ${JSON.stringify(body)}`;
1305
- }
1306
- return new ProviderError(provider, msg, {
1444
+ const bodyMessage = typeof body?.message === "string" && body.message.trim() ? body.message.trim() : void 0;
1445
+ const modelName = typeof body?.model === "string" ? body.model : "";
1446
+ const cleanMessage = bodyMessage ?? err.message;
1447
+ let hint;
1448
+ if (modelName === "codex-mini-latest" || cleanMessage.includes("codex-mini-latest")) {
1449
+ 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.";
1450
+ }
1451
+ const requestId = err.request_id ?? (typeof body?.request_id === "string" ? body.request_id : void 0);
1452
+ return new ProviderError(provider, cleanMessage, {
1307
1453
  statusCode: err.status,
1454
+ ...requestId ? { requestId } : {},
1455
+ ...hint ? { hint } : {},
1308
1456
  cause: err
1309
1457
  });
1310
1458
  }
@@ -1366,19 +1514,19 @@ async function* runStream3(options) {
1366
1514
  });
1367
1515
  if (!response.ok) {
1368
1516
  const text = await response.text().catch(() => "");
1369
- let message = `Codex API error (${response.status}): ${text}`;
1517
+ const parsed = parseCodexErrorBody(text);
1518
+ const message = parsed.message ?? `Codex API returned HTTP ${response.status}.`;
1519
+ const requestId = parsed.requestId ?? response.headers.get("x-request-id") ?? response.headers.get("openai-request-id") ?? void 0;
1520
+ let hint;
1370
1521
  if (response.status === 400 && text.includes("not supported")) {
1371
- message += `
1372
-
1373
- 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`;
1374
- }
1375
- if (response.status === 404 && text.includes("does not exist")) {
1376
- message += `
1377
-
1378
- 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.`;
1522
+ 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.';
1523
+ } else if (response.status === 404 && text.includes("does not exist")) {
1524
+ 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.";
1379
1525
  }
1380
1526
  throw new ProviderError("openai", message, {
1381
- statusCode: response.status
1527
+ statusCode: response.status,
1528
+ ...requestId ? { requestId } : {},
1529
+ ...hint ? { hint } : {}
1382
1530
  });
1383
1531
  }
1384
1532
  if (!response.body) {
@@ -1393,12 +1541,22 @@ Hint: codex-mini-latest requires an OpenAI Pro ($200/mo) or Max subscription. GP
1393
1541
  const type = event.type;
1394
1542
  if (!type) continue;
1395
1543
  if (type === "error") {
1396
- const msg = event.message || JSON.stringify(event);
1397
- throw new ProviderError("openai", `Codex error: ${msg}`);
1544
+ const nested = event.error ?? void 0;
1545
+ const message = nested?.message ?? event.message ?? "Codex stream emitted an error chunk without a message.";
1546
+ const code = nested?.code ?? nested?.type ?? event.code ?? "server_error";
1547
+ const requestId = extractCodexRequestId(message) ?? event.request_id;
1548
+ throw new ProviderError("openai", message, {
1549
+ ...requestId != null ? { requestId } : {},
1550
+ ...code === "server_error" ? { statusCode: 500 } : {}
1551
+ });
1398
1552
  }
1399
1553
  if (type === "response.failed") {
1400
- const msg = event.error?.message || "Codex response failed";
1401
- throw new ProviderError("openai", msg);
1554
+ const nested = event.error;
1555
+ const message = nested?.message ?? "Codex response failed.";
1556
+ const requestId = extractCodexRequestId(message) ?? event.request_id;
1557
+ throw new ProviderError("openai", message, {
1558
+ ...requestId != null ? { requestId } : {}
1559
+ });
1402
1560
  }
1403
1561
  if (type === "response.output_text.delta") {
1404
1562
  const delta = event.delta;
@@ -1643,6 +1801,23 @@ function toCodexTools(tools) {
1643
1801
  strict: null
1644
1802
  }));
1645
1803
  }
1804
+ function extractCodexRequestId(message) {
1805
+ const match = message.match(/request ID ([a-z0-9-]{8,})/i);
1806
+ return match?.[1];
1807
+ }
1808
+ function parseCodexErrorBody(text) {
1809
+ if (!text) return {};
1810
+ try {
1811
+ const parsed = JSON.parse(text);
1812
+ const error = parsed.error;
1813
+ const message = error?.message ?? parsed.message;
1814
+ const requestId = parsed.request_id ?? error?.request_id ?? (message ? extractCodexRequestId(message) : void 0);
1815
+ return { ...message ? { message } : {}, ...requestId ? { requestId } : {} };
1816
+ } catch {
1817
+ const trimmed = text.trim().slice(0, 240);
1818
+ return trimmed ? { message: trimmed } : {};
1819
+ }
1820
+ }
1646
1821
 
1647
1822
  // src/provider-registry.ts
1648
1823
  var ProviderRegistryImpl = class {
@@ -1903,6 +2078,8 @@ function registerPalsuProvider(config) {
1903
2078
  GGAIError,
1904
2079
  ProviderError,
1905
2080
  StreamResult,
2081
+ formatError,
2082
+ formatErrorForDisplay,
1906
2083
  palsuAssistantMessage,
1907
2084
  palsuText,
1908
2085
  palsuThinking,