@integrity-labs/agt-cli 0.27.93 → 0.27.94

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/agt.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  success,
29
29
  table,
30
30
  warn
31
- } from "../chunk-5P3TU2TB.js";
31
+ } from "../chunk-2ITGJXXM.js";
32
32
  import {
33
33
  CHANNEL_REGISTRY,
34
34
  DEPLOYMENT_TEMPLATES,
@@ -4934,7 +4934,7 @@ import { execFileSync, execSync } from "child_process";
4934
4934
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4935
4935
  import chalk18 from "chalk";
4936
4936
  import ora16 from "ora";
4937
- var cliVersion = true ? "0.27.93" : "dev";
4937
+ var cliVersion = true ? "0.27.94" : "dev";
4938
4938
  async function fetchLatestVersion() {
4939
4939
  const host2 = getHost();
4940
4940
  if (!host2) return null;
@@ -5857,7 +5857,7 @@ function handleError(err) {
5857
5857
  }
5858
5858
 
5859
5859
  // src/bin/agt.ts
5860
- var cliVersion2 = true ? "0.27.93" : "dev";
5860
+ var cliVersion2 = true ? "0.27.94" : "dev";
5861
5861
  var program = new Command();
5862
5862
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
5863
5863
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -7578,4 +7578,4 @@ export {
7578
7578
  managerInstallSystemUnitCommand,
7579
7579
  managerUninstallSystemUnitCommand
7580
7580
  };
7581
- //# sourceMappingURL=chunk-5P3TU2TB.js.map
7581
+ //# sourceMappingURL=chunk-2ITGJXXM.js.map
@@ -16,7 +16,7 @@ import {
16
16
  provisionStopHook,
17
17
  requireHost,
18
18
  safeWriteJsonAtomic
19
- } from "../chunk-5P3TU2TB.js";
19
+ } from "../chunk-2ITGJXXM.js";
20
20
  import {
21
21
  getProjectDir as getProjectDir2,
22
22
  getReadyTasks,
@@ -3996,7 +3996,7 @@ var cachedMaintenanceWindow = null;
3996
3996
  var lastVersionCheckAt = 0;
3997
3997
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
3998
3998
  var lastResponsivenessProbeAt = 0;
3999
- var agtCliVersion = true ? "0.27.93" : "dev";
3999
+ var agtCliVersion = true ? "0.27.94" : "dev";
4000
4000
  function resolveBrewPath(execFileSync4) {
4001
4001
  try {
4002
4002
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14526,23 +14526,33 @@ var DEFAULT_THROTTLE = {
14526
14526
  windowMs: 12e4,
14527
14527
  ringSize: 8
14528
14528
  };
14529
- function decideReplyThrottle(input) {
14529
+ var DEFAULT_REPLY_QUEUE_DEPTH = 2;
14530
+ function planReplyDelivery(input) {
14530
14531
  const cfg = input.config ?? DEFAULT_THROTTLE;
14532
+ const maxDepth = input.maxQueueDepth ?? DEFAULT_REPLY_QUEUE_DEPTH;
14531
14533
  const cutoff = input.now - cfg.windowMs;
14532
- const inWindow = input.recentReplyTimestamps.filter((t) => t >= cutoff);
14533
- if (inWindow.length >= cfg.threshold) {
14534
- return {
14535
- allow: false,
14536
- recentCount: inWindow.length,
14537
- reason: "throttle_threshold_exceeded"
14538
- };
14534
+ const inWindow = input.recentReplyTimestamps.filter((t) => t >= cutoff).sort((a, b) => a - b);
14535
+ const occupancy = inWindow.length + input.queuedCount;
14536
+ if (occupancy < cfg.threshold) {
14537
+ return { action: "send", recentCount: inWindow.length, reason: "under_threshold" };
14538
+ }
14539
+ if (input.queuedCount >= maxDepth) {
14540
+ return { action: "refuse", recentCount: inWindow.length, reason: "queue_full" };
14539
14541
  }
14542
+ const idx = Math.min(input.queuedCount, inWindow.length - 1);
14543
+ const opensAt = (inWindow[idx] ?? input.now) + cfg.windowMs;
14540
14544
  return {
14541
- allow: true,
14545
+ action: "queue",
14546
+ deliverAtMs: Math.max(opensAt, input.now),
14542
14547
  recentCount: inWindow.length,
14543
- reason: "under_threshold"
14548
+ reason: "queued_for_slot"
14544
14549
  };
14545
14550
  }
14551
+ function relaxedThrottleConfig(cfg, env = process.env, envVar = "TELEGRAM_PRIVATE_REPLY_THROTTLE_COUNT") {
14552
+ const raw = Number(env[envVar]);
14553
+ const threshold = Number.isFinite(raw) && raw > 0 ? raw : cfg.threshold * 2;
14554
+ return { ...cfg, threshold, ringSize: Math.max(cfg.ringSize, threshold + 2) };
14555
+ }
14546
14556
  var buffers = /* @__PURE__ */ new Map();
14547
14557
  function key(channelId, threadKey) {
14548
14558
  return `${channelId}${threadKey}`;
@@ -16301,6 +16311,54 @@ var orphanSweepTimer = setInterval(() => {
16301
16311
  sweepTelegramStaleMarkers(sessionAlive ? channelOrphanMarkerMs() : STALE_MARKER_MS);
16302
16312
  }, orphanSweepIntervalMs());
16303
16313
  orphanSweepTimer.unref?.();
16314
+ var queuedReplyCounts = /* @__PURE__ */ new Map();
16315
+ function _resetQueuedReplyCountsForTests() {
16316
+ queuedReplyCounts.clear();
16317
+ }
16318
+ async function deliverQueuedReply(p) {
16319
+ const remaining = (queuedReplyCounts.get(p.chatId) ?? 1) - 1;
16320
+ if (remaining <= 0) queuedReplyCounts.delete(p.chatId);
16321
+ else queuedReplyCounts.set(p.chatId, remaining);
16322
+ try {
16323
+ const killed = await isThreadKilled({
16324
+ channelType: "telegram",
16325
+ channelId: p.chatId,
16326
+ threadTs: "",
16327
+ agtHost: AGT_HOST,
16328
+ agtApiKey: AGT_API_KEY
16329
+ });
16330
+ if (killed) {
16331
+ process.stderr.write(
16332
+ `telegram-channel(${AGENT_CODE_NAME}): reply_queue_dropped reason=killed chat=${redactId(p.chatId)}
16333
+ `
16334
+ );
16335
+ return;
16336
+ }
16337
+ const body = { chat_id: p.chatId, text: p.text };
16338
+ if (p.replyToMessageId) body.reply_to_message_id = Number(p.replyToMessageId);
16339
+ const data = await telegramApiCall("sendMessage", body, 15e3);
16340
+ if (!data.ok) {
16341
+ process.stderr.write(
16342
+ `telegram-channel(${AGENT_CODE_NAME}): reply_queue_failed chat=${redactId(p.chatId)} error=${data.description ?? "unknown"}
16343
+ `
16344
+ );
16345
+ return;
16346
+ }
16347
+ recordReply(p.chatId, "", Date.now(), p.throttleCfg);
16348
+ if (p.isReplyTool) {
16349
+ clearPendingMessage(p.chatId, p.replyToMessageId);
16350
+ }
16351
+ process.stderr.write(
16352
+ `telegram-channel(${AGENT_CODE_NAME}): reply_queue_delivered chat=${redactId(p.chatId)}
16353
+ `
16354
+ );
16355
+ } catch (err) {
16356
+ process.stderr.write(
16357
+ `telegram-channel(${AGENT_CODE_NAME}): reply_queue_failed chat=${redactId(p.chatId)} error=${err.message}
16358
+ `
16359
+ );
16360
+ }
16361
+ }
16304
16362
  function clearPendingMessage(chatId, messageId) {
16305
16363
  if (messageId) {
16306
16364
  clearPendingInboundMarker(chatId, messageId);
@@ -16534,28 +16592,56 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
16534
16592
  isError: true
16535
16593
  };
16536
16594
  }
16537
- const tgThrottleCfg = configFromEnv();
16595
+ const isPrivateChat = !chat_id.startsWith("-");
16596
+ const tgThrottleCfg = isPrivateChat ? relaxedThrottleConfig(configFromEnv()) : configFromEnv();
16538
16597
  const tgThrottleNow = Date.now();
16539
- const tgThrottleDecision = decideReplyThrottle({
16598
+ const tgPlan = planReplyDelivery({
16540
16599
  recentReplyTimestamps: getRecentReplies(chat_id, "", tgThrottleNow, tgThrottleCfg),
16600
+ queuedCount: queuedReplyCounts.get(chat_id) ?? 0,
16541
16601
  now: tgThrottleNow,
16542
16602
  config: tgThrottleCfg
16543
16603
  });
16544
- if (!tgThrottleDecision.allow) {
16604
+ if (tgPlan.action === "refuse") {
16545
16605
  process.stderr.write(
16546
- `telegram-channel(${AGENT_CODE_NAME}): reply_throttled chat=${redactId(chat_id)} count=${tgThrottleDecision.recentCount} window_ms=${tgThrottleCfg.windowMs} threshold=${tgThrottleCfg.threshold}
16606
+ `telegram-channel(${AGENT_CODE_NAME}): reply_throttled chat=${redactId(chat_id)} count=${tgPlan.recentCount} queued=${queuedReplyCounts.get(chat_id) ?? 0} window_ms=${tgThrottleCfg.windowMs} threshold=${tgThrottleCfg.threshold}
16547
16607
  `
16548
16608
  );
16549
16609
  return {
16550
16610
  content: [
16551
16611
  {
16552
16612
  type: "text",
16553
- text: `Reply throttled: ${tgThrottleDecision.recentCount} replies from this agent to this chat within the last ${Math.round(tgThrottleCfg.windowMs / 1e3)}s (threshold ${tgThrottleCfg.threshold}). The chat is paused for this agent until a human posts in it. Stop attempting to reply.`
16613
+ text: `Reply throttled: ${tgPlan.recentCount} replies from this agent to this chat within the last ${Math.round(tgThrottleCfg.windowMs / 1e3)}s (threshold ${tgThrottleCfg.threshold}) and the delivery queue is full. The chat is paused for this agent until a human posts in it. Stop attempting to reply.`
16554
16614
  }
16555
16615
  ],
16556
16616
  isError: true
16557
16617
  };
16558
16618
  }
16619
+ if (tgPlan.action === "queue" && tgPlan.deliverAtMs !== void 0) {
16620
+ const delayMs = Math.max(0, tgPlan.deliverAtMs - tgThrottleNow);
16621
+ queuedReplyCounts.set(chat_id, (queuedReplyCounts.get(chat_id) ?? 0) + 1);
16622
+ process.stderr.write(
16623
+ `telegram-channel(${AGENT_CODE_NAME}): reply_queued chat=${redactId(chat_id)} delay_ms=${delayMs} count=${tgPlan.recentCount} threshold=${tgThrottleCfg.threshold}
16624
+ `
16625
+ );
16626
+ const timer = setTimeout(() => {
16627
+ void deliverQueuedReply({
16628
+ chatId: chat_id,
16629
+ text,
16630
+ replyToMessageId: reply_to_message_id,
16631
+ isReplyTool: name === "telegram.reply",
16632
+ throttleCfg: tgThrottleCfg
16633
+ });
16634
+ }, delayMs);
16635
+ timer.unref();
16636
+ return {
16637
+ content: [
16638
+ {
16639
+ type: "text",
16640
+ text: `Reply queued, not yet sent: the reply-rate window is full (${tgPlan.recentCount} recent sends, threshold ${tgThrottleCfg.threshold}). It will be delivered automatically in ~${Math.ceil(delayMs / 1e3)}s. Do not re-send this message; avoid further sends to this chat until it delivers.`
16641
+ }
16642
+ ]
16643
+ };
16644
+ }
16559
16645
  try {
16560
16646
  const body = { chat_id, text };
16561
16647
  if (reply_to_message_id) body.reply_to_message_id = Number(reply_to_message_id);
@@ -17384,5 +17470,6 @@ pollLoop().catch((err) => {
17384
17470
  });
17385
17471
  export {
17386
17472
  __resetBackOnlineNoticeThrottle,
17387
- __resetUndeliverableNoticeThrottle
17473
+ __resetUndeliverableNoticeThrottle,
17474
+ _resetQueuedReplyCountsForTests
17388
17475
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.27.93",
3
+ "version": "0.27.94",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {