@integrity-labs/agt-cli 0.28.224 → 0.28.226

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.
@@ -18,7 +18,7 @@ import {
18
18
  resolveConnectivityProbe,
19
19
  worseConnectivityOutcome,
20
20
  wrapScheduledTaskPrompt
21
- } from "./chunk-S43WVYAF.js";
21
+ } from "./chunk-C2EXC6LY.js";
22
22
  import {
23
23
  parsePsRows
24
24
  } from "./chunk-XWVM4KPK.js";
@@ -5667,7 +5667,7 @@ function requireHost() {
5667
5667
  }
5668
5668
 
5669
5669
  // src/lib/api-client.ts
5670
- var agtCliVersion = true ? "0.28.224" : "dev";
5670
+ var agtCliVersion = true ? "0.28.226" : "dev";
5671
5671
  var lastConfigHash = null;
5672
5672
  function setConfigHash(hash) {
5673
5673
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7720,4 +7720,4 @@ export {
7720
7720
  managerInstallSystemUnitCommand,
7721
7721
  managerUninstallSystemUnitCommand
7722
7722
  };
7723
- //# sourceMappingURL=chunk-TPL4KIC5.js.map
7723
+ //# sourceMappingURL=chunk-IRMBTIZO.js.map
@@ -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-AIX7H4CC.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-NWOXCBWA.js.map
@@ -37,7 +37,7 @@ import {
37
37
  requireHost,
38
38
  safeWriteJsonAtomic,
39
39
  setConfigHash
40
- } from "../chunk-TPL4KIC5.js";
40
+ } from "../chunk-IRMBTIZO.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-C2EXC6LY.js";
126
126
  import {
127
127
  reapOrphanChannelMcps
128
128
  } from "../chunk-XWVM4KPK.js";
@@ -837,6 +837,21 @@ var MANAGED_MCP_SERVER_PREFIXES = [
837
837
  function isManagedMcpServerKey(key) {
838
838
  return MANAGED_MCP_SERVER_PREFIXES.some((p) => key.startsWith(p));
839
839
  }
840
+ function isRemoteMcpEntry(value) {
841
+ if (!value || typeof value !== "object") return false;
842
+ const e = value;
843
+ return e.type === "http" || e.type === "sse" || typeof e.url === "string" && e.command === void 0;
844
+ }
845
+ function orphanedRemoteMcpKeys(mcpServers, expectedIntegrationKeys) {
846
+ const orphans = [];
847
+ for (const [key, entry] of Object.entries(mcpServers)) {
848
+ if (expectedIntegrationKeys.has(key)) continue;
849
+ if (isManagedMcpServerKey(key)) continue;
850
+ if (!isRemoteMcpEntry(entry)) continue;
851
+ orphans.push(key);
852
+ }
853
+ return orphans;
854
+ }
840
855
 
841
856
  // src/lib/auto-resume.ts
842
857
  var DEFAULT_QUIET_MS = 18e5;
@@ -1236,6 +1251,83 @@ function decideRestartGate(opts) {
1236
1251
  return "proceed";
1237
1252
  }
1238
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
+
1239
1331
  // src/lib/claude-pid-tracker.ts
1240
1332
  import { existsSync, readFileSync as readFileSync5 } from "fs";
1241
1333
  function readPidFile(path) {
@@ -2164,6 +2256,7 @@ async function maybeEvaluateConversations(args) {
2164
2256
  } catch (err) {
2165
2257
  backendError = toHealthErrorMessage(err);
2166
2258
  log2(`[conversation-eval] ${codeName}: scoring failed: ${backendError}`);
2259
+ args.onModelCallError?.(err);
2167
2260
  continue;
2168
2261
  }
2169
2262
  if (!verdict) {
@@ -2379,6 +2472,7 @@ async function maybeExtractMemories(args) {
2379
2472
  candidates = parseCandidates(out);
2380
2473
  } catch (err) {
2381
2474
  log2(`[memory-extract] ${codeName}: extraction failed: ${err.message}`);
2475
+ args.onModelCallError?.(err);
2382
2476
  continue;
2383
2477
  }
2384
2478
  if (candidates === null) {
@@ -6227,6 +6321,7 @@ function clearAgentCaches(agentId, codeName) {
6227
6321
  claudeSchedulerStates.delete(codeName);
6228
6322
  claudeTaskConcurrency.delete(codeName);
6229
6323
  lastMcpFailedBannerCount.delete(codeName);
6324
+ lastModelApiErrorSig.delete(codeName);
6230
6325
  memoryFileHashes.delete(agentId);
6231
6326
  lastDownloadHash.delete(agentId);
6232
6327
  lastLocalFileHash.delete(agentId);
@@ -6243,7 +6338,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6243
6338
  var lastVersionCheckAt = 0;
6244
6339
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6245
6340
  var lastResponsivenessProbeAt = 0;
6246
- var agtCliVersion = true ? "0.28.224" : "dev";
6341
+ var agtCliVersion = true ? "0.28.226" : "dev";
6247
6342
  function resolveBrewPath(execFileSync2) {
6248
6343
  try {
6249
6344
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -6965,6 +7060,22 @@ function hostFlagStore() {
6965
7060
  }
6966
7061
  return _hostFlagStore;
6967
7062
  }
7063
+ function reportManagerModelCallError(source, err, modelId) {
7064
+ try {
7065
+ if (!hostFlagStore().getBoolean("model-api-error-reporting")) return;
7066
+ const classified = classifyModelApiError({ error: err });
7067
+ if (!classified) return;
7068
+ void reportModelApiError({
7069
+ source,
7070
+ errorClass: classified.errorClass,
7071
+ httpStatus: classified.httpStatus,
7072
+ modelId,
7073
+ detail: err instanceof Error ? err.message : String(err),
7074
+ log
7075
+ });
7076
+ } catch {
7077
+ }
7078
+ }
6968
7079
  function channelQuarantineMode() {
6969
7080
  return hostFlagStore().getString("channel-quarantine-mode");
6970
7081
  }
@@ -7152,7 +7263,7 @@ async function pollCycle() {
7152
7263
  }
7153
7264
  try {
7154
7265
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7155
- const { collectDiagnostics } = await import("../persistent-session-I4CQEDME.js");
7266
+ const { collectDiagnostics } = await import("../persistent-session-AIX7H4CC.js");
7156
7267
  const diagCodeNames = [...agentState.persistentSessionAgents];
7157
7268
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7158
7269
  let tailscaleHostname;
@@ -7300,7 +7411,7 @@ async function pollCycle() {
7300
7411
  const {
7301
7412
  collectResponsivenessProbes,
7302
7413
  getResponsivenessIntervalMs
7303
- } = await import("../responsiveness-probe-MIUMXKV4.js");
7414
+ } = await import("../responsiveness-probe-VBXDCOHO.js");
7304
7415
  const probeIntervalMs = getResponsivenessIntervalMs();
7305
7416
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7306
7417
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7332,7 +7443,7 @@ async function pollCycle() {
7332
7443
  collectResponsivenessProbes,
7333
7444
  livePendingInboundOldestAgeSeconds,
7334
7445
  parkPendingInbound
7335
- } = await import("../responsiveness-probe-MIUMXKV4.js");
7446
+ } = await import("../responsiveness-probe-VBXDCOHO.js");
7336
7447
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7337
7448
  const wedgeNow = /* @__PURE__ */ new Date();
7338
7449
  const liveAgents = agentState.persistentSessionAgents;
@@ -7465,11 +7576,27 @@ async function pollCycle() {
7465
7576
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
7466
7577
  const observations = [];
7467
7578
  const pendingCacheCommits = [];
7579
+ const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
7468
7580
  for (const codeName of agentState.persistentSessionAgents) {
7469
7581
  const agentId = agentState.codeNameToAgentId.get(codeName);
7470
7582
  if (!agentId) continue;
7471
7583
  const tail = readPaneLogTail(codeName, 40);
7472
7584
  if (!tail) continue;
7585
+ if (modelApiErrorReportingOn) {
7586
+ const observedErr = scrapeAgentRuntimeModelApiError(tail);
7587
+ const sig = observedErr ? `${observedErr.errorClass}:${observedErr.httpStatus ?? ""}` : "";
7588
+ if (observedErr && sig !== (lastModelApiErrorSig.get(codeName) ?? "")) {
7589
+ void reportModelApiError({
7590
+ source: "agent_runtime",
7591
+ errorClass: observedErr.errorClass,
7592
+ httpStatus: observedErr.httpStatus,
7593
+ agentCodeName: codeName,
7594
+ detail: `agent pane: ${observedErr.errorClass}`,
7595
+ log
7596
+ });
7597
+ }
7598
+ lastModelApiErrorSig.set(codeName, sig);
7599
+ }
7473
7600
  const observed = scrapeMcpFailedBannerCount(tail);
7474
7601
  const count = observed ?? 0;
7475
7602
  const last = lastMcpFailedBannerCount.get(codeName);
@@ -7587,7 +7714,7 @@ async function pollCycle() {
7587
7714
  if (restartedCodeNames.length > 0) {
7588
7715
  void (async () => {
7589
7716
  try {
7590
- const { collectDiagnostics } = await import("../persistent-session-I4CQEDME.js");
7717
+ const { collectDiagnostics } = await import("../persistent-session-AIX7H4CC.js");
7591
7718
  const freshDiagnostics = collectDiagnostics(restartedCodeNames);
7592
7719
  await api.post("/host/heartbeat", {
7593
7720
  host_id: hostId,
@@ -7818,21 +7945,25 @@ async function processAgent(agent, agentStates) {
7818
7945
  logMeteredScorerSuppressed();
7819
7946
  }
7820
7947
  if (!scorerSuppressed) {
7948
+ const evalBackend = resolveConversationEvalBackend();
7821
7949
  void maybeEvaluateConversations({
7822
7950
  api,
7823
- backend: resolveConversationEvalBackend(),
7951
+ backend: evalBackend,
7824
7952
  codeName: agent.code_name,
7825
7953
  agentId: agent.agent_id,
7826
- log
7954
+ log,
7955
+ onModelCallError: (err) => reportManagerModelCallError("conversation_eval", err, evalBackend.model ?? null)
7827
7956
  });
7828
7957
  }
7829
7958
  if (memoryExtractionEnabled() && !scorerSuppressed) {
7959
+ const memBackend = resolveConversationEvalBackend();
7830
7960
  void maybeExtractMemories({
7831
7961
  api,
7832
- backend: resolveConversationEvalBackend(),
7962
+ backend: memBackend,
7833
7963
  codeName: agent.code_name,
7834
7964
  agentId: agent.agent_id,
7835
- log
7965
+ log,
7966
+ onModelCallError: (err) => reportManagerModelCallError("memory_extraction", err, memBackend.model ?? null)
7836
7967
  });
7837
7968
  }
7838
7969
  }
@@ -8739,6 +8870,23 @@ async function processAgent(agent, agentStates) {
8739
8870
  log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
8740
8871
  }
8741
8872
  }
8873
+ if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
8874
+ const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
8875
+ if (mcpPath && existsSync8(mcpPath)) {
8876
+ try {
8877
+ const cfg = JSON.parse(readFileSync14(mcpPath, "utf-8"));
8878
+ const expectedRemoteKeys = new Set(
8879
+ integrations.map((i) => i.definition_id)
8880
+ );
8881
+ for (const key of orphanedRemoteMcpKeys(cfg.mcpServers ?? {}, expectedRemoteKeys)) {
8882
+ frameworkAdapter.removeMcpServer(agent.code_name, key);
8883
+ log(`[hot-reload] Removed orphaned remote MCP server '${key}' for '${agent.code_name}' (integration removed)`);
8884
+ }
8885
+ } catch (err) {
8886
+ log(`[hot-reload] Failed to prune orphaned remote MCP servers for '${agent.code_name}': ${err.message}`);
8887
+ }
8888
+ }
8889
+ }
8742
8890
  if (integrations.length > 0) {
8743
8891
  const intHash = computeIntegrationsHash(integrations);
8744
8892
  const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
@@ -9560,6 +9708,7 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
9560
9708
  });
9561
9709
  }
9562
9710
  var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
9711
+ var lastModelApiErrorSig = /* @__PURE__ */ new Map();
9563
9712
  var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
9564
9713
  var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
9565
9714
  var egressAllowlistBySession = /* @__PURE__ */ new Map();
@@ -10068,7 +10217,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
10068
10217
  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}`));
10069
10218
  void (async () => {
10070
10219
  try {
10071
- const { collectDiagnostics } = await import("../persistent-session-I4CQEDME.js");
10220
+ const { collectDiagnostics } = await import("../persistent-session-AIX7H4CC.js");
10072
10221
  await api.post("/host/heartbeat", {
10073
10222
  host_id: hostId,
10074
10223
  agent_diagnostics: collectDiagnostics([codeName])
@@ -10462,7 +10611,7 @@ async function processClaudePairSessions(agents) {
10462
10611
  killPairSession,
10463
10612
  pairTmuxSession,
10464
10613
  finalizeClaudePairOnboarding
10465
- } = await import("../claude-pair-runtime-JFP2N723.js");
10614
+ } = await import("../claude-pair-runtime-NWOXCBWA.js");
10466
10615
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
10467
10616
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
10468
10617
  const killed = await killPairSession(pairTmuxSession(pairId));