@openacp/cli 2026.328.2 → 2026.330.3

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.
Files changed (86) hide show
  1. package/dist/{adapter-HGJENQCN.js → adapter-AWSI4GML.js} +4 -4
  2. package/dist/api-server-5VNYFWJE.js +7 -0
  3. package/dist/{api-server-WFB5K6FP.js → api-server-JLBDKCU4.js} +2 -2
  4. package/dist/{chunk-5TCXYDLR.js → chunk-237WYH6H.js} +26 -3
  5. package/dist/chunk-237WYH6H.js.map +1 -0
  6. package/dist/{chunk-E2SLHZAC.js → chunk-2HEFALTZ.js} +6 -6
  7. package/dist/{chunk-I53NEV3S.js → chunk-5WGVYX3C.js} +13 -3
  8. package/dist/chunk-5WGVYX3C.js.map +1 -0
  9. package/dist/{chunk-IXMIC4GQ.js → chunk-BTJHGSLM.js} +2 -2
  10. package/dist/{chunk-43JVXFYP.js → chunk-GEOXPGCO.js} +2 -2
  11. package/dist/{chunk-JUFN4XMB.js → chunk-KDU3ZEWT.js} +2 -2
  12. package/dist/{chunk-QWP76EBW.js → chunk-MITTQMGZ.js} +16 -9
  13. package/dist/chunk-MITTQMGZ.js.map +1 -0
  14. package/dist/{chunk-QBEQJFGL.js → chunk-MPGEHTGE.js} +3 -3
  15. package/dist/{chunk-4B6PCWQP.js → chunk-PA6MNBG4.js} +6 -2
  16. package/dist/chunk-PA6MNBG4.js.map +1 -0
  17. package/dist/{chunk-VD3QSMVY.js → chunk-QWVHCTCA.js} +2 -2
  18. package/dist/{chunk-NT6FYV27.js → chunk-TMVTSWVH.js} +2 -2
  19. package/dist/{chunk-6VR4GWOO.js → chunk-UCIZM5SW.js} +247 -70
  20. package/dist/chunk-UCIZM5SW.js.map +1 -0
  21. package/dist/chunk-UWH7KIAA.js +701 -0
  22. package/dist/chunk-UWH7KIAA.js.map +1 -0
  23. package/dist/{chunk-JOMDPFQ2.js → chunk-W4LK6WJP.js} +29 -4
  24. package/dist/chunk-W4LK6WJP.js.map +1 -0
  25. package/dist/{chunk-RXMWJHWH.js → chunk-XBZIHNKV.js} +733 -221
  26. package/dist/chunk-XBZIHNKV.js.map +1 -0
  27. package/dist/cli.js +63 -68
  28. package/dist/cli.js.map +1 -1
  29. package/dist/config-KN6NKKPF.js +20 -0
  30. package/dist/{config-editor-OU6PUY66.js → config-editor-76RVZS4B.js} +3 -3
  31. package/dist/context-NXXW62NJ.js +9 -0
  32. package/dist/{core-plugins-R2EVZAJV.js → core-plugins-BPZY7SEB.js} +9 -9
  33. package/dist/{daemon-DTA6KYYY.js → daemon-XFEMMJSZ.js} +3 -3
  34. package/dist/doctor-AV6AUO22.js +9 -0
  35. package/dist/index.d.ts +110 -44
  36. package/dist/index.js +8 -8
  37. package/dist/{main-RRSX5SRL.js → main-VEJCG5PY.js} +38 -30
  38. package/dist/main-VEJCG5PY.js.map +1 -0
  39. package/dist/{plugin-installer-5XHORMLS.js → plugin-installer-VSTYZSXC.js} +2 -2
  40. package/dist/{setup-OI6A3OXW.js → setup-DISPNDEK.js} +4 -5
  41. package/dist/setup-DISPNDEK.js.map +1 -0
  42. package/dist/speech-SG62JYIF.js +9 -0
  43. package/dist/telegram-L3YM6SQJ.js +7 -0
  44. package/dist/tunnel-HWJ27WDH.js +7 -0
  45. package/dist/{tunnel-service-I2NFUX3V.js → tunnel-service-ZMO4THKE.js} +88 -8
  46. package/dist/tunnel-service-ZMO4THKE.js.map +1 -0
  47. package/package.json +1 -1
  48. package/dist/api-server-DSUW637I.js +0 -7
  49. package/dist/chunk-4B6PCWQP.js.map +0 -1
  50. package/dist/chunk-5TCXYDLR.js.map +0 -1
  51. package/dist/chunk-6VR4GWOO.js.map +0 -1
  52. package/dist/chunk-I53NEV3S.js.map +0 -1
  53. package/dist/chunk-JOMDPFQ2.js.map +0 -1
  54. package/dist/chunk-QWP76EBW.js.map +0 -1
  55. package/dist/chunk-RXMWJHWH.js.map +0 -1
  56. package/dist/chunk-ZHGPZBS4.js +0 -49
  57. package/dist/chunk-ZHGPZBS4.js.map +0 -1
  58. package/dist/config-UCAFCS5W.js +0 -14
  59. package/dist/context-7MPU7RL5.js +0 -9
  60. package/dist/doctor-D723IB2I.js +0 -9
  61. package/dist/main-RRSX5SRL.js.map +0 -1
  62. package/dist/setup-OI6A3OXW.js.map +0 -1
  63. package/dist/speech-GB7PHVQZ.js +0 -9
  64. package/dist/telegram-UVIAXADE.js +0 -7
  65. package/dist/tunnel-4WNFC7GO.js +0 -7
  66. package/dist/tunnel-service-I2NFUX3V.js.map +0 -1
  67. /package/dist/{adapter-HGJENQCN.js.map → adapter-AWSI4GML.js.map} +0 -0
  68. /package/dist/{api-server-DSUW637I.js.map → api-server-5VNYFWJE.js.map} +0 -0
  69. /package/dist/{api-server-WFB5K6FP.js.map → api-server-JLBDKCU4.js.map} +0 -0
  70. /package/dist/{chunk-E2SLHZAC.js.map → chunk-2HEFALTZ.js.map} +0 -0
  71. /package/dist/{chunk-IXMIC4GQ.js.map → chunk-BTJHGSLM.js.map} +0 -0
  72. /package/dist/{chunk-43JVXFYP.js.map → chunk-GEOXPGCO.js.map} +0 -0
  73. /package/dist/{chunk-JUFN4XMB.js.map → chunk-KDU3ZEWT.js.map} +0 -0
  74. /package/dist/{chunk-QBEQJFGL.js.map → chunk-MPGEHTGE.js.map} +0 -0
  75. /package/dist/{chunk-VD3QSMVY.js.map → chunk-QWVHCTCA.js.map} +0 -0
  76. /package/dist/{chunk-NT6FYV27.js.map → chunk-TMVTSWVH.js.map} +0 -0
  77. /package/dist/{config-UCAFCS5W.js.map → config-KN6NKKPF.js.map} +0 -0
  78. /package/dist/{config-editor-OU6PUY66.js.map → config-editor-76RVZS4B.js.map} +0 -0
  79. /package/dist/{context-7MPU7RL5.js.map → context-NXXW62NJ.js.map} +0 -0
  80. /package/dist/{core-plugins-R2EVZAJV.js.map → core-plugins-BPZY7SEB.js.map} +0 -0
  81. /package/dist/{daemon-DTA6KYYY.js.map → daemon-XFEMMJSZ.js.map} +0 -0
  82. /package/dist/{doctor-D723IB2I.js.map → doctor-AV6AUO22.js.map} +0 -0
  83. /package/dist/{plugin-installer-5XHORMLS.js.map → plugin-installer-VSTYZSXC.js.map} +0 -0
  84. /package/dist/{speech-GB7PHVQZ.js.map → speech-SG62JYIF.js.map} +0 -0
  85. /package/dist/{telegram-UVIAXADE.js.map → telegram-L3YM6SQJ.js.map} +0 -0
  86. /package/dist/{tunnel-4WNFC7GO.js.map → tunnel-HWJ27WDH.js.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-AFKX424Q.js";
8
8
  import {
9
9
  DoctorEngine
10
- } from "./chunk-43JVXFYP.js";
10
+ } from "./chunk-GEOXPGCO.js";
11
11
  import {
12
12
  CheckpointReader,
13
13
  DEFAULT_MAX_TOKENS
@@ -65,6 +65,53 @@ function buildDeepLink(chatId, threadId, messageId) {
65
65
  // src/plugins/telegram/commands/new-session.ts
66
66
  import { InlineKeyboard as InlineKeyboard2 } from "grammy";
67
67
 
68
+ // src/core/adapter-primitives/format-types.ts
69
+ var STATUS_ICONS = {
70
+ pending: "\u23F3",
71
+ in_progress: "\u{1F504}",
72
+ completed: "\u2705",
73
+ failed: "\u274C",
74
+ cancelled: "\u{1F6AB}",
75
+ running: "\u{1F504}",
76
+ done: "\u2705",
77
+ error: "\u274C"
78
+ };
79
+ var KIND_ICONS = {
80
+ read: "\u{1F4D6}",
81
+ edit: "\u270F\uFE0F",
82
+ write: "\u270F\uFE0F",
83
+ delete: "\u{1F5D1}\uFE0F",
84
+ execute: "\u25B6\uFE0F",
85
+ command: "\u25B6\uFE0F",
86
+ bash: "\u25B6\uFE0F",
87
+ terminal: "\u25B6\uFE0F",
88
+ search: "\u{1F50D}",
89
+ web: "\u{1F310}",
90
+ fetch: "\u{1F310}",
91
+ agent: "\u{1F9E0}",
92
+ think: "\u{1F9E0}",
93
+ install: "\u{1F4E6}",
94
+ move: "\u{1F4E6}",
95
+ other: "\u{1F6E0}\uFE0F"
96
+ };
97
+ var KIND_LABELS = {
98
+ read: "Read",
99
+ edit: "Edit",
100
+ write: "Write",
101
+ delete: "Delete",
102
+ execute: "Run",
103
+ bash: "Bash",
104
+ command: "Run",
105
+ terminal: "Terminal",
106
+ search: "Search",
107
+ web: "Web",
108
+ fetch: "Fetch",
109
+ agent: "Agent",
110
+ think: "Agent",
111
+ install: "Install",
112
+ move: "Move"
113
+ };
114
+
68
115
  // src/core/adapter-primitives/format-utils.ts
69
116
  function progressBar(ratio, length = 10) {
70
117
  const filled = Math.round(Math.min(ratio, 1) * length);
@@ -125,36 +172,6 @@ function splitMessage(text, maxLength) {
125
172
  return chunks;
126
173
  }
127
174
 
128
- // src/core/adapter-primitives/format-types.ts
129
- var STATUS_ICONS = {
130
- pending: "\u23F3",
131
- in_progress: "\u{1F504}",
132
- completed: "\u2705",
133
- failed: "\u274C",
134
- cancelled: "\u{1F6AB}",
135
- running: "\u{1F504}",
136
- done: "\u2705",
137
- error: "\u274C"
138
- };
139
- var KIND_ICONS = {
140
- read: "\u{1F4D6}",
141
- edit: "\u270F\uFE0F",
142
- write: "\u270F\uFE0F",
143
- delete: "\u{1F5D1}\uFE0F",
144
- execute: "\u25B6\uFE0F",
145
- command: "\u25B6\uFE0F",
146
- bash: "\u25B6\uFE0F",
147
- terminal: "\u25B6\uFE0F",
148
- search: "\u{1F50D}",
149
- web: "\u{1F310}",
150
- fetch: "\u{1F310}",
151
- agent: "\u{1F9E0}",
152
- think: "\u{1F9E0}",
153
- install: "\u{1F4E6}",
154
- move: "\u{1F4E6}",
155
- other: "\u{1F6E0}\uFE0F"
156
- };
157
-
158
175
  // src/core/adapter-primitives/message-formatter.ts
159
176
  function extractContentText(content, depth = 0) {
160
177
  if (!content || depth > 5) return "";
@@ -419,58 +436,85 @@ function renderToolCard(snap) {
419
436
  const { totalVisible, completedVisible, allComplete } = snap;
420
437
  const headerCheck = allComplete ? " \u2705" : "";
421
438
  if (totalVisible > 0) {
422
- sections.push(
423
- `<b>\u{1F4CB} Tools (${completedVisible}/${totalVisible})</b>${headerCheck}`
424
- );
439
+ sections.push(`<b>\u{1F4CB} Tools (${completedVisible}/${totalVisible})</b>${headerCheck}`);
425
440
  }
426
- const visible = snap.entries.filter((e) => !e.hidden);
427
- const completed = visible.filter(
428
- (e) => e.status === "completed" || e.status === "done" || e.status === "failed"
429
- );
430
- const running = visible.filter(
431
- (e) => e.status !== "completed" && e.status !== "done" && e.status !== "failed"
432
- );
433
- for (const entry of completed) {
434
- let line = `${entry.icon} ${escapeHtml(entry.label)}`;
435
- if (entry.viewerLinks) {
436
- const links = [];
437
- const fileName = entry.viewerFilePath?.split("/").pop() ?? "";
438
- if (entry.viewerLinks.file)
439
- links.push(
440
- `<a href="${escapeHtml(entry.viewerLinks.file)}">View ${escapeHtml(fileName || "file")}</a>`
441
- );
442
- if (entry.viewerLinks.diff)
443
- links.push(
444
- `<a href="${escapeHtml(entry.viewerLinks.diff)}">View diff</a>`
445
- );
446
- if (links.length > 0) line += `
447
- ${links.join(" \xB7 ")}`;
448
- }
449
- sections.push(line);
441
+ const DONE = /* @__PURE__ */ new Set(["completed", "done", "failed", "error"]);
442
+ const visible = snap.specs.filter((s) => !s.isHidden);
443
+ const completed = visible.filter((s) => DONE.has(s.status));
444
+ const running = visible.filter((s) => !DONE.has(s.status));
445
+ for (const spec of completed) {
446
+ sections.push(renderSpecSection(spec));
450
447
  }
451
448
  if (snap.planEntries && snap.planEntries.length > 0) {
452
- const planDone = snap.planEntries.filter(
453
- (e) => e.status === "completed"
454
- ).length;
449
+ const planDone = snap.planEntries.filter((e) => e.status === "completed").length;
455
450
  const planTotal = snap.planEntries.length;
456
451
  sections.push(`\u2500\u2500 Plan: ${planDone}/${planTotal} \u2500\u2500`);
457
- const statusIcon = {
458
- completed: "\u2705",
459
- in_progress: "\u{1F504}",
460
- pending: "\u2B1C"
461
- };
452
+ const statusIcon = { completed: "\u2705", in_progress: "\u{1F504}", pending: "\u2B1C" };
462
453
  for (let i = 0; i < snap.planEntries.length; i++) {
463
454
  const e = snap.planEntries[i];
464
- const icon = statusIcon[e.status] ?? "\u2B1C";
465
- sections.push(`${icon} ${i + 1}. ${escapeHtml(e.content)}`);
455
+ sections.push(`${statusIcon[e.status] ?? "\u2B1C"} ${i + 1}. ${escapeHtml(e.content)}`);
466
456
  }
467
457
  sections.push("\u2500\u2500\u2500\u2500");
468
458
  }
469
- for (const entry of running) {
470
- sections.push(`${entry.icon} ${escapeHtml(entry.label)}`);
459
+ for (const spec of running) {
460
+ sections.push(renderSpecSection(spec));
471
461
  }
472
462
  return sections.join("\n\n");
473
463
  }
464
+ var FILE_KINDS = /* @__PURE__ */ new Set(["read", "edit", "write", "delete"]);
465
+ function shortenTitle(title, kind) {
466
+ if (!FILE_KINDS.has(kind) || !title.includes("/")) return title;
467
+ const parenIdx = title.indexOf(" (");
468
+ const pathPart = parenIdx > 0 ? title.slice(0, parenIdx) : title;
469
+ const rangePart = parenIdx > 0 ? title.slice(parenIdx) : "";
470
+ const fileName = pathPart.split("/").pop() || pathPart;
471
+ return fileName + rangePart;
472
+ }
473
+ function renderSpecSection(spec) {
474
+ const lines = [];
475
+ const DONE = /* @__PURE__ */ new Set(["completed", "done", "failed", "error"]);
476
+ const statusPrefix = spec.status === "error" || spec.status === "failed" ? "\u274C " : DONE.has(spec.status) ? "\u2705 " : "\u{1F504} ";
477
+ const kindLabel = KIND_LABELS[spec.kind];
478
+ const displayTitle = shortenTitle(spec.title, spec.kind);
479
+ const hasUniqueTitle = displayTitle && displayTitle.toLowerCase() !== kindLabel?.toLowerCase() && displayTitle.toLowerCase() !== spec.kind;
480
+ let titleLine;
481
+ if (kindLabel) {
482
+ titleLine = hasUniqueTitle ? `${statusPrefix}${spec.icon} <b>${kindLabel}</b> \xB7 ${escapeHtml(displayTitle)}` : `${statusPrefix}${spec.icon} <b>${kindLabel}</b>`;
483
+ } else {
484
+ titleLine = `${statusPrefix}${spec.icon} ${escapeHtml(displayTitle)}`;
485
+ }
486
+ if (spec.diffStats) {
487
+ const { added, removed } = spec.diffStats;
488
+ if (added > 0 && removed > 0) titleLine += ` \xB7 <i>+${added}/-${removed} lines</i>`;
489
+ else if (added > 0) titleLine += ` \xB7 <i>+${added} lines</i>`;
490
+ else if (removed > 0) titleLine += ` \xB7 <i>-${removed} lines</i>`;
491
+ }
492
+ lines.push(titleLine);
493
+ if (spec.description) lines.push(` <i>${escapeHtml(spec.description)}</i>`);
494
+ if (spec.command) lines.push(` <code>${escapeHtml(spec.command)}</code>`);
495
+ if (spec.inputContent) {
496
+ const truncated = spec.inputContent.length > 800 ? spec.inputContent.slice(0, 797) + "\u2026" : spec.inputContent;
497
+ lines.push(` <pre><code>${escapeHtml(truncated)}</code></pre>`);
498
+ }
499
+ if (spec.outputSummary) lines.push(` \xB7 ${escapeHtml(spec.outputSummary)}`);
500
+ if (spec.outputContent || spec.outputFallbackContent) {
501
+ const raw = spec.outputContent ?? spec.outputFallbackContent;
502
+ const truncated = raw.length > 800 ? raw.slice(0, 797) + "\u2026" : raw;
503
+ lines.push(` <pre><code>${escapeHtml(truncated)}</code></pre>`);
504
+ }
505
+ if (spec.viewerLinks?.file || spec.viewerLinks?.diff || spec.outputViewerLink) {
506
+ const linkParts = [];
507
+ const shortName = displayTitle || kindLabel || spec.kind;
508
+ if (spec.viewerLinks?.file)
509
+ linkParts.push(`<a href="${escapeHtml(spec.viewerLinks.file)}">View ${escapeHtml(shortName)}</a>`);
510
+ if (spec.viewerLinks?.diff)
511
+ linkParts.push(`<a href="${escapeHtml(spec.viewerLinks.diff)}">View diff</a>`);
512
+ if (spec.outputViewerLink)
513
+ linkParts.push(`<a href="${escapeHtml(spec.outputViewerLink)}">View output</a>`);
514
+ lines.push(` ${linkParts.join(" \xB7 ")}`);
515
+ }
516
+ return lines.join("\n");
517
+ }
474
518
  var TELEGRAM_MAX_LENGTH = 4096;
475
519
  function splitToolCardText(text) {
476
520
  if (text.length <= TELEGRAM_MAX_LENGTH) return [text];
@@ -478,12 +522,13 @@ function splitToolCardText(text) {
478
522
  const chunks = [];
479
523
  let current = "";
480
524
  for (const section of sections) {
525
+ const safeSection = section.length > TELEGRAM_MAX_LENGTH ? section.slice(0, TELEGRAM_MAX_LENGTH - 3) + "..." : section;
481
526
  const candidate = current ? `${current}
482
527
 
483
- ${section}` : section;
528
+ ${safeSection}` : safeSection;
484
529
  if (candidate.length > TELEGRAM_MAX_LENGTH && current) {
485
530
  chunks.push(current);
486
- current = section;
531
+ current = safeSection;
487
532
  } else {
488
533
  current = candidate;
489
534
  }
@@ -747,33 +792,75 @@ async function handleTTS(ctx, core) {
747
792
  });
748
793
  }
749
794
  }
750
- var VERBOSITY_LABELS = {
795
+ async function handleVerbosity(ctx, core) {
796
+ await ctx.reply("\u26A0\uFE0F <code>/verbosity</code> is deprecated. Use <code>/outputmode</code> instead.", { parse_mode: "HTML" });
797
+ await handleOutputMode(ctx, core);
798
+ }
799
+ var OUTPUT_MODE_LABELS = {
751
800
  low: "\u{1F507} Low",
752
801
  medium: "\u{1F4CA} Medium",
753
- high: "\u{1F4D6} High"
802
+ high: "\u{1F50D} High"
754
803
  };
755
- async function handleVerbosity(ctx, core) {
804
+ async function handleOutputMode(ctx, core) {
756
805
  const args = ctx.message?.text?.split(/\s+/).slice(1) ?? [];
757
- const arg = args[0]?.toLowerCase();
758
- if (arg === "low" || arg === "medium" || arg === "high") {
806
+ const arg0 = args[0]?.toLowerCase();
807
+ const arg1 = args[1]?.toLowerCase();
808
+ if (arg0 === "session") {
809
+ const chatId = ctx.chat?.id;
810
+ const threadId = ctx.message?.message_thread_id;
811
+ if (!chatId || threadId === void 0) {
812
+ await ctx.reply("\u26A0\uFE0F This command must be used in a session topic.", { parse_mode: "HTML" });
813
+ return;
814
+ }
815
+ const session = core.sessionManager.getSessionByThread(
816
+ "telegram",
817
+ String(threadId)
818
+ );
819
+ if (!session) {
820
+ await ctx.reply("\u26A0\uFE0F No active session found for this topic.", { parse_mode: "HTML" });
821
+ return;
822
+ }
823
+ if (arg1 === "reset") {
824
+ await core.sessionManager.patchRecord(session.id, { outputMode: void 0 });
825
+ await ctx.reply("\u{1F504} Session output mode reset to adapter default.", { parse_mode: "HTML" });
826
+ } else if (arg1 === "low" || arg1 === "medium" || arg1 === "high") {
827
+ await core.sessionManager.patchRecord(session.id, { outputMode: arg1 });
828
+ await ctx.reply(
829
+ `${OUTPUT_MODE_LABELS[arg1]} Session output mode set to <b>${arg1}</b>.`,
830
+ { parse_mode: "HTML" }
831
+ );
832
+ } else {
833
+ const record = core.sessionManager.getSessionRecord(session.id);
834
+ const current = record?.outputMode ?? "(adapter default)";
835
+ await ctx.reply(
836
+ `\u{1F4CA} Session output mode: <b>${current}</b>
837
+
838
+ Usage: <code>/outputmode session low|medium|high|reset</code>`,
839
+ { parse_mode: "HTML" }
840
+ );
841
+ }
842
+ return;
843
+ }
844
+ if (arg0 === "low" || arg0 === "medium" || arg0 === "high") {
759
845
  await core.configManager.save(
760
- { channels: { telegram: { displayVerbosity: arg } } },
761
- "channels.telegram.displayVerbosity"
846
+ { channels: { telegram: { outputMode: arg0 } } },
847
+ "channels.telegram.outputMode"
762
848
  );
763
849
  await ctx.reply(
764
- `${VERBOSITY_LABELS[arg]} Display verbosity set to <b>${arg}</b>.`,
850
+ `${OUTPUT_MODE_LABELS[arg0]} Output mode set to <b>${arg0}</b>.`,
765
851
  { parse_mode: "HTML" }
766
852
  );
767
853
  } else {
768
- const current = core.configManager.get().channels?.telegram?.displayVerbosity ?? "medium";
854
+ const current = core.configManager.get().channels?.telegram?.outputMode ?? "medium";
769
855
  await ctx.reply(
770
- `\u{1F4CA} Current verbosity: <b>${current}</b>
856
+ `\u{1F4CA} Current output mode: <b>${current}</b>
771
857
 
772
- Usage: <code>/verbosity low|medium|high</code>
858
+ Usage: <code>/outputmode low|medium|high</code>
859
+ Session override: <code>/outputmode session low|medium|high|reset</code>
773
860
 
774
- \u2022 <b>low</b> \u2014 minimal output, title only
775
- \u2022 <b>medium</b> \u2014 balanced (default)
776
- \u2022 <b>high</b> \u2014 full detail with content`,
861
+ \u2022 <b>low</b> \u2014 minimal: title only
862
+ \u2022 <b>medium</b> \u2014 balanced: description + output summary (default)
863
+ \u2022 <b>high</b> \u2014 full detail: inline output, IN/OUT blocks`,
777
864
  { parse_mode: "HTML" }
778
865
  );
779
866
  }
@@ -783,12 +870,12 @@ function setupVerbosityCallbacks(bot, core) {
783
870
  const level = ctx.callbackQuery.data.slice(3);
784
871
  if (level !== "low" && level !== "medium" && level !== "high") return;
785
872
  await core.configManager.save(
786
- { channels: { telegram: { displayVerbosity: level } } },
787
- "channels.telegram.displayVerbosity"
873
+ { channels: { telegram: { outputMode: level } } },
874
+ "channels.telegram.outputMode"
788
875
  );
789
876
  try {
790
877
  await ctx.answerCallbackQuery({
791
- text: `${VERBOSITY_LABELS[level]} Verbosity: ${level}`
878
+ text: `${OUTPUT_MODE_LABELS[level]} Output mode: ${level}`
792
879
  });
793
880
  } catch {
794
881
  }
@@ -2764,6 +2851,7 @@ function setupCommands(bot, core, chatId, assistant) {
2764
2851
  bot.command("archive", (ctx) => handleArchive(ctx, core));
2765
2852
  bot.command("text_to_speech", (ctx) => handleTTS(ctx, core));
2766
2853
  bot.command("verbosity", (ctx) => handleVerbosity(ctx, core));
2854
+ bot.command("outputmode", (ctx) => handleOutputMode(ctx, core));
2767
2855
  bot.command("resume", (ctx) => handleResume(ctx, core, chatId, assistant));
2768
2856
  }
2769
2857
  function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSession) {
@@ -2851,7 +2939,8 @@ var STATIC_COMMANDS = [
2851
2939
  { command: "tunnels", description: "List active tunnels" },
2852
2940
  { command: "archive", description: "Archive session topic (recreate with clean history)" },
2853
2941
  { command: "text_to_speech", description: "Toggle Text to Speech (/text_to_speech on, /text_to_speech off)" },
2854
- { command: "verbosity", description: "Set display verbosity (/verbosity low|medium|high)" },
2942
+ { command: "verbosity", description: "Deprecated: use /outputmode instead" },
2943
+ { command: "outputmode", description: "Control output display level (low/medium/high)" },
2855
2944
  { command: "resume", description: "Resume with conversation history from Entire checkpoints" }
2856
2945
  ];
2857
2946
 
@@ -3556,34 +3645,29 @@ function redirectToAssistant(chatId, assistantTopicId) {
3556
3645
 
3557
3646
  // src/core/adapter-primitives/primitives/tool-card-state.ts
3558
3647
  var DEBOUNCE_MS = 500;
3648
+ var DONE_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "failed", "error"]);
3559
3649
  var ToolCardState = class {
3560
- entries = [];
3650
+ specs = [];
3561
3651
  planEntries;
3562
3652
  usage;
3563
3653
  finalized = false;
3564
3654
  isFirstFlush = true;
3565
3655
  debounceTimer;
3566
- verbosity;
3567
3656
  onFlush;
3568
3657
  constructor(config) {
3569
- this.verbosity = config.verbosity;
3570
3658
  this.onFlush = config.onFlush;
3571
3659
  }
3572
- addTool(meta, kind, rawInput) {
3573
- if (this.finalized) return;
3574
- const hidden = this.verbosity !== "high" && evaluateNoise(meta.name, kind, rawInput) !== null;
3575
- const entry = {
3576
- id: meta.id,
3577
- name: meta.name,
3578
- kind,
3579
- status: meta.status ?? "running",
3580
- icon: resolveToolIcon({ status: meta.status ?? "running", kind }),
3581
- label: formatToolSummary(meta.name, rawInput, meta.displaySummary),
3582
- viewerLinks: meta.viewerLinks,
3583
- viewerFilePath: meta.viewerFilePath,
3584
- hidden
3585
- };
3586
- this.entries.push(entry);
3660
+ updateFromSpec(spec) {
3661
+ const existingIdx = this.specs.findIndex((s) => s.id === spec.id);
3662
+ if (existingIdx >= 0) {
3663
+ this.specs[existingIdx] = spec;
3664
+ } else {
3665
+ this.specs.push(spec);
3666
+ }
3667
+ if (this.finalized) {
3668
+ this.onFlush(this.snapshot());
3669
+ return;
3670
+ }
3587
3671
  if (this.isFirstFlush) {
3588
3672
  this.isFirstFlush = false;
3589
3673
  this.flush();
@@ -3591,20 +3675,10 @@ var ToolCardState = class {
3591
3675
  this.scheduleFlush();
3592
3676
  }
3593
3677
  }
3594
- updateTool(id, status, viewerLinks, viewerFilePath) {
3595
- if (this.finalized) return;
3596
- const entry = this.entries.find((e) => e.id === id);
3597
- if (!entry) return;
3598
- entry.status = status;
3599
- entry.icon = resolveToolIcon({ status, kind: entry.kind });
3600
- if (viewerLinks) entry.viewerLinks = viewerLinks;
3601
- if (viewerFilePath) entry.viewerFilePath = viewerFilePath;
3602
- this.scheduleFlush();
3603
- }
3604
3678
  updatePlan(entries) {
3605
3679
  if (this.finalized) return;
3606
3680
  this.planEntries = entries;
3607
- if (this.entries.length === 0 && this.isFirstFlush) {
3681
+ if (this.specs.length === 0 && this.isFirstFlush) {
3608
3682
  this.isFirstFlush = false;
3609
3683
  this.flush();
3610
3684
  } else {
@@ -3627,23 +3701,19 @@ var ToolCardState = class {
3627
3701
  this.clearDebounce();
3628
3702
  }
3629
3703
  hasContent() {
3630
- return this.entries.length > 0 || this.planEntries !== void 0;
3704
+ return this.specs.length > 0 || this.planEntries !== void 0;
3631
3705
  }
3632
3706
  snapshot() {
3633
- const visible = this.entries.filter((e) => !e.hidden);
3634
- const completedVisible = visible.filter(
3635
- (e) => e.status === "completed" || e.status === "done"
3636
- ).length;
3707
+ const visible = this.specs.filter((s) => !s.isHidden);
3708
+ const completedVisible = visible.filter((s) => DONE_STATUSES.has(s.status)).length;
3637
3709
  const allComplete = visible.length > 0 && completedVisible === visible.length;
3638
3710
  return {
3639
- entries: this.entries,
3711
+ specs: this.specs,
3640
3712
  planEntries: this.planEntries,
3641
3713
  usage: this.usage,
3642
- visibleCount: visible.length,
3643
3714
  totalVisible: visible.length,
3644
3715
  completedVisible,
3645
- allComplete,
3646
- verbosity: this.verbosity
3716
+ allComplete
3647
3717
  };
3648
3718
  }
3649
3719
  flush() {
@@ -3665,40 +3735,279 @@ var ToolCardState = class {
3665
3735
  }
3666
3736
  };
3667
3737
 
3738
+ // src/core/adapter-primitives/stream-accumulator.ts
3739
+ var ToolStateMap = class {
3740
+ entries = /* @__PURE__ */ new Map();
3741
+ pendingUpdates = /* @__PURE__ */ new Map();
3742
+ /**
3743
+ * Creates or updates an entry from a tool_call event.
3744
+ * If a pending update exists for this id, applies it immediately.
3745
+ */
3746
+ upsert(meta, kind, rawInput) {
3747
+ const isNoise = evaluateNoise(meta.name, kind, rawInput) !== null;
3748
+ const entry = {
3749
+ id: meta.id,
3750
+ name: meta.name,
3751
+ kind,
3752
+ rawInput,
3753
+ content: null,
3754
+ status: meta.status ?? "running",
3755
+ viewerLinks: meta.viewerLinks,
3756
+ displaySummary: meta.displaySummary,
3757
+ displayTitle: meta.displayTitle,
3758
+ displayKind: meta.displayKind,
3759
+ isNoise
3760
+ };
3761
+ this.entries.set(meta.id, entry);
3762
+ const pending = this.pendingUpdates.get(meta.id);
3763
+ if (pending) {
3764
+ this.pendingUpdates.delete(meta.id);
3765
+ this._applyUpdate(entry, pending);
3766
+ }
3767
+ return entry;
3768
+ }
3769
+ /**
3770
+ * Updates an existing entry from a tool_call_update event.
3771
+ * If the entry doesn't exist yet (out-of-order delivery), buffers the update.
3772
+ */
3773
+ merge(id, status, rawInput, content, viewerLinks, diffStats) {
3774
+ const entry = this.entries.get(id);
3775
+ if (!entry) {
3776
+ this.pendingUpdates.set(id, { status, rawInput, content, viewerLinks, diffStats });
3777
+ return void 0;
3778
+ }
3779
+ this._applyUpdate(entry, { status, rawInput, content, viewerLinks, diffStats });
3780
+ return entry;
3781
+ }
3782
+ _applyUpdate(entry, update) {
3783
+ entry.status = update.status;
3784
+ if (update.rawInput !== void 0) {
3785
+ entry.rawInput = update.rawInput;
3786
+ }
3787
+ if (update.content !== void 0) {
3788
+ entry.content = update.content ?? null;
3789
+ }
3790
+ if (update.viewerLinks !== void 0) {
3791
+ entry.viewerLinks = update.viewerLinks;
3792
+ }
3793
+ if (update.diffStats !== void 0) {
3794
+ entry.diffStats = update.diffStats;
3795
+ }
3796
+ }
3797
+ get(id) {
3798
+ return this.entries.get(id);
3799
+ }
3800
+ clear() {
3801
+ this.entries.clear();
3802
+ this.pendingUpdates.clear();
3803
+ }
3804
+ };
3805
+ var ThoughtBuffer = class {
3806
+ chunks = [];
3807
+ sealed = false;
3808
+ append(chunk) {
3809
+ if (this.sealed) return;
3810
+ this.chunks.push(chunk);
3811
+ }
3812
+ seal() {
3813
+ this.sealed = true;
3814
+ return this.chunks.join("");
3815
+ }
3816
+ getText() {
3817
+ return this.chunks.join("");
3818
+ }
3819
+ isSealed() {
3820
+ return this.sealed;
3821
+ }
3822
+ reset() {
3823
+ this.chunks = [];
3824
+ this.sealed = false;
3825
+ }
3826
+ };
3827
+
3828
+ // src/core/adapter-primitives/display-spec-builder.ts
3829
+ var EXECUTE_KINDS = /* @__PURE__ */ new Set(["execute", "bash", "command", "terminal"]);
3830
+ var INLINE_MAX_LINES = 15;
3831
+ var INLINE_MAX_CHARS = 800;
3832
+ function asRecord(value) {
3833
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3834
+ return value;
3835
+ }
3836
+ return {};
3837
+ }
3838
+ function capitalize(s) {
3839
+ return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
3840
+ }
3841
+ function buildTitle(entry, kind) {
3842
+ if (entry.displayTitle) return entry.displayTitle;
3843
+ if (entry.displaySummary) return entry.displaySummary;
3844
+ const input = asRecord(entry.rawInput);
3845
+ if (kind === "read") {
3846
+ const filePath = typeof input.file_path === "string" ? input.file_path : null;
3847
+ if (filePath) {
3848
+ const startLine = typeof input.start_line === "number" ? input.start_line : null;
3849
+ const endLine = typeof input.end_line === "number" ? input.end_line : null;
3850
+ if (startLine !== null && endLine !== null) return `${filePath} (lines ${startLine}\u2013${endLine})`;
3851
+ if (startLine !== null) return `${filePath} (from line ${startLine})`;
3852
+ const offset = typeof input.offset === "number" ? input.offset : null;
3853
+ const limit = typeof input.limit === "number" ? input.limit : null;
3854
+ if (offset !== null && limit !== null) return `${filePath} (lines ${offset}\u2013${offset + limit - 1})`;
3855
+ if (offset !== null) return `${filePath} (from line ${offset})`;
3856
+ return filePath;
3857
+ }
3858
+ return capitalize(entry.name);
3859
+ }
3860
+ if (kind === "edit" || kind === "write" || kind === "delete") {
3861
+ const filePath = typeof input.file_path === "string" ? input.file_path : typeof input.path === "string" ? input.path : null;
3862
+ if (filePath) return filePath;
3863
+ return capitalize(entry.name);
3864
+ }
3865
+ if (EXECUTE_KINDS.has(kind)) {
3866
+ const description = typeof input.description === "string" ? input.description : null;
3867
+ if (description) return description;
3868
+ const command = typeof input.command === "string" ? input.command : null;
3869
+ if (command) return command.length > 60 ? command.slice(0, 57) + "..." : command;
3870
+ return capitalize(entry.name);
3871
+ }
3872
+ if (kind === "agent") {
3873
+ const skill = typeof input.skill === "string" ? input.skill : null;
3874
+ const description = typeof input.description === "string" ? input.description : null;
3875
+ const subtype = typeof input.subagent_type === "string" ? input.subagent_type : null;
3876
+ if (skill) return skill;
3877
+ if (description) return description.length > 60 ? description.slice(0, 57) + "..." : description;
3878
+ if (subtype) return subtype;
3879
+ return capitalize(entry.name);
3880
+ }
3881
+ if (kind === "search") {
3882
+ const pattern = typeof input.pattern === "string" ? input.pattern : typeof input.query === "string" ? input.query : null;
3883
+ if (pattern) {
3884
+ let title = `${capitalize(entry.name)} "${pattern}"`;
3885
+ const glob = typeof input.glob === "string" ? input.glob : null;
3886
+ const type = typeof input.type === "string" ? input.type : null;
3887
+ if (glob) title += ` (glob: ${glob})`;
3888
+ else if (type) title += ` (type: ${type})`;
3889
+ return title;
3890
+ }
3891
+ return capitalize(entry.name);
3892
+ }
3893
+ if (entry.name.toLowerCase() === "skill" && typeof input.skill === "string" && input.skill) {
3894
+ return input.skill;
3895
+ }
3896
+ return entry.name;
3897
+ }
3898
+ function buildOutputSummary(content) {
3899
+ const lines = content.split("\n").length;
3900
+ return `${lines} line${lines === 1 ? "" : "s"} of output`;
3901
+ }
3902
+ function isTitleFromCommand(title, command) {
3903
+ return title === command || command.length > 60 && title === command.slice(0, 57) + "...";
3904
+ }
3905
+ var DisplaySpecBuilder = class {
3906
+ constructor(tunnelService) {
3907
+ this.tunnelService = tunnelService;
3908
+ }
3909
+ buildToolSpec(entry, mode, sessionContext) {
3910
+ const effectiveKind = entry.displayKind ?? entry.kind;
3911
+ const icon = KIND_ICONS[effectiveKind] ?? KIND_ICONS["other"] ?? "\u{1F6E0}\uFE0F";
3912
+ const title = buildTitle(entry, effectiveKind);
3913
+ const isHidden = entry.isNoise && mode !== "high";
3914
+ const includeMeta = mode !== "low";
3915
+ const input = asRecord(entry.rawInput);
3916
+ const rawDescription = typeof input.description === "string" ? input.description : null;
3917
+ const descLower = rawDescription?.toLowerCase();
3918
+ const description = includeMeta && rawDescription && rawDescription !== title && descLower !== effectiveKind && descLower !== entry.name.toLowerCase() ? rawDescription : null;
3919
+ const rawCommand = EXECUTE_KINDS.has(effectiveKind) && typeof input.command === "string" ? input.command : null;
3920
+ const command = includeMeta && rawCommand && !isTitleFromCommand(title, rawCommand) ? rawCommand : null;
3921
+ const inputContent = null;
3922
+ const content = entry.content;
3923
+ let outputSummary = null;
3924
+ let outputContent = null;
3925
+ let outputViewerLink = void 0;
3926
+ let outputFallbackContent = void 0;
3927
+ if (content && content.trim().length > 0 && includeMeta) {
3928
+ outputSummary = buildOutputSummary(content);
3929
+ const isLong = content.split("\n").length > INLINE_MAX_LINES || content.length > INLINE_MAX_CHARS;
3930
+ if (isLong) {
3931
+ const publicUrl = this.tunnelService?.getPublicUrl();
3932
+ const hasPublicTunnel = !!publicUrl && !publicUrl.startsWith("http://localhost") && !publicUrl.startsWith("http://127.0.0.1");
3933
+ if (this.tunnelService && sessionContext && hasPublicTunnel) {
3934
+ const label = typeof input.command === "string" ? input.command : entry.name;
3935
+ const id = this.tunnelService.getStore().storeOutput(sessionContext.id, label, content);
3936
+ if (id !== null) {
3937
+ outputViewerLink = this.tunnelService.outputUrl(id);
3938
+ }
3939
+ } else if (mode === "high") {
3940
+ outputFallbackContent = content;
3941
+ }
3942
+ } else if (mode === "high") {
3943
+ outputContent = content;
3944
+ }
3945
+ }
3946
+ const diffStats = includeMeta ? entry.diffStats ?? null : null;
3947
+ return {
3948
+ id: entry.id,
3949
+ kind: effectiveKind,
3950
+ icon,
3951
+ title,
3952
+ description,
3953
+ command,
3954
+ inputContent,
3955
+ outputSummary,
3956
+ outputContent,
3957
+ diffStats,
3958
+ viewerLinks: entry.viewerLinks,
3959
+ outputViewerLink,
3960
+ outputFallbackContent,
3961
+ status: entry.status,
3962
+ isNoise: entry.isNoise,
3963
+ isHidden
3964
+ };
3965
+ }
3966
+ buildThoughtSpec(content, mode) {
3967
+ const indicator = "Thinking...";
3968
+ return {
3969
+ indicator,
3970
+ content: mode === "high" ? content : null
3971
+ };
3972
+ }
3973
+ };
3974
+
3668
3975
  // src/plugins/telegram/activity.ts
3669
3976
  var log10 = createChildLogger({ module: "telegram:activity" });
3670
3977
  var THINKING_REFRESH_MS = 15e3;
3671
3978
  var THINKING_MAX_MS = 3 * 60 * 1e3;
3672
3979
  var ThinkingIndicator = class {
3673
- constructor(api, chatId, threadId, sendQueue) {
3980
+ constructor(api, chatId, threadId, sendQueue, sessionId = "", tracer = null) {
3674
3981
  this.api = api;
3675
3982
  this.chatId = chatId;
3676
3983
  this.threadId = threadId;
3677
3984
  this.sendQueue = sendQueue;
3985
+ this.sessionId = sessionId;
3986
+ this.tracer = tracer;
3678
3987
  }
3679
3988
  msgId;
3680
3989
  sending = false;
3681
3990
  dismissed = false;
3682
3991
  refreshTimer;
3683
3992
  showTime = 0;
3993
+ tracer;
3684
3994
  async show() {
3685
- if (this.msgId || this.sending || this.dismissed) return;
3995
+ if (this.sending || this.dismissed) return;
3996
+ if (this.msgId) return;
3686
3997
  this.sending = true;
3687
3998
  this.showTime = Date.now();
3999
+ const text = "\u{1F4AD} <i>Thinking...</i>";
3688
4000
  try {
3689
4001
  const result = await this.sendQueue.enqueue(
3690
- () => this.api.sendMessage(this.chatId, "\u{1F4AD} <i>Thinking...</i>", {
4002
+ () => this.api.sendMessage(this.chatId, text, {
3691
4003
  message_thread_id: this.threadId,
3692
4004
  parse_mode: "HTML",
3693
4005
  disable_notification: true
3694
4006
  })
3695
4007
  );
3696
4008
  if (result) {
4009
+ this.tracer?.log("telegram", { action: "thinking:show", sessionId: this.sessionId, msgId: result.message_id });
3697
4010
  if (this.dismissed) {
3698
- try {
3699
- await this.api.deleteMessage(this.chatId, result.message_id);
3700
- } catch {
3701
- }
3702
4011
  } else {
3703
4012
  this.msgId = result.message_id;
3704
4013
  this.startRefreshTimer();
@@ -3710,19 +4019,27 @@ var ThinkingIndicator = class {
3710
4019
  this.sending = false;
3711
4020
  }
3712
4021
  }
3713
- /** Dismiss indicator: stops refresh timer and deletes the Telegram message */
4022
+ /** Edit the indicator message to append a viewer link, then dismiss. */
4023
+ async finalizeWithViewerLink(url) {
4024
+ this.stopRefreshTimer();
4025
+ if (this.msgId && !this.dismissed) {
4026
+ const text = `\u{1F4AD} <i>Thinking...</i> <a href="${escapeHtml(url)}">View thinking</a>`;
4027
+ await this.sendQueue.enqueue(() => {
4028
+ if (!this.msgId) return Promise.resolve(void 0);
4029
+ return this.api.editMessageText(this.chatId, this.msgId, text, { parse_mode: "HTML" });
4030
+ }).catch(() => {
4031
+ });
4032
+ }
4033
+ this.dismissed = true;
4034
+ this.msgId = void 0;
4035
+ }
4036
+ /** Dismiss indicator: stops refresh timer. Message is left in chat to reduce API calls. */
3714
4037
  async dismiss() {
3715
4038
  if (this.dismissed) return;
3716
4039
  this.dismissed = true;
4040
+ this.tracer?.log("telegram", { action: "thinking:dismiss", sessionId: this.sessionId });
3717
4041
  this.stopRefreshTimer();
3718
- const msgId = this.msgId;
3719
4042
  this.msgId = void 0;
3720
- if (msgId) {
3721
- try {
3722
- await this.api.deleteMessage(this.chatId, msgId);
3723
- } catch {
3724
- }
3725
- }
3726
4043
  }
3727
4044
  /** Reset for a new prompt cycle */
3728
4045
  reset() {
@@ -3736,12 +4053,13 @@ var ThinkingIndicator = class {
3736
4053
  return;
3737
4054
  }
3738
4055
  const elapsed = Math.round((Date.now() - this.showTime) / 1e3);
4056
+ const refreshText = `\u{1F4AD} <i>Still thinking... (${elapsed}s)</i>`;
3739
4057
  this.sendQueue.enqueue(() => {
3740
4058
  if (this.dismissed || !this.msgId) return Promise.resolve(void 0);
3741
4059
  return this.api.editMessageText(
3742
4060
  this.chatId,
3743
4061
  this.msgId,
3744
- `\u{1F4AD} <i>Still thinking... (${elapsed}s)</i>`,
4062
+ refreshText,
3745
4063
  { parse_mode: "HTML" }
3746
4064
  );
3747
4065
  }).then(() => {
@@ -3757,13 +4075,14 @@ var ThinkingIndicator = class {
3757
4075
  }
3758
4076
  };
3759
4077
  var ToolCard = class {
3760
- constructor(api, chatId, threadId, sendQueue, verbosity) {
4078
+ constructor(api, chatId, threadId, sendQueue, sessionId = "", tracer = null) {
3761
4079
  this.api = api;
3762
4080
  this.chatId = chatId;
3763
4081
  this.threadId = threadId;
3764
4082
  this.sendQueue = sendQueue;
4083
+ this.tracer = tracer;
4084
+ this.sessionId = sessionId;
3765
4085
  this.state = new ToolCardState({
3766
- verbosity,
3767
4086
  onFlush: (snapshot) => {
3768
4087
  this.flushPromise = this.flushPromise.then(() => this._sendOrEdit(snapshot)).catch(() => {
3769
4088
  });
@@ -3774,12 +4093,11 @@ var ToolCard = class {
3774
4093
  msgId;
3775
4094
  lastSentText;
3776
4095
  flushPromise = Promise.resolve();
3777
- overflowCount = 0;
3778
- addTool(meta, kind, rawInput) {
3779
- this.state.addTool(meta, kind, rawInput);
3780
- }
3781
- updateTool(id, status, viewerLinks, viewerFilePath) {
3782
- this.state.updateTool(id, status, viewerLinks, viewerFilePath);
4096
+ overflowMsgIds = [];
4097
+ tracer;
4098
+ sessionId;
4099
+ updateFromSpec(spec) {
4100
+ this.state.updateFromSpec(spec);
3783
4101
  }
3784
4102
  updatePlan(entries) {
3785
4103
  this.state.updatePlan(entries);
@@ -3801,19 +4119,29 @@ var ToolCard = class {
3801
4119
  return this.msgId;
3802
4120
  }
3803
4121
  async _sendOrEdit(snapshot) {
3804
- const fullText = renderToolCard(snapshot);
4122
+ let snapshotToRender = snapshot;
4123
+ let fullText = renderToolCard(snapshotToRender);
4124
+ if (fullText.length > 4096) {
4125
+ snapshotToRender = {
4126
+ ...snapshot,
4127
+ specs: snapshot.specs.map(
4128
+ (s) => s.outputContent ? { ...s, outputContent: null } : s
4129
+ )
4130
+ };
4131
+ fullText = renderToolCard(snapshotToRender);
4132
+ }
3805
4133
  if (!fullText) return;
3806
4134
  if (this.msgId && fullText === this.lastSentText) return;
3807
4135
  this.lastSentText = fullText;
3808
4136
  const chunks = splitToolCardText(fullText);
4137
+ this.tracer?.log("telegram", { action: "toolCard:render", sessionId: this.sessionId, chunks: chunks.length, total: snapshot.totalVisible, completed: snapshot.completedVisible, allComplete: snapshot.allComplete, msgId: this.msgId, entries: snapshot.specs.map((s) => ({ id: s.id, kind: s.kind, icon: s.icon, title: s.title })), html: fullText });
3809
4138
  try {
3810
4139
  const firstChunk = chunks[0];
3811
4140
  if (this.msgId) {
3812
4141
  await this.sendQueue.enqueue(
3813
- () => this.api.editMessageText(this.chatId, this.msgId, firstChunk, {
3814
- parse_mode: "HTML"
3815
- })
4142
+ () => this.api.editMessageText(this.chatId, this.msgId, firstChunk, { parse_mode: "HTML" })
3816
4143
  );
4144
+ this.tracer?.log("telegram", { action: "telegram:edit", sessionId: this.sessionId, msgId: this.msgId, html: firstChunk });
3817
4145
  } else {
3818
4146
  const result = await this.sendQueue.enqueue(
3819
4147
  () => this.api.sendMessage(this.chatId, firstChunk, {
@@ -3823,17 +4151,25 @@ var ToolCard = class {
3823
4151
  })
3824
4152
  );
3825
4153
  if (result) this.msgId = result.message_id;
4154
+ this.tracer?.log("telegram", { action: "telegram:send", sessionId: this.sessionId, msgId: result?.message_id, html: firstChunk });
3826
4155
  }
3827
4156
  for (let i = 1; i < chunks.length; i++) {
3828
- if (i > this.overflowCount) {
4157
+ const overflowIdx = i - 1;
4158
+ if (overflowIdx < this.overflowMsgIds.length) {
3829
4159
  await this.sendQueue.enqueue(
4160
+ () => this.api.editMessageText(this.chatId, this.overflowMsgIds[overflowIdx], chunks[i], { parse_mode: "HTML" })
4161
+ );
4162
+ this.tracer?.log("telegram", { action: "telegram:edit:overflow", sessionId: this.sessionId, msgId: this.overflowMsgIds[overflowIdx] });
4163
+ } else {
4164
+ const result = await this.sendQueue.enqueue(
3830
4165
  () => this.api.sendMessage(this.chatId, chunks[i], {
3831
4166
  message_thread_id: this.threadId,
3832
4167
  parse_mode: "HTML",
3833
4168
  disable_notification: true
3834
4169
  })
3835
4170
  );
3836
- this.overflowCount = i;
4171
+ if (result) this.overflowMsgIds.push(result.message_id);
4172
+ this.tracer?.log("telegram", { action: "telegram:send:overflow", sessionId: this.sessionId, msgId: result?.message_id });
3837
4173
  }
3838
4174
  }
3839
4175
  } catch (err) {
@@ -3842,64 +4178,112 @@ var ToolCard = class {
3842
4178
  }
3843
4179
  };
3844
4180
  var ActivityTracker = class {
3845
- constructor(api, chatId, threadId, sendQueue, verbosity = "medium") {
4181
+ constructor(api, chatId, threadId, sendQueue, outputMode = "medium", sessionId = "", tracer = null, tunnelService, sessionContext) {
3846
4182
  this.api = api;
3847
4183
  this.chatId = chatId;
3848
4184
  this.threadId = threadId;
3849
4185
  this.sendQueue = sendQueue;
3850
- this.verbosity = verbosity;
3851
- this.thinking = new ThinkingIndicator(api, chatId, threadId, sendQueue);
3852
- this.toolCard = new ToolCard(api, chatId, threadId, sendQueue, verbosity);
4186
+ this._outputMode = outputMode;
4187
+ this.tracer = tracer;
4188
+ this.sessionId = sessionId;
4189
+ this.sessionContext = sessionContext;
4190
+ this.tunnelService = tunnelService;
4191
+ this.specBuilder = new DisplaySpecBuilder(tunnelService);
4192
+ this.toolStateMap = new ToolStateMap();
4193
+ this.thoughtBuffer = new ThoughtBuffer();
4194
+ this.thinking = new ThinkingIndicator(api, chatId, threadId, sendQueue, sessionId, tracer);
4195
+ this.toolCard = new ToolCard(api, chatId, threadId, sendQueue, sessionId, tracer);
3853
4196
  }
3854
4197
  isFirstEvent = true;
3855
4198
  thinking;
3856
4199
  toolCard;
3857
- verbosity;
4200
+ previousToolCard;
4201
+ toolStateMap;
4202
+ previousToolStateMap;
4203
+ specBuilder;
4204
+ thoughtBuffer;
4205
+ _outputMode;
4206
+ tracer;
4207
+ sessionId;
4208
+ sessionContext;
4209
+ tunnelService;
4210
+ setOutputMode(mode) {
4211
+ this._outputMode = mode;
4212
+ }
3858
4213
  async onNewPrompt() {
4214
+ this.tracer?.log("telegram", { action: "tracker:newPrompt", sessionId: this.sessionId });
3859
4215
  this.isFirstEvent = true;
4216
+ this.thoughtBuffer.reset();
3860
4217
  await this.thinking.dismiss();
3861
4218
  this.thinking.reset();
3862
4219
  await this.toolCard.finalize();
3863
- this.toolCard = new ToolCard(
3864
- this.api,
3865
- this.chatId,
3866
- this.threadId,
3867
- this.sendQueue,
3868
- this.verbosity
3869
- );
4220
+ this.previousToolCard = void 0;
4221
+ this.previousToolStateMap = void 0;
4222
+ this.toolStateMap.clear();
4223
+ this.toolCard = new ToolCard(this.api, this.chatId, this.threadId, this.sendQueue, this.sessionId, this.tracer);
3870
4224
  }
3871
- async onThought() {
4225
+ async onThought(text) {
4226
+ this.tracer?.log("telegram", { action: "tracker:thought", sessionId: this.sessionId });
3872
4227
  this.isFirstEvent = false;
4228
+ if (!this.thoughtBuffer.isSealed()) this.thoughtBuffer.append(text);
3873
4229
  await this.sealToolCardIfNeeded();
3874
4230
  await this.thinking.show();
3875
4231
  }
3876
4232
  async onTextStart() {
4233
+ this.tracer?.log("telegram", { action: "tracker:textStart", sessionId: this.sessionId });
3877
4234
  this.isFirstEvent = false;
3878
- await this.thinking.dismiss();
4235
+ this.thoughtBuffer.seal();
4236
+ if (this._outputMode === "high" && this.tunnelService && this.sessionContext) {
4237
+ const thoughtText = this.thoughtBuffer.getText();
4238
+ if (thoughtText.trim().length > 0) {
4239
+ const id = this.tunnelService.getStore().storeOutput(
4240
+ this.sessionContext.id,
4241
+ "thinking",
4242
+ thoughtText
4243
+ );
4244
+ if (id !== null) {
4245
+ await this.thinking.finalizeWithViewerLink(this.tunnelService.outputUrl(id));
4246
+ } else {
4247
+ await this.thinking.dismiss();
4248
+ }
4249
+ } else {
4250
+ await this.thinking.dismiss();
4251
+ }
4252
+ } else {
4253
+ await this.thinking.dismiss();
4254
+ }
3879
4255
  await this.sealToolCardIfNeeded();
3880
4256
  }
3881
4257
  async onToolCall(meta, kind, rawInput) {
4258
+ this.tracer?.log("telegram", { action: "tracker:toolCall", sessionId: this.sessionId, meta, kind, rawInput });
3882
4259
  this.isFirstEvent = false;
3883
4260
  await this.thinking.dismiss();
3884
4261
  this.thinking.reset();
3885
- this.toolCard.addTool(meta, kind, rawInput);
3886
- }
3887
- /** Finalize current tool card and create a fresh one (when interrupted by text/thought) */
3888
- async sealToolCardIfNeeded() {
3889
- if (!this.toolCard.hasContent()) return;
3890
- await this.toolCard.finalize();
3891
- this.toolCard = new ToolCard(
3892
- this.api,
3893
- this.chatId,
3894
- this.threadId,
3895
- this.sendQueue,
3896
- this.verbosity
3897
- );
3898
- }
3899
- async onToolUpdate(id, status, viewerLinks, viewerFilePath) {
3900
- this.toolCard.updateTool(id, status, viewerLinks, viewerFilePath);
4262
+ const entry = this.toolStateMap.upsert(meta, kind, rawInput);
4263
+ const spec = this.specBuilder.buildToolSpec(entry, this._outputMode, this.sessionContext);
4264
+ this.toolCard.updateFromSpec(spec);
4265
+ }
4266
+ async onToolUpdate(id, status, viewerLinks, viewerFilePath, content, rawInput, diffStats) {
4267
+ this.tracer?.log("telegram", { action: "tracker:toolUpdate", sessionId: this.sessionId, toolId: id, status, viewerLinks, viewerFilePath, hasPrevCard: !!this.previousToolCard });
4268
+ if (this.previousToolStateMap?.get(id)) {
4269
+ this.previousToolStateMap.merge(id, status, rawInput, content, viewerLinks, diffStats);
4270
+ const prevEntry = this.previousToolStateMap.get(id);
4271
+ if (prevEntry) {
4272
+ const prevSpec = this.specBuilder.buildToolSpec(prevEntry, this._outputMode, this.sessionContext);
4273
+ this.previousToolCard?.updateFromSpec(prevSpec);
4274
+ }
4275
+ }
4276
+ const existed = !!this.toolStateMap.get(id);
4277
+ const entry = this.toolStateMap.merge(id, status, rawInput, content, viewerLinks, diffStats);
4278
+ if (!existed || !entry) return;
4279
+ if (viewerLinks || entry.viewerLinks) {
4280
+ log10.debug({ toolId: id, status, hasIncomingLinks: !!viewerLinks, hasEntryLinks: !!entry.viewerLinks, entryLinks: entry.viewerLinks }, "toolUpdate: viewer links trace");
4281
+ }
4282
+ const spec = this.specBuilder.buildToolSpec(entry, this._outputMode, this.sessionContext);
4283
+ this.toolCard.updateFromSpec(spec);
3901
4284
  }
3902
4285
  async onPlan(entries) {
4286
+ this.tracer?.log("telegram", { action: "tracker:plan", sessionId: this.sessionId, entries });
3903
4287
  this.isFirstEvent = false;
3904
4288
  await this.thinking.dismiss();
3905
4289
  this.toolCard.updatePlan(entries);
@@ -3919,6 +4303,15 @@ var ActivityTracker = class {
3919
4303
  void this.thinking.dismiss();
3920
4304
  this.toolCard.destroy();
3921
4305
  }
4306
+ async sealToolCardIfNeeded() {
4307
+ if (!this.toolCard.hasContent()) return;
4308
+ this.tracer?.log("telegram", { action: "tracker:seal", sessionId: this.sessionId });
4309
+ await this.toolCard.finalize();
4310
+ this.previousToolCard = this.toolCard;
4311
+ this.previousToolStateMap = this.toolStateMap;
4312
+ this.toolStateMap = new ToolStateMap();
4313
+ this.toolCard = new ToolCard(this.api, this.chatId, this.threadId, this.sendQueue, this.sessionId, this.tracer);
4314
+ }
3922
4315
  };
3923
4316
 
3924
4317
  // src/core/adapter-primitives/primitives/send-queue.ts
@@ -4179,12 +4572,13 @@ function setupActionCallbacks(bot, core, chatId, getAssistantSessionId) {
4179
4572
  // src/plugins/telegram/streaming.ts
4180
4573
  var FLUSH_INTERVAL = 5e3;
4181
4574
  var MessageDraft = class {
4182
- constructor(bot, chatId, threadId, sendQueue, sessionId) {
4575
+ constructor(bot, chatId, threadId, sendQueue, sessionId, tracer = null) {
4183
4576
  this.bot = bot;
4184
4577
  this.chatId = chatId;
4185
4578
  this.threadId = threadId;
4186
4579
  this.sendQueue = sendQueue;
4187
4580
  this.sessionId = sessionId;
4581
+ this.tracer = tracer;
4188
4582
  }
4189
4583
  buffer = "";
4190
4584
  messageId;
@@ -4193,6 +4587,7 @@ var MessageDraft = class {
4193
4587
  flushPromise = Promise.resolve();
4194
4588
  lastSentBuffer = "";
4195
4589
  displayTruncated = false;
4590
+ tracer;
4196
4591
  append(text) {
4197
4592
  if (!text) return;
4198
4593
  this.buffer += text;
@@ -4237,6 +4632,7 @@ var MessageDraft = class {
4237
4632
  );
4238
4633
  if (result) {
4239
4634
  this.messageId = result.message_id;
4635
+ this.tracer?.log("telegram", { action: "draft:send", sessionId: this.sessionId, msgId: result.message_id, textLen: snapshot.length, truncated, text: snapshot });
4240
4636
  if (!truncated) {
4241
4637
  this.lastSentBuffer = snapshot;
4242
4638
  this.displayTruncated = false;
@@ -4257,6 +4653,7 @@ var MessageDraft = class {
4257
4653
  { type: "text", key: this.sessionId }
4258
4654
  );
4259
4655
  if (result !== void 0) {
4656
+ this.tracer?.log("telegram", { action: "draft:edit", sessionId: this.sessionId, msgId: this.messageId, textLen: snapshot.length, truncated, text: snapshot });
4260
4657
  if (!truncated) {
4261
4658
  this.lastSentBuffer = snapshot;
4262
4659
  this.displayTruncated = false;
@@ -4269,6 +4666,7 @@ var MessageDraft = class {
4269
4666
  }
4270
4667
  }
4271
4668
  async finalize() {
4669
+ this.tracer?.log("telegram", { action: "draft:finalize", sessionId: this.sessionId, bufferLen: this.buffer.length, msgId: this.messageId });
4272
4670
  if (this.flushTimer) {
4273
4671
  clearTimeout(this.flushTimer);
4274
4672
  this.flushTimer = void 0;
@@ -4288,6 +4686,7 @@ var MessageDraft = class {
4288
4686
  }),
4289
4687
  { type: "other" }
4290
4688
  );
4689
+ this.tracer?.log("telegram", { action: "draft:finalize:edit", sessionId: this.sessionId, msgId: this.messageId });
4291
4690
  } else {
4292
4691
  const msg = await this.sendQueue.enqueue(
4293
4692
  () => this.bot.api.sendMessage(this.chatId, fullHtml, {
@@ -4298,6 +4697,7 @@ var MessageDraft = class {
4298
4697
  { type: "other" }
4299
4698
  );
4300
4699
  if (msg) this.messageId = msg.message_id;
4700
+ this.tracer?.log("telegram", { action: "draft:finalize:send", sessionId: this.sessionId, msgId: msg?.message_id });
4301
4701
  }
4302
4702
  return this.messageId;
4303
4703
  } catch {
@@ -4333,6 +4733,7 @@ var MessageDraft = class {
4333
4733
  chunkPromises.push(promise);
4334
4734
  }
4335
4735
  await Promise.all(chunkPromises);
4736
+ this.tracer?.log("telegram", { action: "draft:finalize:split", sessionId: this.sessionId, chunks: mdChunks.length });
4336
4737
  return this.messageId;
4337
4738
  }
4338
4739
  getMessageId() {
@@ -4368,7 +4769,7 @@ var DraftManager = class {
4368
4769
  drafts = /* @__PURE__ */ new Map();
4369
4770
  textBuffers = /* @__PURE__ */ new Map();
4370
4771
  finalizedDrafts = /* @__PURE__ */ new Map();
4371
- getOrCreate(sessionId, threadId) {
4772
+ getOrCreate(sessionId, threadId, tracer = null) {
4372
4773
  let draft = this.drafts.get(sessionId);
4373
4774
  if (!draft) {
4374
4775
  draft = new MessageDraft(
@@ -4376,7 +4777,8 @@ var DraftManager = class {
4376
4777
  this.chatId,
4377
4778
  threadId,
4378
4779
  this.sendQueue,
4379
- sessionId
4780
+ sessionId,
4781
+ tracer
4380
4782
  );
4381
4783
  this.drafts.set(sessionId, draft);
4382
4784
  }
@@ -4838,6 +5240,28 @@ var TelegramRenderer = class extends BaseRenderer {
4838
5240
  }
4839
5241
  };
4840
5242
 
5243
+ // src/core/adapter-primitives/output-mode-resolver.ts
5244
+ var VALID_MODES = /* @__PURE__ */ new Set(["low", "medium", "high"]);
5245
+ function toOutputMode(v) {
5246
+ return typeof v === "string" && VALID_MODES.has(v) ? v : void 0;
5247
+ }
5248
+ var OutputModeResolver = class {
5249
+ resolve(configManager, adapterName, sessionId, sessionManager) {
5250
+ const config = configManager.get();
5251
+ let mode = toOutputMode(config.outputMode) ?? "medium";
5252
+ const channels = config.channels;
5253
+ const channelCfg = channels?.[adapterName];
5254
+ const adapterMode = toOutputMode(channelCfg?.outputMode);
5255
+ if (adapterMode) mode = adapterMode;
5256
+ if (sessionId && sessionManager) {
5257
+ const session = sessionManager.getSession(sessionId);
5258
+ const sessionMode = session?.record?.outputMode;
5259
+ if (sessionMode) mode = sessionMode;
5260
+ }
5261
+ return mode;
5262
+ }
5263
+ };
5264
+
4841
5265
  // src/plugins/telegram/adapter.ts
4842
5266
  var log12 = createChildLogger({ module: "telegram" });
4843
5267
  function patchedFetch(input, init) {
@@ -4867,6 +5291,7 @@ var TelegramAdapter = class extends MessagingAdapter {
4867
5291
  core;
4868
5292
  bot;
4869
5293
  telegramConfig;
5294
+ saveTopicIds;
4870
5295
  permissionHandler;
4871
5296
  assistantSession = null;
4872
5297
  assistantInitializing = false;
@@ -4874,6 +5299,7 @@ var TelegramAdapter = class extends MessagingAdapter {
4874
5299
  assistantTopicId;
4875
5300
  sendQueue = new SendQueue({ minInterval: 3e3 });
4876
5301
  _sessionThreadIds = /* @__PURE__ */ new Map();
5302
+ outputModeResolver = new OutputModeResolver();
4877
5303
  // Extracted managers
4878
5304
  draftManager;
4879
5305
  skillManager;
@@ -4888,21 +5314,33 @@ var TelegramAdapter = class extends MessagingAdapter {
4888
5314
  }
4889
5315
  return threadId;
4890
5316
  }
4891
- getOrCreateTracker(sessionId, threadId, verbosity = "medium") {
5317
+ getOrCreateTracker(sessionId, threadId, outputMode = "medium") {
4892
5318
  let tracker = this.sessionTrackers.get(sessionId);
4893
5319
  if (!tracker) {
5320
+ const tunnelService = this.core.lifecycleManager?.serviceRegistry?.get("tunnel");
5321
+ const session = this.core.sessionManager.getSession(sessionId);
5322
+ const sessionContext = session ? {
5323
+ id: sessionId,
5324
+ workingDirectory: session.workingDirectory
5325
+ } : void 0;
4894
5326
  tracker = new ActivityTracker(
4895
5327
  this.bot.api,
4896
5328
  this.telegramConfig.chatId,
4897
5329
  threadId,
4898
5330
  this.sendQueue,
4899
- verbosity
5331
+ outputMode,
5332
+ sessionId,
5333
+ this.getTracer(sessionId),
5334
+ tunnelService,
5335
+ sessionContext
4900
5336
  );
4901
5337
  this.sessionTrackers.set(sessionId, tracker);
5338
+ } else {
5339
+ tracker.setOutputMode(outputMode);
4902
5340
  }
4903
5341
  return tracker;
4904
5342
  }
4905
- constructor(core, config) {
5343
+ constructor(core, config, saveTopicIds) {
4906
5344
  super({ configManager: core.configManager }, {
4907
5345
  ...config,
4908
5346
  maxMessageLength: 4096,
@@ -4910,6 +5348,7 @@ var TelegramAdapter = class extends MessagingAdapter {
4910
5348
  });
4911
5349
  this.core = core;
4912
5350
  this.telegramConfig = config;
5351
+ this.saveTopicIds = saveTopicIds;
4913
5352
  }
4914
5353
  async start() {
4915
5354
  this.bot = new Bot(this.telegramConfig.botToken, {
@@ -4981,9 +5420,13 @@ var TelegramAdapter = class extends MessagingAdapter {
4981
5420
  this.telegramConfig.chatId,
4982
5421
  this.telegramConfig,
4983
5422
  async (updates) => {
4984
- await this.core.configManager.save({
4985
- channels: { telegram: updates }
4986
- });
5423
+ if (this.saveTopicIds) {
5424
+ await this.saveTopicIds(updates);
5425
+ } else {
5426
+ await this.core.configManager.save({
5427
+ channels: { telegram: updates }
5428
+ });
5429
+ }
4987
5430
  }
4988
5431
  );
4989
5432
  this.notificationTopicId = topics.notificationTopicId;
@@ -5378,8 +5821,10 @@ ${lines.join("\n")}`;
5378
5821
  "telegram",
5379
5822
  String(threadId)
5380
5823
  )?.id;
5381
- if (sessionId)
5824
+ if (sessionId) {
5825
+ this.getTracer(sessionId)?.log("telegram", { action: "incoming:message", sessionId, userId: String(ctx.from?.id), text: ctx.message?.text });
5382
5826
  await this.draftManager.finalize(sessionId, this.assistantSession?.id);
5827
+ }
5383
5828
  if (sessionId) {
5384
5829
  const tracker = this.sessionTrackers.get(sessionId);
5385
5830
  if (tracker) await tracker.onNewPrompt();
@@ -5462,6 +5907,18 @@ ${lines.join("\n")}`;
5462
5907
  });
5463
5908
  }
5464
5909
  // --- MessagingAdapter overrides ---
5910
+ /**
5911
+ * Per-session serial dispatch queues.
5912
+ * SessionBridge fires sendMessage() as fire-and-forget, so multiple events
5913
+ * (tool_call, tool_update, text) can arrive concurrently. Without serialization,
5914
+ * fast handlers (tool_update) overtake slow ones (tool_call with draftManager.finalize),
5915
+ * causing out-of-order processing where a tool's completion update is processed before
5916
+ * its creation event. This queue ensures events are processed in the order they arrive.
5917
+ */
5918
+ _dispatchQueues = /* @__PURE__ */ new Map();
5919
+ getTracer(sessionId) {
5920
+ return this.core.sessionManager.getSession(sessionId)?.agentInstance?.debugTracer ?? null;
5921
+ }
5465
5922
  async sendMessage(sessionId, content) {
5466
5923
  if (this.assistantInitializing && sessionId === this.assistantSession?.id)
5467
5924
  return;
@@ -5476,33 +5933,61 @@ ${lines.join("\n")}`;
5476
5933
  );
5477
5934
  return;
5478
5935
  }
5479
- this._sessionThreadIds.set(sessionId, threadId);
5480
- try {
5481
- await super.sendMessage(sessionId, content);
5482
- } finally {
5483
- this._sessionThreadIds.delete(sessionId);
5484
- }
5936
+ const prev = this._dispatchQueues.get(sessionId) ?? Promise.resolve();
5937
+ const next = prev.then(async () => {
5938
+ this.getTracer(sessionId)?.log("telegram", { action: "dispatch:enter", sessionId, message: content });
5939
+ this._sessionThreadIds.set(sessionId, threadId);
5940
+ try {
5941
+ await super.sendMessage(sessionId, content);
5942
+ } finally {
5943
+ this._sessionThreadIds.delete(sessionId);
5944
+ }
5945
+ }).catch((err) => {
5946
+ log12.warn({ err, sessionId }, "Dispatch queue error");
5947
+ });
5948
+ this._dispatchQueues.set(sessionId, next);
5949
+ await next;
5485
5950
  }
5486
- async handleThought(sessionId, _content, _verbosity) {
5951
+ async handleThought(sessionId, content, _verbosity) {
5952
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:thought", sessionId, text: content.text });
5487
5953
  const threadId = this.getThreadId(sessionId);
5488
- const tracker = this.getOrCreateTracker(sessionId, threadId);
5489
- await tracker.onThought();
5954
+ const mode = this.outputModeResolver.resolve(
5955
+ this.context.configManager,
5956
+ this.name,
5957
+ sessionId,
5958
+ this.core.sessionManager
5959
+ );
5960
+ const tracker = this.getOrCreateTracker(sessionId, threadId, mode);
5961
+ await tracker.onThought(content.text);
5490
5962
  }
5491
5963
  async handleText(sessionId, content) {
5964
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:text", sessionId, text: content.text });
5492
5965
  const threadId = this.getThreadId(sessionId);
5493
5966
  if (!this.draftManager.hasDraft(sessionId)) {
5494
- const tracker = this.getOrCreateTracker(sessionId, threadId);
5495
- tracker.onTextStart().catch(() => {
5496
- });
5967
+ const mode = this.outputModeResolver.resolve(
5968
+ this.context.configManager,
5969
+ this.name,
5970
+ sessionId,
5971
+ this.core.sessionManager
5972
+ );
5973
+ const tracker = this.getOrCreateTracker(sessionId, threadId, mode);
5974
+ await tracker.onTextStart();
5497
5975
  }
5498
- const draft = this.draftManager.getOrCreate(sessionId, threadId);
5976
+ const draft = this.draftManager.getOrCreate(sessionId, threadId, this.getTracer(sessionId));
5499
5977
  draft.append(content.text);
5500
5978
  this.draftManager.appendText(sessionId, content.text);
5501
5979
  }
5502
- async handleToolCall(sessionId, content, verbosity) {
5980
+ async handleToolCall(sessionId, content, _verbosity) {
5503
5981
  const threadId = this.getThreadId(sessionId);
5504
5982
  const meta = content.metadata ?? {};
5505
- const tracker = this.getOrCreateTracker(sessionId, threadId, verbosity);
5983
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:toolCall", sessionId, toolId: meta.id, toolName: meta.name, kind: meta.kind, status: meta.status, displaySummary: meta.displaySummary, rawInput: meta.rawInput });
5984
+ const mode = this.outputModeResolver.resolve(
5985
+ this.context.configManager,
5986
+ this.name,
5987
+ sessionId,
5988
+ this.core.sessionManager
5989
+ );
5990
+ const tracker = this.getOrCreateTracker(sessionId, threadId, mode);
5506
5991
  await this.draftManager.finalize(sessionId, this.assistantSession?.id);
5507
5992
  await tracker.onToolCall(
5508
5993
  {
@@ -5522,22 +6007,39 @@ ${lines.join("\n")}`;
5522
6007
  meta.rawInput
5523
6008
  );
5524
6009
  }
5525
- async handleToolUpdate(sessionId, content, verbosity) {
6010
+ async handleToolUpdate(sessionId, content, _verbosity) {
5526
6011
  const threadId = this.getThreadId(sessionId);
5527
6012
  const meta = content.metadata ?? {};
5528
- const tracker = this.getOrCreateTracker(sessionId, threadId, verbosity);
6013
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:toolUpdate", sessionId, toolId: meta.id, name: meta.name, kind: meta.kind, status: meta.status, viewerLinks: meta.viewerLinks, viewerFilePath: meta.viewerFilePath });
6014
+ const mode = this.outputModeResolver.resolve(
6015
+ this.context.configManager,
6016
+ this.name,
6017
+ sessionId,
6018
+ this.core.sessionManager
6019
+ );
6020
+ const tracker = this.getOrCreateTracker(sessionId, threadId, mode);
5529
6021
  await tracker.onToolUpdate(
5530
6022
  meta.id ?? "",
5531
6023
  meta.status ?? "completed",
5532
6024
  meta.viewerLinks,
5533
- meta.viewerFilePath
6025
+ meta.viewerFilePath,
6026
+ typeof meta.content === "string" ? meta.content : null,
6027
+ meta.rawInput ?? void 0,
6028
+ meta.diffStats
5534
6029
  );
5535
6030
  }
5536
- async handlePlan(sessionId, content, verbosity) {
6031
+ async handlePlan(sessionId, content, _verbosity) {
5537
6032
  const threadId = this.getThreadId(sessionId);
5538
6033
  const meta = content.metadata ?? {};
5539
6034
  const entries = meta.entries ?? [];
5540
- const tracker = this.getOrCreateTracker(sessionId, threadId, verbosity);
6035
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:plan", sessionId, entryCount: entries.length });
6036
+ const mode = this.outputModeResolver.resolve(
6037
+ this.context.configManager,
6038
+ this.name,
6039
+ sessionId,
6040
+ this.core.sessionManager
6041
+ );
6042
+ const tracker = this.getOrCreateTracker(sessionId, threadId, mode);
5541
6043
  await tracker.onPlan(
5542
6044
  entries.map((e) => ({
5543
6045
  content: e.content,
@@ -5549,6 +6051,7 @@ ${lines.join("\n")}`;
5549
6051
  async handleUsage(sessionId, content, verbosity) {
5550
6052
  const threadId = this.getThreadId(sessionId);
5551
6053
  const meta = content.metadata;
6054
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:usage", sessionId, tokensUsed: meta?.tokensUsed, contextSize: meta?.contextSize, cost: meta?.cost });
5552
6055
  await this.draftManager.finalize(sessionId, this.assistantSession?.id);
5553
6056
  const usageText = formatUsage(meta ?? {}, verbosity);
5554
6057
  let usageMsgId;
@@ -5585,6 +6088,7 @@ Task completed.
5585
6088
  }
5586
6089
  }
5587
6090
  async handleAttachment(sessionId, content) {
6091
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:attachment", sessionId, type: content.attachment?.type, fileName: content.attachment?.fileName });
5588
6092
  const threadId = this.getThreadId(sessionId);
5589
6093
  if (!content.attachment) return;
5590
6094
  const { attachment } = content;
@@ -5640,6 +6144,7 @@ Task completed.
5640
6144
  }
5641
6145
  }
5642
6146
  async handleSessionEnd(sessionId, _content) {
6147
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:sessionEnd", sessionId });
5643
6148
  const threadId = this.getThreadId(sessionId);
5644
6149
  await this.draftManager.finalize(sessionId, this.assistantSession?.id);
5645
6150
  this.draftManager.cleanup(sessionId);
@@ -5659,6 +6164,7 @@ Task completed.
5659
6164
  }
5660
6165
  }
5661
6166
  async handleError(sessionId, content) {
6167
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:error", sessionId, text: content.text });
5662
6168
  const threadId = this.getThreadId(sessionId);
5663
6169
  await this.draftManager.finalize(sessionId, this.assistantSession?.id);
5664
6170
  const tracker = this.sessionTrackers.get(sessionId);
@@ -5679,6 +6185,7 @@ Task completed.
5679
6185
  );
5680
6186
  }
5681
6187
  async handleSystem(sessionId, content) {
6188
+ this.getTracer(sessionId)?.log("telegram", { action: "handle:system", sessionId, text: content.text });
5682
6189
  const threadId = this.getThreadId(sessionId);
5683
6190
  await this.sendQueue.enqueue(
5684
6191
  () => this.bot.api.sendMessage(
@@ -5693,6 +6200,7 @@ Task completed.
5693
6200
  );
5694
6201
  }
5695
6202
  async sendPermissionRequest(sessionId, request) {
6203
+ this.getTracer(sessionId)?.log("telegram", { action: "permission:send", sessionId, requestId: request.id, description: request.description });
5696
6204
  log12.info({ sessionId, requestId: request.id }, "Permission request sent");
5697
6205
  const session = this.core.sessionManager.getSession(sessionId);
5698
6206
  if (!session) return;
@@ -5701,6 +6209,7 @@ Task completed.
5701
6209
  );
5702
6210
  }
5703
6211
  async sendNotification(notification) {
6212
+ this.getTracer(notification.sessionId)?.log("telegram", { action: "notification:send", sessionId: notification.sessionId, type: notification.type });
5704
6213
  if (notification.sessionId === this.assistantSession?.id) return;
5705
6214
  log12.info(
5706
6215
  { sessionId: notification.sessionId, type: notification.type },
@@ -5740,12 +6249,14 @@ Task completed.
5740
6249
  );
5741
6250
  }
5742
6251
  async createSessionThread(sessionId, name) {
6252
+ this.getTracer(sessionId)?.log("telegram", { action: "thread:create", sessionId, name });
5743
6253
  log12.info({ sessionId, name }, "Session topic created");
5744
6254
  return String(
5745
6255
  await createSessionTopic(this.bot, this.telegramConfig.chatId, name)
5746
6256
  );
5747
6257
  }
5748
6258
  async renameSessionThread(sessionId, newName) {
6259
+ this.getTracer(sessionId)?.log("telegram", { action: "thread:rename", sessionId, newName });
5749
6260
  const session = this.core.sessionManager.getSession(sessionId);
5750
6261
  if (!session) return;
5751
6262
  await renameSessionTopic(
@@ -5855,6 +6366,7 @@ Task completed.
5855
6366
  await this.draftManager.stripPattern(sessionId, /\[TTS\][\s\S]*?\[\/TTS\]/g);
5856
6367
  }
5857
6368
  async archiveSessionTopic(sessionId) {
6369
+ this.getTracer(sessionId)?.log("telegram", { action: "thread:archive", sessionId });
5858
6370
  const core = this.core;
5859
6371
  const session = core.sessionManager.getSession(sessionId);
5860
6372
  if (!session) throw new Error("Session not found");
@@ -5878,13 +6390,13 @@ Task completed.
5878
6390
  };
5879
6391
 
5880
6392
  export {
6393
+ STATUS_ICONS,
6394
+ KIND_ICONS,
5881
6395
  progressBar,
5882
6396
  formatTokens,
5883
6397
  stripCodeFences,
5884
6398
  truncateContent,
5885
6399
  splitMessage,
5886
- STATUS_ICONS,
5887
- KIND_ICONS,
5888
6400
  extractContentText,
5889
6401
  formatToolSummary,
5890
6402
  formatToolTitle,
@@ -5895,4 +6407,4 @@ export {
5895
6407
  BaseRenderer,
5896
6408
  TelegramAdapter
5897
6409
  };
5898
- //# sourceMappingURL=chunk-RXMWJHWH.js.map
6410
+ //# sourceMappingURL=chunk-XBZIHNKV.js.map