@integrity-labs/agt-cli 0.28.225 → 0.28.227

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.
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-I4CQEDME.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-VZ44GVA4.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-JFP2N723.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-CGFYM63W.js.map
@@ -37,7 +37,7 @@ import {
37
37
  requireHost,
38
38
  safeWriteJsonAtomic,
39
39
  setConfigHash
40
- } from "../chunk-A36N2XXT.js";
40
+ } from "../chunk-VUPYJ4WU.js";
41
41
  import {
42
42
  getProjectDir as getProjectDir2,
43
43
  getReadyTasks,
@@ -122,7 +122,7 @@ import {
122
122
  takeZombieDetection,
123
123
  transcriptActivityAgeSeconds,
124
124
  writeEgressAllowlist
125
- } from "../chunk-S43WVYAF.js";
125
+ } from "../chunk-VV5IXUN6.js";
126
126
  import {
127
127
  reapOrphanChannelMcps
128
128
  } from "../chunk-XWVM4KPK.js";
@@ -1251,6 +1251,83 @@ function decideRestartGate(opts) {
1251
1251
  return "proceed";
1252
1252
  }
1253
1253
 
1254
+ // src/lib/model-api-error.ts
1255
+ function classifyHttpStatus(status) {
1256
+ if (status === 529) return "overloaded_529";
1257
+ if (status === 429) return "rate_limit_429";
1258
+ if (status >= 500 && status <= 599) return "server_error_5xx";
1259
+ return null;
1260
+ }
1261
+ function classifyModelApiError(input) {
1262
+ if (typeof input.status === "number") {
1263
+ const cls = classifyHttpStatus(input.status);
1264
+ if (cls) return { errorClass: cls, httpStatus: input.status };
1265
+ }
1266
+ const err = input.error;
1267
+ const rawMessage = input.message ?? (err instanceof Error ? err.message : typeof err === "string" ? err : "");
1268
+ const errName = err instanceof Error ? err.name : "";
1269
+ const haystack = `${errName} ${rawMessage}`.toLowerCase();
1270
+ if (!haystack.trim()) return null;
1271
+ const statusMatch = haystack.match(/returned\s+(\d{3})\b/);
1272
+ if (statusMatch) {
1273
+ const status = Number(statusMatch[1]);
1274
+ const cls = classifyHttpStatus(status);
1275
+ if (cls) return { errorClass: cls, httpStatus: status };
1276
+ }
1277
+ if (errName === "TimeoutError" || errName === "AbortError" || /\btimed?\s*out\b|\btimeout\b|\baborted\b|etimedout/.test(haystack)) {
1278
+ return { errorClass: "timeout", httpStatus: null };
1279
+ }
1280
+ if (/econnreset|econnrefused|enotfound|eai_again|epipe|socket hang up|network error|fetch failed|und_err/.test(
1281
+ haystack
1282
+ )) {
1283
+ return { errorClass: "connection_error", httpStatus: null };
1284
+ }
1285
+ if (/overloaded/.test(haystack)) {
1286
+ return { errorClass: "overloaded_529", httpStatus: null };
1287
+ }
1288
+ return null;
1289
+ }
1290
+ var AGENT_API_ERROR_RE = /API\s*Error[:\s]+(?:(\d{3})\b|([A-Za-z][^\n]{0,60}))/gi;
1291
+ function scrapeAgentRuntimeModelApiError(paneTail) {
1292
+ if (!paneTail) return null;
1293
+ let last = null;
1294
+ let m;
1295
+ AGENT_API_ERROR_RE.lastIndex = 0;
1296
+ while ((m = AGENT_API_ERROR_RE.exec(paneTail)) !== null) {
1297
+ if (m[1]) {
1298
+ const status = Number(m[1]);
1299
+ const cls = classifyHttpStatus(status);
1300
+ if (cls) last = { errorClass: cls, httpStatus: status };
1301
+ continue;
1302
+ }
1303
+ const text = (m[2] ?? "").toLowerCase();
1304
+ if (/overloaded/.test(text)) last = { errorClass: "overloaded_529", httpStatus: null };
1305
+ else if (/\btimed?\s*out\b|\btimeout\b/.test(text)) last = { errorClass: "timeout", httpStatus: null };
1306
+ }
1307
+ return last;
1308
+ }
1309
+ async function reportModelApiError(opts) {
1310
+ try {
1311
+ const hostId = await getHostId();
1312
+ if (!hostId) return;
1313
+ await api.post("/host/model-api-error-events", {
1314
+ host_id: hostId,
1315
+ agent_code_name: opts.agentCodeName ?? null,
1316
+ source: opts.source,
1317
+ error_class: opts.errorClass,
1318
+ http_status: opts.httpStatus ?? null,
1319
+ model_id: opts.modelId ?? null,
1320
+ // Content-free by contract, but bound it defensively.
1321
+ detail: opts.detail ? opts.detail.slice(0, 500) : null,
1322
+ occurred_at: opts.occurredAt ?? (/* @__PURE__ */ new Date()).toISOString()
1323
+ });
1324
+ } catch (err) {
1325
+ opts.log?.(
1326
+ `[model-api-error] report failed (${opts.source}/${opts.errorClass}): ${err instanceof Error ? err.message : String(err)}`
1327
+ );
1328
+ }
1329
+ }
1330
+
1254
1331
  // src/lib/claude-pid-tracker.ts
1255
1332
  import { existsSync, readFileSync as readFileSync5 } from "fs";
1256
1333
  function readPidFile(path) {
@@ -2179,6 +2256,7 @@ async function maybeEvaluateConversations(args) {
2179
2256
  } catch (err) {
2180
2257
  backendError = toHealthErrorMessage(err);
2181
2258
  log2(`[conversation-eval] ${codeName}: scoring failed: ${backendError}`);
2259
+ args.onModelCallError?.(err);
2182
2260
  continue;
2183
2261
  }
2184
2262
  if (!verdict) {
@@ -2394,6 +2472,7 @@ async function maybeExtractMemories(args) {
2394
2472
  candidates = parseCandidates(out);
2395
2473
  } catch (err) {
2396
2474
  log2(`[memory-extract] ${codeName}: extraction failed: ${err.message}`);
2475
+ args.onModelCallError?.(err);
2397
2476
  continue;
2398
2477
  }
2399
2478
  if (candidates === null) {
@@ -6055,6 +6134,11 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
6055
6134
  );
6056
6135
  }
6057
6136
  }
6137
+ var sessionToolRebindCooldownAt = /* @__PURE__ */ new Map();
6138
+ var SESSION_TOOL_REBIND_COOLDOWN_MS = 10 * 60 * 1e3;
6139
+ function sessionToolRebindKey(codeName, serverKey) {
6140
+ return `${codeName}\0${serverKey}`;
6141
+ }
6058
6142
  async function runAgentSessionToolBindProbes(agent, integrations, projectDir) {
6059
6143
  if (integrations.length === 0) return;
6060
6144
  const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
@@ -6074,6 +6158,36 @@ async function runAgentSessionToolBindProbes(agent, integrations, projectDir) {
6074
6158
  `Session-tool-bind probe for '${agent.code_name}': probed=${result.probed} reported=${result.reports.length} due=${result.due}`
6075
6159
  );
6076
6160
  }
6161
+ if (result && result.rebindCandidates.length > 0 && hostFlagStore().getBoolean("session-tool-rebind")) {
6162
+ let mcpJsonForRebind = null;
6163
+ try {
6164
+ mcpJsonForRebind = JSON.parse(readFileSync14(join16(projectDir, ".mcp.json"), "utf-8"));
6165
+ } catch {
6166
+ mcpJsonForRebind = null;
6167
+ }
6168
+ const isolated = isolationMode(agent.code_name) === "docker";
6169
+ const now = Date.now();
6170
+ for (const candidate of result.rebindCandidates) {
6171
+ const keysToReap = candidate.serverKeys.filter((k) => {
6172
+ const last = sessionToolRebindCooldownAt.get(sessionToolRebindKey(agent.code_name, k));
6173
+ return last === void 0 || now - last >= SESSION_TOOL_REBIND_COOLDOWN_MS;
6174
+ });
6175
+ if (keysToReap.length === 0) continue;
6176
+ reapStaleMcpChildren({
6177
+ log,
6178
+ codeName: agent.code_name,
6179
+ serverKeys: keysToReap,
6180
+ mcpJson: mcpJsonForRebind,
6181
+ isolated
6182
+ });
6183
+ for (const k of keysToReap) {
6184
+ sessionToolRebindCooldownAt.set(sessionToolRebindKey(agent.code_name, k), now);
6185
+ }
6186
+ log(
6187
+ `Session-tool rebind for '${agent.code_name}': ${candidate.status} integration=${candidate.integration_id} reaped MCP child(ren) [${keysToReap.join(", ")}] for respawn`
6188
+ );
6189
+ }
6190
+ }
6077
6191
  }
6078
6192
  function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gateReason = breakerReason) {
6079
6193
  const gate = restartGateFor(codeName, gateReason);
@@ -6242,6 +6356,7 @@ function clearAgentCaches(agentId, codeName) {
6242
6356
  claudeSchedulerStates.delete(codeName);
6243
6357
  claudeTaskConcurrency.delete(codeName);
6244
6358
  lastMcpFailedBannerCount.delete(codeName);
6359
+ lastModelApiErrorSig.delete(codeName);
6245
6360
  memoryFileHashes.delete(agentId);
6246
6361
  lastDownloadHash.delete(agentId);
6247
6362
  lastLocalFileHash.delete(agentId);
@@ -6258,7 +6373,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6258
6373
  var lastVersionCheckAt = 0;
6259
6374
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6260
6375
  var lastResponsivenessProbeAt = 0;
6261
- var agtCliVersion = true ? "0.28.225" : "dev";
6376
+ var agtCliVersion = true ? "0.28.227" : "dev";
6262
6377
  function resolveBrewPath(execFileSync2) {
6263
6378
  try {
6264
6379
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -6980,6 +7095,22 @@ function hostFlagStore() {
6980
7095
  }
6981
7096
  return _hostFlagStore;
6982
7097
  }
7098
+ function reportManagerModelCallError(source, err, modelId) {
7099
+ try {
7100
+ if (!hostFlagStore().getBoolean("model-api-error-reporting")) return;
7101
+ const classified = classifyModelApiError({ error: err });
7102
+ if (!classified) return;
7103
+ void reportModelApiError({
7104
+ source,
7105
+ errorClass: classified.errorClass,
7106
+ httpStatus: classified.httpStatus,
7107
+ modelId,
7108
+ detail: err instanceof Error ? err.message : String(err),
7109
+ log
7110
+ });
7111
+ } catch {
7112
+ }
7113
+ }
6983
7114
  function channelQuarantineMode() {
6984
7115
  return hostFlagStore().getString("channel-quarantine-mode");
6985
7116
  }
@@ -7167,7 +7298,7 @@ async function pollCycle() {
7167
7298
  }
7168
7299
  try {
7169
7300
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7170
- const { collectDiagnostics } = await import("../persistent-session-I4CQEDME.js");
7301
+ const { collectDiagnostics } = await import("../persistent-session-VZ44GVA4.js");
7171
7302
  const diagCodeNames = [...agentState.persistentSessionAgents];
7172
7303
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7173
7304
  let tailscaleHostname;
@@ -7315,7 +7446,7 @@ async function pollCycle() {
7315
7446
  const {
7316
7447
  collectResponsivenessProbes,
7317
7448
  getResponsivenessIntervalMs
7318
- } = await import("../responsiveness-probe-MIUMXKV4.js");
7449
+ } = await import("../responsiveness-probe-DLIVXYKX.js");
7319
7450
  const probeIntervalMs = getResponsivenessIntervalMs();
7320
7451
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7321
7452
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7347,7 +7478,7 @@ async function pollCycle() {
7347
7478
  collectResponsivenessProbes,
7348
7479
  livePendingInboundOldestAgeSeconds,
7349
7480
  parkPendingInbound
7350
- } = await import("../responsiveness-probe-MIUMXKV4.js");
7481
+ } = await import("../responsiveness-probe-DLIVXYKX.js");
7351
7482
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7352
7483
  const wedgeNow = /* @__PURE__ */ new Date();
7353
7484
  const liveAgents = agentState.persistentSessionAgents;
@@ -7480,11 +7611,27 @@ async function pollCycle() {
7480
7611
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
7481
7612
  const observations = [];
7482
7613
  const pendingCacheCommits = [];
7614
+ const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
7483
7615
  for (const codeName of agentState.persistentSessionAgents) {
7484
7616
  const agentId = agentState.codeNameToAgentId.get(codeName);
7485
7617
  if (!agentId) continue;
7486
7618
  const tail = readPaneLogTail(codeName, 40);
7487
7619
  if (!tail) continue;
7620
+ if (modelApiErrorReportingOn) {
7621
+ const observedErr = scrapeAgentRuntimeModelApiError(tail);
7622
+ const sig = observedErr ? `${observedErr.errorClass}:${observedErr.httpStatus ?? ""}` : "";
7623
+ if (observedErr && sig !== (lastModelApiErrorSig.get(codeName) ?? "")) {
7624
+ void reportModelApiError({
7625
+ source: "agent_runtime",
7626
+ errorClass: observedErr.errorClass,
7627
+ httpStatus: observedErr.httpStatus,
7628
+ agentCodeName: codeName,
7629
+ detail: `agent pane: ${observedErr.errorClass}`,
7630
+ log
7631
+ });
7632
+ }
7633
+ lastModelApiErrorSig.set(codeName, sig);
7634
+ }
7488
7635
  const observed = scrapeMcpFailedBannerCount(tail);
7489
7636
  const count = observed ?? 0;
7490
7637
  const last = lastMcpFailedBannerCount.get(codeName);
@@ -7602,7 +7749,7 @@ async function pollCycle() {
7602
7749
  if (restartedCodeNames.length > 0) {
7603
7750
  void (async () => {
7604
7751
  try {
7605
- const { collectDiagnostics } = await import("../persistent-session-I4CQEDME.js");
7752
+ const { collectDiagnostics } = await import("../persistent-session-VZ44GVA4.js");
7606
7753
  const freshDiagnostics = collectDiagnostics(restartedCodeNames);
7607
7754
  await api.post("/host/heartbeat", {
7608
7755
  host_id: hostId,
@@ -7833,21 +7980,25 @@ async function processAgent(agent, agentStates) {
7833
7980
  logMeteredScorerSuppressed();
7834
7981
  }
7835
7982
  if (!scorerSuppressed) {
7983
+ const evalBackend = resolveConversationEvalBackend();
7836
7984
  void maybeEvaluateConversations({
7837
7985
  api,
7838
- backend: resolveConversationEvalBackend(),
7986
+ backend: evalBackend,
7839
7987
  codeName: agent.code_name,
7840
7988
  agentId: agent.agent_id,
7841
- log
7989
+ log,
7990
+ onModelCallError: (err) => reportManagerModelCallError("conversation_eval", err, evalBackend.model ?? null)
7842
7991
  });
7843
7992
  }
7844
7993
  if (memoryExtractionEnabled() && !scorerSuppressed) {
7994
+ const memBackend = resolveConversationEvalBackend();
7845
7995
  void maybeExtractMemories({
7846
7996
  api,
7847
- backend: resolveConversationEvalBackend(),
7997
+ backend: memBackend,
7848
7998
  codeName: agent.code_name,
7849
7999
  agentId: agent.agent_id,
7850
- log
8000
+ log,
8001
+ onModelCallError: (err) => reportManagerModelCallError("memory_extraction", err, memBackend.model ?? null)
7851
8002
  });
7852
8003
  }
7853
8004
  }
@@ -9592,6 +9743,7 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
9592
9743
  });
9593
9744
  }
9594
9745
  var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
9746
+ var lastModelApiErrorSig = /* @__PURE__ */ new Map();
9595
9747
  var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
9596
9748
  var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
9597
9749
  var egressAllowlistBySession = /* @__PURE__ */ new Map();
@@ -10100,7 +10252,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
10100
10252
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
10101
10253
  void (async () => {
10102
10254
  try {
10103
- const { collectDiagnostics } = await import("../persistent-session-I4CQEDME.js");
10255
+ const { collectDiagnostics } = await import("../persistent-session-VZ44GVA4.js");
10104
10256
  await api.post("/host/heartbeat", {
10105
10257
  host_id: hostId,
10106
10258
  agent_diagnostics: collectDiagnostics([codeName])
@@ -10494,7 +10646,7 @@ async function processClaudePairSessions(agents) {
10494
10646
  killPairSession,
10495
10647
  pairTmuxSession,
10496
10648
  finalizeClaudePairOnboarding
10497
- } = await import("../claude-pair-runtime-JFP2N723.js");
10649
+ } = await import("../claude-pair-runtime-CGFYM63W.js");
10498
10650
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
10499
10651
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
10500
10652
  const killed = await killPairSession(pairTmuxSession(pairId));