@appchy/jarvis 0.1.23 → 0.1.25

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
  }
@@ -1063,6 +1077,9 @@ async function processAfterHooks(ctx, req) {
1063
1077
  }
1064
1078
  function claudeCodeProvider(config = {}) {
1065
1079
  const useSubscription = config.useSubscription ?? false;
1080
+ if (useSubscription && process.env.ANTHROPIC_API_KEY) {
1081
+ delete process.env.ANTHROPIC_API_KEY;
1082
+ }
1066
1083
  const apiKey = useSubscription ? void 0 : config.apiKey ?? process.env.ANTHROPIC_API_KEY;
1067
1084
  async function query(ctx, req, _options) {
1068
1085
  const { query: claudeQuery } = await import("@anthropic-ai/claude-agent-sdk");
@@ -1080,6 +1097,7 @@ function claudeCodeProvider(config = {}) {
1080
1097
  let lastAssistantContent = "";
1081
1098
  let json;
1082
1099
  let sdkError;
1100
+ let rateLimit;
1083
1101
  let inputTokens = 0;
1084
1102
  let outputTokens = 0;
1085
1103
  const isResuming = !!config.session?.resume;
@@ -1190,6 +1208,13 @@ function claudeCodeProvider(config = {}) {
1190
1208
  }
1191
1209
  }
1192
1210
  }
1211
+ if (message.type === "rate_limit_event") {
1212
+ const ev = message;
1213
+ const resetsAt = ev.resetsAt ?? ev.resets_at ?? (typeof ev.resetTime === "number" ? new Date(ev.resetTime).toISOString() : void 0);
1214
+ const tier = ev.tier ?? ev.scope;
1215
+ rateLimit = { ...resetsAt ? { resetsAt } : {}, ...tier ? { tier } : {} };
1216
+ logger.info(ctx, "[ClaudeCode] rate_limit_event (soft warning)", { resetsAt, tier });
1217
+ }
1193
1218
  if (message.type === "result") {
1194
1219
  const subtype = message.subtype;
1195
1220
  if (subtype && subtype !== "success") {
@@ -1211,20 +1236,35 @@ function claudeCodeProvider(config = {}) {
1211
1236
  }
1212
1237
  }
1213
1238
  } 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;
1239
+ const rl = isRateLimitError(error);
1240
+ if (rl.matched) {
1241
+ sdkError = "rate_limit";
1242
+ rateLimit = {
1243
+ ...rl.resetsAt ? { resetsAt: rl.resetsAt } : rateLimit?.resetsAt ? { resetsAt: rateLimit.resetsAt } : {},
1244
+ ...rl.tier ? { tier: rl.tier } : rateLimit?.tier ? { tier: rateLimit.tier } : {}
1245
+ };
1246
+ logger.warn(ctx, "[ClaudeCode] Query throttled (hard rate limit)", {
1247
+ model: req.model,
1248
+ resetsAt: rl.resetsAt,
1249
+ tier: rl.tier
1250
+ });
1251
+ } else {
1252
+ logger.error(ctx, "[ClaudeCode] Query error", {
1253
+ error: error instanceof Error ? error.message : String(error),
1254
+ model: req.model,
1255
+ apiKeyPresent: !!apiKey,
1256
+ cwd: config.workingDirectory,
1257
+ mcpServers: Object.keys(config.mcpServers || {})
1258
+ });
1259
+ throw error;
1260
+ }
1222
1261
  }
1223
1262
  logger.info(ctx, "[ClaudeCode] Query complete", { messageCount });
1224
1263
  return {
1225
1264
  content: lastAssistantContent || aggregatedContent,
1226
1265
  json,
1227
1266
  error: sdkError,
1267
+ ...rateLimit ? { rateLimit } : {},
1228
1268
  toolCalls: void 0,
1229
1269
  metadata: {
1230
1270
  model: req.model,
@@ -1271,6 +1311,7 @@ function claudeCodeProvider(config = {}) {
1271
1311
  mcpServers: Object.keys(config.mcpServers || {})
1272
1312
  });
1273
1313
  let messageCount = 0;
1314
+ let streamRateLimit;
1274
1315
  try {
1275
1316
  for await (const message of claudeQuery({
1276
1317
  prompt: typeof prompt2 === "string" ? prompt2 : JSON.stringify(prompt2),
@@ -1365,6 +1406,13 @@ function claudeCodeProvider(config = {}) {
1365
1406
  }
1366
1407
  }
1367
1408
  }
1409
+ if (message.type === "rate_limit_event") {
1410
+ const ev = message;
1411
+ const resetsAt = ev.resetsAt ?? ev.resets_at ?? (typeof ev.resetTime === "number" ? new Date(ev.resetTime).toISOString() : void 0);
1412
+ const tier = ev.tier ?? ev.scope;
1413
+ streamRateLimit = { ...resetsAt ? { resetsAt } : {}, ...tier ? { tier } : {} };
1414
+ logger.info(ctx, "[ClaudeCode] rate_limit_event (soft warning)", { resetsAt, tier });
1415
+ }
1368
1416
  if (message.type === "result") {
1369
1417
  if ("usage" in message) {
1370
1418
  const usage = message.usage;
@@ -1377,6 +1425,7 @@ function claudeCodeProvider(config = {}) {
1377
1425
  content: "",
1378
1426
  // Text already yielded incrementally
1379
1427
  json: sc,
1428
+ ...streamRateLimit ? { rateLimit: streamRateLimit } : {},
1380
1429
  metadata: {
1381
1430
  model: req.model,
1382
1431
  usage: {
@@ -1391,6 +1440,33 @@ function claudeCodeProvider(config = {}) {
1391
1440
  }
1392
1441
  }
1393
1442
  } catch (error) {
1443
+ const rl = isRateLimitError(error);
1444
+ if (rl.matched) {
1445
+ const merged = {
1446
+ ...rl.resetsAt ? { resetsAt: rl.resetsAt } : streamRateLimit?.resetsAt ? { resetsAt: streamRateLimit.resetsAt } : {},
1447
+ ...rl.tier ? { tier: rl.tier } : streamRateLimit?.tier ? { tier: streamRateLimit.tier } : {}
1448
+ };
1449
+ logger.warn(ctx, "[ClaudeCode] Stream throttled (hard rate limit)", {
1450
+ model: req.model,
1451
+ ...merged
1452
+ });
1453
+ yield {
1454
+ content: "",
1455
+ error: "rate_limit",
1456
+ rateLimit: merged,
1457
+ metadata: {
1458
+ model: req.model,
1459
+ usage: {
1460
+ inputTokens,
1461
+ outputTokens,
1462
+ totalTokens: inputTokens + outputTokens
1463
+ },
1464
+ duration: Date.now() - startTime,
1465
+ provider: "claude-code"
1466
+ }
1467
+ };
1468
+ return;
1469
+ }
1394
1470
  logger.error(ctx, "[ClaudeCode] Stream error", {
1395
1471
  error: error instanceof Error ? error.message : String(error),
1396
1472
  model: req.model,
@@ -4358,6 +4434,9 @@ function computeCost(model, usage) {
4358
4434
  return input + output + read2 + write;
4359
4435
  }
4360
4436
  function claudeCodeAgent(config = {}) {
4437
+ if (config.useSubscription && process.env.ANTHROPIC_API_KEY) {
4438
+ delete process.env.ANTHROPIC_API_KEY;
4439
+ }
4361
4440
  const activeRuns = /* @__PURE__ */ new Map();
4362
4441
  return {
4363
4442
  id: "claude-code",
@@ -4438,13 +4517,20 @@ ${orig.content ?? ""}`
4438
4517
  runId,
4439
4518
  success: !response.error && !aborted
4440
4519
  });
4520
+ const isRateLimit = response.error === "rate_limit";
4441
4521
  return {
4442
4522
  message: response.content ?? "",
4443
4523
  success: !response.error && !aborted,
4444
4524
  cancelled: aborted,
4445
4525
  state: req.state ?? {},
4446
4526
  metadata: { inputTokens: 0, outputTokens: 0, totalTokens: 0, iterations: 0 },
4447
- ...response.error ? { exit: { reason: "error", message: response.error } } : {}
4527
+ ...isRateLimit ? {
4528
+ exit: {
4529
+ reason: "rate_limit",
4530
+ message: "Rate limited \u2014 try again in a moment.",
4531
+ ...response.rateLimit?.resetsAt ? { resetsAt: response.rateLimit.resetsAt } : {}
4532
+ }
4533
+ } : response.error ? { exit: { reason: "error", message: response.error } } : {}
4448
4534
  };
4449
4535
  } catch (err) {
4450
4536
  const aborted = abortController.signal.aborted;
@@ -4460,6 +4546,26 @@ ${orig.content ?? ""}`
4460
4546
  };
4461
4547
  }
4462
4548
  const message = err instanceof Error ? err.message : String(err);
4549
+ const e = err;
4550
+ const status = typeof e.status === "number" ? e.status : void 0;
4551
+ const name = typeof e.name === "string" ? e.name : "";
4552
+ const isRateLimit = status === 429 || /rate.?limit/i.test(message) || /rate.?limit/i.test(name);
4553
+ if (isRateLimit) {
4554
+ const resetsAt = typeof e.resetsAt === "string" ? e.resetsAt : void 0;
4555
+ logger.warn(ctx, "[claude-code] Throttled", { runId, resetsAt });
4556
+ return {
4557
+ message: "",
4558
+ success: false,
4559
+ cancelled: false,
4560
+ state: req.state ?? {},
4561
+ metadata: { inputTokens: 0, outputTokens: 0, totalTokens: 0, iterations: 0 },
4562
+ exit: {
4563
+ reason: "rate_limit",
4564
+ message: "Rate limited \u2014 try again in a moment.",
4565
+ ...resetsAt ? { resetsAt } : {}
4566
+ }
4567
+ };
4568
+ }
4463
4569
  logger.error(ctx, "[claude-code] Failed", { runId, error: message });
4464
4570
  return {
4465
4571
  message: "",
@@ -5288,9 +5394,9 @@ function getWorkspacePath() {
5288
5394
  var provider2 = null;
5289
5395
  var pendingInputs = /* @__PURE__ */ new Map();
5290
5396
  function initAgent(c) {
5397
+ const useSubscription = c.useSubscription ?? !c.anthropicApiKey;
5291
5398
  provider2 = claudeCodeAgent({
5292
- apiKey: c.anthropicApiKey,
5293
- useSubscription: c.useSubscription,
5399
+ ...useSubscription ? { useSubscription: true } : { apiKey: c.anthropicApiKey },
5294
5400
  userId: c.userId,
5295
5401
  appUrl: c.appUrl,
5296
5402
  defaultWorkspace: getWorkspacePath()
@@ -5334,6 +5440,13 @@ async function runTask(ctx, req) {
5334
5440
  content: result.message,
5335
5441
  error: result.exit?.message,
5336
5442
  interrupted: result.cancelled,
5443
+ ...result.exit ? {
5444
+ exit: {
5445
+ reason: result.exit.reason,
5446
+ message: result.exit.message,
5447
+ ...result.exit.resetsAt ? { resetsAt: result.exit.resetsAt } : {}
5448
+ }
5449
+ } : {},
5337
5450
  ...result.sessionId ? { sessionId: result.sessionId } : {}
5338
5451
  }
5339
5452
  });
@@ -5534,7 +5647,7 @@ function codeAgents(config) {
5534
5647
 
5535
5648
  // src/chats.ts
5536
5649
  init_src6();
5537
- var claudeCode = claudeCodeAgent();
5650
+ var claudeCode = claudeCodeAgent({ useSubscription: true });
5538
5651
  var agentProvider = agents({ providers: [claudeCode] });
5539
5652
  var codeAgentProvider = codeAgents({ providers: [claudeCode] });
5540
5653
 
@@ -6967,7 +7080,7 @@ function register6(program) {
6967
7080
  console.log(` Connected: ${config.connectedAt}`);
6968
7081
  }
6969
7082
  } else {
6970
- console.log(` Config: Not set up. Run 'jarvis connect <token>'`);
7083
+ console.log(` Config: Not set up. Run 'jarvis start'`);
6971
7084
  }
6972
7085
  const svc = createServiceManager();
6973
7086
  const svcStatus = svc.status();