@appchy/jarvis 0.1.24 → 0.1.26

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/bin.js CHANGED
@@ -886,6 +886,20 @@ var init_anthropic_llm_provider = __esm({
886
886
  });
887
887
 
888
888
  // ../../providers/anthropic/src/claude-code.llm.provider.ts
889
+ function isRateLimitError(err) {
890
+ if (!err) return { matched: false };
891
+ const e = err;
892
+ const msg = typeof e.message === "string" ? e.message : "";
893
+ const name = typeof e.name === "string" ? e.name : "";
894
+ const status = typeof e.status === "number" ? e.status : void 0;
895
+ const matched = status === 429 || /rate.?limit/i.test(msg) || /rate.?limit/i.test(name);
896
+ if (!matched) return { matched: false };
897
+ return {
898
+ matched: true,
899
+ ...typeof e.resetsAt === "string" ? { resetsAt: e.resetsAt } : {},
900
+ ...typeof e.tier === "string" ? { tier: e.tier } : {}
901
+ };
902
+ }
889
903
  function generateId() {
890
904
  return `pui-${Date.now()}-${++_idCounter}`;
891
905
  }
@@ -1080,6 +1094,7 @@ function claudeCodeProvider(config = {}) {
1080
1094
  let lastAssistantContent = "";
1081
1095
  let json;
1082
1096
  let sdkError;
1097
+ let rateLimit;
1083
1098
  let inputTokens = 0;
1084
1099
  let outputTokens = 0;
1085
1100
  const isResuming = !!config.session?.resume;
@@ -1190,6 +1205,13 @@ function claudeCodeProvider(config = {}) {
1190
1205
  }
1191
1206
  }
1192
1207
  }
1208
+ if (message.type === "rate_limit_event") {
1209
+ const ev = message;
1210
+ const resetsAt = ev.resetsAt ?? ev.resets_at ?? (typeof ev.resetTime === "number" ? new Date(ev.resetTime).toISOString() : void 0);
1211
+ const tier = ev.tier ?? ev.scope;
1212
+ rateLimit = { ...resetsAt ? { resetsAt } : {}, ...tier ? { tier } : {} };
1213
+ logger.info(ctx, "[ClaudeCode] rate_limit_event (soft warning)", { resetsAt, tier });
1214
+ }
1193
1215
  if (message.type === "result") {
1194
1216
  const subtype = message.subtype;
1195
1217
  if (subtype && subtype !== "success") {
@@ -1211,20 +1233,35 @@ function claudeCodeProvider(config = {}) {
1211
1233
  }
1212
1234
  }
1213
1235
  } catch (error) {
1214
- logger.error(ctx, "[ClaudeCode] Query error", {
1215
- error: error instanceof Error ? error.message : String(error),
1216
- model: req.model,
1217
- apiKeyPresent: !!apiKey,
1218
- cwd: config.workingDirectory,
1219
- mcpServers: Object.keys(config.mcpServers || {})
1220
- });
1221
- throw error;
1236
+ const rl = isRateLimitError(error);
1237
+ if (rl.matched) {
1238
+ sdkError = "rate_limit";
1239
+ rateLimit = {
1240
+ ...rl.resetsAt ? { resetsAt: rl.resetsAt } : rateLimit?.resetsAt ? { resetsAt: rateLimit.resetsAt } : {},
1241
+ ...rl.tier ? { tier: rl.tier } : rateLimit?.tier ? { tier: rateLimit.tier } : {}
1242
+ };
1243
+ logger.warn(ctx, "[ClaudeCode] Query throttled (hard rate limit)", {
1244
+ model: req.model,
1245
+ resetsAt: rl.resetsAt,
1246
+ tier: rl.tier
1247
+ });
1248
+ } else {
1249
+ logger.error(ctx, "[ClaudeCode] Query error", {
1250
+ error: error instanceof Error ? error.message : String(error),
1251
+ model: req.model,
1252
+ apiKeyPresent: !!apiKey,
1253
+ cwd: config.workingDirectory,
1254
+ mcpServers: Object.keys(config.mcpServers || {})
1255
+ });
1256
+ throw error;
1257
+ }
1222
1258
  }
1223
1259
  logger.info(ctx, "[ClaudeCode] Query complete", { messageCount });
1224
1260
  return {
1225
1261
  content: lastAssistantContent || aggregatedContent,
1226
1262
  json,
1227
1263
  error: sdkError,
1264
+ ...rateLimit ? { rateLimit } : {},
1228
1265
  toolCalls: void 0,
1229
1266
  metadata: {
1230
1267
  model: req.model,
@@ -1271,6 +1308,7 @@ function claudeCodeProvider(config = {}) {
1271
1308
  mcpServers: Object.keys(config.mcpServers || {})
1272
1309
  });
1273
1310
  let messageCount = 0;
1311
+ let streamRateLimit;
1274
1312
  try {
1275
1313
  for await (const message of claudeQuery({
1276
1314
  prompt: typeof prompt2 === "string" ? prompt2 : JSON.stringify(prompt2),
@@ -1365,6 +1403,13 @@ function claudeCodeProvider(config = {}) {
1365
1403
  }
1366
1404
  }
1367
1405
  }
1406
+ if (message.type === "rate_limit_event") {
1407
+ const ev = message;
1408
+ const resetsAt = ev.resetsAt ?? ev.resets_at ?? (typeof ev.resetTime === "number" ? new Date(ev.resetTime).toISOString() : void 0);
1409
+ const tier = ev.tier ?? ev.scope;
1410
+ streamRateLimit = { ...resetsAt ? { resetsAt } : {}, ...tier ? { tier } : {} };
1411
+ logger.info(ctx, "[ClaudeCode] rate_limit_event (soft warning)", { resetsAt, tier });
1412
+ }
1368
1413
  if (message.type === "result") {
1369
1414
  if ("usage" in message) {
1370
1415
  const usage = message.usage;
@@ -1377,6 +1422,7 @@ function claudeCodeProvider(config = {}) {
1377
1422
  content: "",
1378
1423
  // Text already yielded incrementally
1379
1424
  json: sc,
1425
+ ...streamRateLimit ? { rateLimit: streamRateLimit } : {},
1380
1426
  metadata: {
1381
1427
  model: req.model,
1382
1428
  usage: {
@@ -1391,6 +1437,33 @@ function claudeCodeProvider(config = {}) {
1391
1437
  }
1392
1438
  }
1393
1439
  } catch (error) {
1440
+ const rl = isRateLimitError(error);
1441
+ if (rl.matched) {
1442
+ const merged = {
1443
+ ...rl.resetsAt ? { resetsAt: rl.resetsAt } : streamRateLimit?.resetsAt ? { resetsAt: streamRateLimit.resetsAt } : {},
1444
+ ...rl.tier ? { tier: rl.tier } : streamRateLimit?.tier ? { tier: streamRateLimit.tier } : {}
1445
+ };
1446
+ logger.warn(ctx, "[ClaudeCode] Stream throttled (hard rate limit)", {
1447
+ model: req.model,
1448
+ ...merged
1449
+ });
1450
+ yield {
1451
+ content: "",
1452
+ error: "rate_limit",
1453
+ rateLimit: merged,
1454
+ metadata: {
1455
+ model: req.model,
1456
+ usage: {
1457
+ inputTokens,
1458
+ outputTokens,
1459
+ totalTokens: inputTokens + outputTokens
1460
+ },
1461
+ duration: Date.now() - startTime,
1462
+ provider: "claude-code"
1463
+ }
1464
+ };
1465
+ return;
1466
+ }
1394
1467
  logger.error(ctx, "[ClaudeCode] Stream error", {
1395
1468
  error: error instanceof Error ? error.message : String(error),
1396
1469
  model: req.model,
@@ -4438,13 +4511,20 @@ ${orig.content ?? ""}`
4438
4511
  runId,
4439
4512
  success: !response.error && !aborted
4440
4513
  });
4514
+ const isRateLimit = response.error === "rate_limit";
4441
4515
  return {
4442
4516
  message: response.content ?? "",
4443
4517
  success: !response.error && !aborted,
4444
4518
  cancelled: aborted,
4445
4519
  state: req.state ?? {},
4446
4520
  metadata: { inputTokens: 0, outputTokens: 0, totalTokens: 0, iterations: 0 },
4447
- ...response.error ? { exit: { reason: "error", message: response.error } } : {}
4521
+ ...isRateLimit ? {
4522
+ exit: {
4523
+ reason: "rate_limit",
4524
+ message: "Rate limited \u2014 try again in a moment.",
4525
+ ...response.rateLimit?.resetsAt ? { resetsAt: response.rateLimit.resetsAt } : {}
4526
+ }
4527
+ } : response.error ? { exit: { reason: "error", message: response.error } } : {}
4448
4528
  };
4449
4529
  } catch (err) {
4450
4530
  const aborted = abortController.signal.aborted;
@@ -4460,6 +4540,26 @@ ${orig.content ?? ""}`
4460
4540
  };
4461
4541
  }
4462
4542
  const message = err instanceof Error ? err.message : String(err);
4543
+ const e = err;
4544
+ const status = typeof e.status === "number" ? e.status : void 0;
4545
+ const name = typeof e.name === "string" ? e.name : "";
4546
+ const isRateLimit = status === 429 || /rate.?limit/i.test(message) || /rate.?limit/i.test(name);
4547
+ if (isRateLimit) {
4548
+ const resetsAt = typeof e.resetsAt === "string" ? e.resetsAt : void 0;
4549
+ logger.warn(ctx, "[claude-code] Throttled", { runId, resetsAt });
4550
+ return {
4551
+ message: "",
4552
+ success: false,
4553
+ cancelled: false,
4554
+ state: req.state ?? {},
4555
+ metadata: { inputTokens: 0, outputTokens: 0, totalTokens: 0, iterations: 0 },
4556
+ exit: {
4557
+ reason: "rate_limit",
4558
+ message: "Rate limited \u2014 try again in a moment.",
4559
+ ...resetsAt ? { resetsAt } : {}
4560
+ }
4561
+ };
4562
+ }
4463
4563
  logger.error(ctx, "[claude-code] Failed", { runId, error: message });
4464
4564
  return {
4465
4565
  message: "",
@@ -5334,6 +5434,13 @@ async function runTask(ctx, req) {
5334
5434
  content: result.message,
5335
5435
  error: result.exit?.message,
5336
5436
  interrupted: result.cancelled,
5437
+ ...result.exit ? {
5438
+ exit: {
5439
+ reason: result.exit.reason,
5440
+ message: result.exit.message,
5441
+ ...result.exit.resetsAt ? { resetsAt: result.exit.resetsAt } : {}
5442
+ }
5443
+ } : {},
5337
5444
  ...result.sessionId ? { sessionId: result.sessionId } : {}
5338
5445
  }
5339
5446
  });