@openacp/cli 0.2.24 → 0.2.26

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.
@@ -54,33 +54,35 @@ import { randomUUID } from "crypto";
54
54
  import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
55
55
  var log = createChildLogger({ module: "agent-instance" });
56
56
  function resolveAgentCommand(cmd) {
57
- const packageDirs = [
58
- path.resolve(
59
- process.cwd(),
60
- "node_modules",
61
- "@zed-industries",
62
- cmd,
63
- "dist",
64
- "index.js"
65
- ),
66
- path.resolve(process.cwd(), "node_modules", cmd, "dist", "index.js")
67
- ];
68
- for (const jsPath of packageDirs) {
69
- if (fs.existsSync(jsPath)) {
70
- return { command: process.execPath, args: [jsPath] };
71
- }
72
- }
73
- const localBin = path.resolve(process.cwd(), "node_modules", ".bin", cmd);
74
- if (fs.existsSync(localBin)) {
75
- const content = fs.readFileSync(localBin, "utf-8");
76
- if (content.startsWith("#!/usr/bin/env node")) {
77
- return { command: process.execPath, args: [localBin] };
78
- }
79
- const match = content.match(/"([^"]+\.js)"/);
80
- if (match) {
81
- const target = path.resolve(path.dirname(localBin), match[1]);
82
- if (fs.existsSync(target)) {
83
- return { command: process.execPath, args: [target] };
57
+ const searchRoots = [process.cwd()];
58
+ const ownDir = path.resolve(import.meta.dirname, "..", "..");
59
+ if (ownDir !== process.cwd()) {
60
+ searchRoots.push(ownDir);
61
+ }
62
+ for (const root of searchRoots) {
63
+ const packageDirs = [
64
+ path.resolve(root, "node_modules", "@zed-industries", cmd, "dist", "index.js"),
65
+ path.resolve(root, "node_modules", cmd, "dist", "index.js")
66
+ ];
67
+ for (const jsPath of packageDirs) {
68
+ if (fs.existsSync(jsPath)) {
69
+ return { command: process.execPath, args: [jsPath] };
70
+ }
71
+ }
72
+ }
73
+ for (const root of searchRoots) {
74
+ const localBin = path.resolve(root, "node_modules", ".bin", cmd);
75
+ if (fs.existsSync(localBin)) {
76
+ const content = fs.readFileSync(localBin, "utf-8");
77
+ if (content.startsWith("#!/usr/bin/env node")) {
78
+ return { command: process.execPath, args: [localBin] };
79
+ }
80
+ const match = content.match(/"([^"]+\.js)"/);
81
+ if (match) {
82
+ const target = path.resolve(path.dirname(localBin), match[1]);
83
+ if (fs.existsSync(target)) {
84
+ return { command: process.execPath, args: [target] };
85
+ }
84
86
  }
85
87
  }
86
88
  }
@@ -1588,20 +1590,25 @@ function splitMessage(text, maxLength = 4096) {
1588
1590
  }
1589
1591
 
1590
1592
  // src/adapters/telegram/streaming.ts
1593
+ var nextDraftId = 1;
1591
1594
  var MessageDraft = class {
1592
- // 1 second throttle
1593
- constructor(bot, chatId, threadId) {
1595
+ // Only set in fallback mode (sendMessageDraft returns true, not Message)
1596
+ constructor(bot, chatId, threadId, throttleMs = 200, sendQueue) {
1594
1597
  this.bot = bot;
1595
1598
  this.chatId = chatId;
1596
1599
  this.threadId = threadId;
1600
+ this.sendQueue = sendQueue;
1601
+ this.draftId = nextDraftId++;
1602
+ this.minInterval = throttleMs;
1597
1603
  }
1598
- messageId;
1604
+ draftId;
1599
1605
  buffer = "";
1600
1606
  lastFlush = 0;
1601
1607
  flushTimer;
1602
1608
  flushPromise = Promise.resolve();
1603
- // serialize flushes
1604
- minInterval = 1e3;
1609
+ minInterval;
1610
+ useFallback = false;
1611
+ messageId;
1605
1612
  append(text) {
1606
1613
  this.buffer += text;
1607
1614
  this.scheduleFlush();
@@ -1626,34 +1633,48 @@ var MessageDraft = class {
1626
1633
  const html = markdownToTelegramHtml(this.buffer);
1627
1634
  const truncated = html.length > 4096 ? html.slice(0, 4090) + "\n..." : html;
1628
1635
  if (!truncated) return;
1636
+ if (this.useFallback) {
1637
+ await this.flushFallback(truncated);
1638
+ return;
1639
+ }
1640
+ try {
1641
+ await this.bot.api.sendMessageDraft(this.chatId, this.draftId, truncated, {
1642
+ message_thread_id: this.threadId,
1643
+ parse_mode: "HTML"
1644
+ });
1645
+ } catch {
1646
+ this.useFallback = true;
1647
+ this.minInterval = 1e3;
1648
+ await this.flushFallback(truncated);
1649
+ }
1650
+ }
1651
+ async flushFallback(html) {
1652
+ const exec = this.sendQueue ? (fn) => this.sendQueue.enqueue(fn) : (fn) => fn();
1629
1653
  try {
1630
1654
  if (!this.messageId) {
1631
- const msg = await this.bot.api.sendMessage(this.chatId, truncated, {
1632
- message_thread_id: this.threadId,
1633
- parse_mode: "HTML",
1634
- disable_notification: true
1635
- });
1655
+ const msg = await exec(
1656
+ () => this.bot.api.sendMessage(this.chatId, html, {
1657
+ message_thread_id: this.threadId,
1658
+ parse_mode: "HTML",
1659
+ disable_notification: true
1660
+ })
1661
+ );
1636
1662
  this.messageId = msg.message_id;
1637
1663
  } else {
1638
- await this.bot.api.editMessageText(
1639
- this.chatId,
1640
- this.messageId,
1641
- truncated,
1642
- {
1664
+ await exec(
1665
+ () => this.bot.api.editMessageText(this.chatId, this.messageId, html, {
1643
1666
  parse_mode: "HTML"
1644
- }
1667
+ })
1645
1668
  );
1646
1669
  }
1647
1670
  } catch {
1648
1671
  try {
1649
1672
  if (!this.messageId) {
1650
- const msg = await this.bot.api.sendMessage(
1651
- this.chatId,
1652
- this.buffer.slice(0, 4096),
1653
- {
1673
+ const msg = await exec(
1674
+ () => this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {
1654
1675
  message_thread_id: this.threadId,
1655
1676
  disable_notification: true
1656
- }
1677
+ })
1657
1678
  );
1658
1679
  this.messageId = msg.message_id;
1659
1680
  }
@@ -1661,7 +1682,7 @@ var MessageDraft = class {
1661
1682
  }
1662
1683
  }
1663
1684
  }
1664
- async finalize(replyMarkup) {
1685
+ async finalize() {
1665
1686
  if (this.flushTimer) {
1666
1687
  clearTimeout(this.flushTimer);
1667
1688
  this.flushTimer = void 0;
@@ -1673,38 +1694,25 @@ var MessageDraft = class {
1673
1694
  try {
1674
1695
  for (let i = 0; i < chunks.length; i++) {
1675
1696
  const chunk = chunks[i];
1676
- const isLast = i === chunks.length - 1;
1677
- const markup = isLast && replyMarkup ? { reply_markup: replyMarkup } : {};
1678
1697
  if (i === 0 && this.messageId) {
1679
- await this.bot.api.editMessageText(
1680
- this.chatId,
1681
- this.messageId,
1682
- chunk,
1683
- {
1684
- parse_mode: "HTML",
1685
- ...markup
1686
- }
1687
- );
1698
+ await this.bot.api.editMessageText(this.chatId, this.messageId, chunk, {
1699
+ parse_mode: "HTML"
1700
+ });
1688
1701
  } else {
1689
1702
  const msg = await this.bot.api.sendMessage(this.chatId, chunk, {
1690
1703
  message_thread_id: this.threadId,
1691
1704
  parse_mode: "HTML",
1692
- disable_notification: true,
1693
- ...markup
1705
+ disable_notification: true
1694
1706
  });
1695
1707
  this.messageId = msg.message_id;
1696
1708
  }
1697
1709
  }
1698
1710
  } catch {
1699
1711
  try {
1700
- await this.bot.api.sendMessage(
1701
- this.chatId,
1702
- this.buffer.slice(0, 4096),
1703
- {
1704
- message_thread_id: this.threadId,
1705
- disable_notification: true
1706
- }
1707
- );
1712
+ await this.bot.api.sendMessage(this.chatId, this.buffer.slice(0, 4096), {
1713
+ message_thread_id: this.threadId,
1714
+ disable_notification: true
1715
+ });
1708
1716
  } catch {
1709
1717
  }
1710
1718
  }
@@ -1713,9 +1721,6 @@ var MessageDraft = class {
1713
1721
  getMessageId() {
1714
1722
  return this.messageId;
1715
1723
  }
1716
- getBuffer() {
1717
- return this.buffer;
1718
- }
1719
1724
  };
1720
1725
 
1721
1726
  // src/adapters/telegram/topics.ts
@@ -1753,10 +1758,10 @@ function buildDeepLink(chatId, messageId) {
1753
1758
  import { InlineKeyboard } from "grammy";
1754
1759
  import { nanoid as nanoid2 } from "nanoid";
1755
1760
  var log6 = createChildLogger({ module: "telegram-commands" });
1756
- function setupCommands(bot, core, chatId) {
1757
- bot.command("new", (ctx) => handleNew(ctx, core, chatId));
1761
+ function setupCommands(bot, core, chatId, assistant) {
1762
+ bot.command("new", (ctx) => handleNew(ctx, core, chatId, assistant));
1758
1763
  bot.command("new_chat", (ctx) => handleNewChat(ctx, core, chatId));
1759
- bot.command("cancel", (ctx) => handleCancel(ctx, core));
1764
+ bot.command("cancel", (ctx) => handleCancel(ctx, core, assistant));
1760
1765
  bot.command("status", (ctx) => handleStatus(ctx, core));
1761
1766
  bot.command("agents", (ctx) => handleAgents(ctx, core));
1762
1767
  bot.command("help", (ctx) => handleHelp(ctx));
@@ -1801,12 +1806,21 @@ Choose an action:`, {
1801
1806
  reply_markup: buildMenuKeyboard()
1802
1807
  });
1803
1808
  }
1804
- async function handleNew(ctx, core, chatId) {
1809
+ async function handleNew(ctx, core, chatId, assistant) {
1805
1810
  const rawMatch = ctx.match;
1806
1811
  const matchStr = typeof rawMatch === "string" ? rawMatch : "";
1807
1812
  const args = matchStr.split(" ").filter(Boolean);
1808
1813
  const agentName = args[0];
1809
1814
  const workspace = args[1];
1815
+ const currentThreadId = ctx.message?.message_thread_id;
1816
+ if (assistant && currentThreadId === assistant.topicId && (!agentName || !workspace)) {
1817
+ const assistantSession = assistant.getSession();
1818
+ if (assistantSession) {
1819
+ const prompt = agentName ? `User wants to create a new session with agent "${agentName}" but didn't specify a workspace. Ask them which workspace to use.` : `User wants to create a new session. Ask them which agent and workspace to use.`;
1820
+ await assistantSession.enqueuePrompt(prompt);
1821
+ return;
1822
+ }
1823
+ }
1810
1824
  log6.info({ userId: ctx.from?.id, agentName }, "New session command");
1811
1825
  let threadId;
1812
1826
  try {
@@ -1900,9 +1914,18 @@ async function handleNewChat(ctx, core, chatId) {
1900
1914
  await ctx.reply(`\u274C ${escapeHtml(message)}`, { parse_mode: "HTML" });
1901
1915
  }
1902
1916
  }
1903
- async function handleCancel(ctx, core) {
1917
+ async function handleCancel(ctx, core, assistant) {
1904
1918
  const threadId = ctx.message?.message_thread_id;
1905
1919
  if (!threadId) return;
1920
+ if (assistant && threadId === assistant.topicId) {
1921
+ const assistantSession = assistant.getSession();
1922
+ if (assistantSession) {
1923
+ await assistantSession.enqueuePrompt(
1924
+ "User wants to cancel a session. Confirm which session to cancel."
1925
+ );
1926
+ return;
1927
+ }
1928
+ }
1906
1929
  const session = core.sessionManager.getSessionByThread(
1907
1930
  "telegram",
1908
1931
  String(threadId)
@@ -2190,6 +2213,39 @@ function redirectToAssistant(chatId, assistantTopicId) {
2190
2213
  return `\u{1F4AC} Please use the <a href="${link}">\u{1F916} Assistant</a> topic to chat with OpenACP.`;
2191
2214
  }
2192
2215
 
2216
+ // src/adapters/telegram/send-queue.ts
2217
+ var TelegramSendQueue = class {
2218
+ queue = Promise.resolve();
2219
+ lastExec = 0;
2220
+ minInterval;
2221
+ constructor(minInterval = 100) {
2222
+ this.minInterval = minInterval;
2223
+ }
2224
+ enqueue(fn) {
2225
+ let resolve;
2226
+ let reject;
2227
+ const resultPromise = new Promise((res, rej) => {
2228
+ resolve = res;
2229
+ reject = rej;
2230
+ });
2231
+ this.queue = this.queue.then(async () => {
2232
+ const elapsed = Date.now() - this.lastExec;
2233
+ if (elapsed < this.minInterval) {
2234
+ await new Promise((r) => setTimeout(r, this.minInterval - elapsed));
2235
+ }
2236
+ try {
2237
+ const result = await fn();
2238
+ resolve(result);
2239
+ } catch (err) {
2240
+ reject(err);
2241
+ } finally {
2242
+ this.lastExec = Date.now();
2243
+ }
2244
+ });
2245
+ return resultPromise;
2246
+ }
2247
+ };
2248
+
2193
2249
  // src/adapters/telegram/action-detect.ts
2194
2250
  import { nanoid as nanoid4 } from "nanoid";
2195
2251
  import { InlineKeyboard as InlineKeyboard3 } from "grammy";
@@ -2354,6 +2410,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2354
2410
  bot;
2355
2411
  telegramConfig;
2356
2412
  sessionDrafts = /* @__PURE__ */ new Map();
2413
+ sessionTextBuffers = /* @__PURE__ */ new Map();
2357
2414
  toolCallMessages = /* @__PURE__ */ new Map();
2358
2415
  // sessionId → (toolCallId → state)
2359
2416
  permissionHandler;
@@ -2362,6 +2419,7 @@ var TelegramAdapter = class extends ChannelAdapter {
2362
2419
  assistantTopicId;
2363
2420
  skillMessages = /* @__PURE__ */ new Map();
2364
2421
  // sessionId → pinned messageId
2422
+ sendQueue = new TelegramSendQueue();
2365
2423
  constructor(core, config) {
2366
2424
  super(core, config);
2367
2425
  this.telegramConfig = config;
@@ -2372,6 +2430,22 @@ var TelegramAdapter = class extends ChannelAdapter {
2372
2430
  const rootCause = err.error instanceof Error ? err.error : err;
2373
2431
  log8.error({ err: rootCause }, "Telegram bot error");
2374
2432
  });
2433
+ this.bot.api.config.use(async (prev, method, payload, signal) => {
2434
+ const maxRetries = 3;
2435
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
2436
+ const result = await prev(method, payload, signal);
2437
+ if (result.ok || result.error_code !== 429 || attempt === maxRetries) {
2438
+ return result;
2439
+ }
2440
+ const retryAfter = (result.parameters?.retry_after ?? 5) + 1;
2441
+ log8.warn(
2442
+ { method, retryAfter, attempt: attempt + 1 },
2443
+ "Rate limited by Telegram, retrying"
2444
+ );
2445
+ await new Promise((r) => setTimeout(r, retryAfter * 1e3));
2446
+ }
2447
+ return prev(method, payload, signal);
2448
+ });
2375
2449
  this.bot.api.config.use((prev, method, payload, signal) => {
2376
2450
  if (method === "getUpdates") {
2377
2451
  const p = payload;
@@ -2423,7 +2497,11 @@ var TelegramAdapter = class extends ChannelAdapter {
2423
2497
  setupCommands(
2424
2498
  this.bot,
2425
2499
  this.core,
2426
- this.telegramConfig.chatId
2500
+ this.telegramConfig.chatId,
2501
+ {
2502
+ topicId: this.assistantTopicId,
2503
+ getSession: () => this.assistantSession
2504
+ }
2427
2505
  );
2428
2506
  this.permissionHandler.setupCallbackHandler();
2429
2507
  this.setupRoutes();
@@ -2519,24 +2597,32 @@ Workspace: <code>${workspace}</code>
2519
2597
  draft = new MessageDraft(
2520
2598
  this.bot,
2521
2599
  this.telegramConfig.chatId,
2522
- threadId
2600
+ threadId,
2601
+ this.telegramConfig.streamThrottleMs,
2602
+ this.sendQueue
2523
2603
  );
2524
2604
  this.sessionDrafts.set(sessionId, draft);
2525
2605
  }
2526
2606
  draft.append(content.text);
2607
+ this.sessionTextBuffers.set(
2608
+ sessionId,
2609
+ (this.sessionTextBuffers.get(sessionId) ?? "") + content.text
2610
+ );
2527
2611
  break;
2528
2612
  }
2529
2613
  case "tool_call": {
2530
2614
  await this.finalizeDraft(sessionId);
2531
2615
  const meta = content.metadata;
2532
- const msg = await this.bot.api.sendMessage(
2533
- this.telegramConfig.chatId,
2534
- formatToolCall(meta),
2535
- {
2536
- message_thread_id: threadId,
2537
- parse_mode: "HTML",
2538
- disable_notification: true
2539
- }
2616
+ const msg = await this.sendQueue.enqueue(
2617
+ () => this.bot.api.sendMessage(
2618
+ this.telegramConfig.chatId,
2619
+ formatToolCall(meta),
2620
+ {
2621
+ message_thread_id: threadId,
2622
+ parse_mode: "HTML",
2623
+ disable_notification: true
2624
+ }
2625
+ )
2540
2626
  );
2541
2627
  if (!this.toolCallMessages.has(sessionId)) {
2542
2628
  this.toolCallMessages.set(sessionId, /* @__PURE__ */ new Map());
@@ -2562,11 +2648,13 @@ Workspace: <code>${workspace}</code>
2562
2648
  viewerLinks
2563
2649
  };
2564
2650
  try {
2565
- await this.bot.api.editMessageText(
2566
- this.telegramConfig.chatId,
2567
- toolState.msgId,
2568
- formatToolUpdate(merged),
2569
- { parse_mode: "HTML" }
2651
+ await this.sendQueue.enqueue(
2652
+ () => this.bot.api.editMessageText(
2653
+ this.telegramConfig.chatId,
2654
+ toolState.msgId,
2655
+ formatToolUpdate(merged),
2656
+ { parse_mode: "HTML" }
2657
+ )
2570
2658
  );
2571
2659
  } catch {
2572
2660
  }
@@ -2575,31 +2663,35 @@ Workspace: <code>${workspace}</code>
2575
2663
  }
2576
2664
  case "plan": {
2577
2665
  await this.finalizeDraft(sessionId);
2578
- await this.bot.api.sendMessage(
2579
- this.telegramConfig.chatId,
2580
- formatPlan(
2581
- content.metadata
2582
- ),
2583
- {
2584
- message_thread_id: threadId,
2585
- parse_mode: "HTML",
2586
- disable_notification: true
2587
- }
2666
+ await this.sendQueue.enqueue(
2667
+ () => this.bot.api.sendMessage(
2668
+ this.telegramConfig.chatId,
2669
+ formatPlan(
2670
+ content.metadata
2671
+ ),
2672
+ {
2673
+ message_thread_id: threadId,
2674
+ parse_mode: "HTML",
2675
+ disable_notification: true
2676
+ }
2677
+ )
2588
2678
  );
2589
2679
  break;
2590
2680
  }
2591
2681
  case "usage": {
2592
2682
  await this.finalizeDraft(sessionId);
2593
- await this.bot.api.sendMessage(
2594
- this.telegramConfig.chatId,
2595
- formatUsage(
2596
- content.metadata
2597
- ),
2598
- {
2599
- message_thread_id: threadId,
2600
- parse_mode: "HTML",
2601
- disable_notification: true
2602
- }
2683
+ await this.sendQueue.enqueue(
2684
+ () => this.bot.api.sendMessage(
2685
+ this.telegramConfig.chatId,
2686
+ formatUsage(
2687
+ content.metadata
2688
+ ),
2689
+ {
2690
+ message_thread_id: threadId,
2691
+ parse_mode: "HTML",
2692
+ disable_notification: true
2693
+ }
2694
+ )
2603
2695
  );
2604
2696
  break;
2605
2697
  }
@@ -2608,27 +2700,31 @@ Workspace: <code>${workspace}</code>
2608
2700
  this.sessionDrafts.delete(sessionId);
2609
2701
  this.toolCallMessages.delete(sessionId);
2610
2702
  await this.cleanupSkillCommands(sessionId);
2611
- await this.bot.api.sendMessage(
2612
- this.telegramConfig.chatId,
2613
- `\u2705 <b>Done</b>`,
2614
- {
2615
- message_thread_id: threadId,
2616
- parse_mode: "HTML",
2617
- disable_notification: true
2618
- }
2703
+ await this.sendQueue.enqueue(
2704
+ () => this.bot.api.sendMessage(
2705
+ this.telegramConfig.chatId,
2706
+ `\u2705 <b>Done</b>`,
2707
+ {
2708
+ message_thread_id: threadId,
2709
+ parse_mode: "HTML",
2710
+ disable_notification: true
2711
+ }
2712
+ )
2619
2713
  );
2620
2714
  break;
2621
2715
  }
2622
2716
  case "error": {
2623
2717
  await this.finalizeDraft(sessionId);
2624
- await this.bot.api.sendMessage(
2625
- this.telegramConfig.chatId,
2626
- `\u274C <b>Error:</b> ${escapeHtml(content.text)}`,
2627
- {
2628
- message_thread_id: threadId,
2629
- parse_mode: "HTML",
2630
- disable_notification: true
2631
- }
2718
+ await this.sendQueue.enqueue(
2719
+ () => this.bot.api.sendMessage(
2720
+ this.telegramConfig.chatId,
2721
+ `\u274C <b>Error:</b> ${escapeHtml(content.text)}`,
2722
+ {
2723
+ message_thread_id: threadId,
2724
+ parse_mode: "HTML",
2725
+ disable_notification: true
2726
+ }
2727
+ )
2632
2728
  );
2633
2729
  break;
2634
2730
  }
@@ -2640,7 +2736,9 @@ Workspace: <code>${workspace}</code>
2640
2736
  sessionId
2641
2737
  );
2642
2738
  if (!session) return;
2643
- await this.permissionHandler.sendPermissionRequest(session, request);
2739
+ await this.sendQueue.enqueue(
2740
+ () => this.permissionHandler.sendPermissionRequest(session, request)
2741
+ );
2644
2742
  }
2645
2743
  async sendNotification(notification) {
2646
2744
  log8.info(
@@ -2662,11 +2760,13 @@ Workspace: <code>${workspace}</code>
2662
2760
 
2663
2761
  <a href="${notification.deepLink}">\u2192 Go to message</a>`;
2664
2762
  }
2665
- await this.bot.api.sendMessage(this.telegramConfig.chatId, text, {
2666
- message_thread_id: this.notificationTopicId,
2667
- parse_mode: "HTML",
2668
- disable_notification: false
2669
- });
2763
+ await this.sendQueue.enqueue(
2764
+ () => this.bot.api.sendMessage(this.telegramConfig.chatId, text, {
2765
+ message_thread_id: this.notificationTopicId,
2766
+ parse_mode: "HTML",
2767
+ disable_notification: false
2768
+ })
2769
+ );
2670
2770
  }
2671
2771
  async createSessionThread(sessionId, name) {
2672
2772
  log8.info({ sessionId, name }, "Session topic created");
@@ -2714,15 +2814,17 @@ Workspace: <code>${workspace}</code>
2714
2814
  }
2715
2815
  }
2716
2816
  try {
2717
- const msg = await this.bot.api.sendMessage(
2718
- this.telegramConfig.chatId,
2719
- text,
2720
- {
2721
- message_thread_id: threadId,
2722
- parse_mode: "HTML",
2723
- reply_markup: keyboard,
2724
- disable_notification: true
2725
- }
2817
+ const msg = await this.sendQueue.enqueue(
2818
+ () => this.bot.api.sendMessage(
2819
+ this.telegramConfig.chatId,
2820
+ text,
2821
+ {
2822
+ message_thread_id: threadId,
2823
+ parse_mode: "HTML",
2824
+ reply_markup: keyboard,
2825
+ disable_notification: true
2826
+ }
2827
+ )
2726
2828
  );
2727
2829
  this.skillMessages.set(sessionId, msg.message_id);
2728
2830
  await this.bot.api.pinChatMessage(
@@ -2778,19 +2880,29 @@ Workspace: <code>${workspace}</code>
2778
2880
  async finalizeDraft(sessionId) {
2779
2881
  const draft = this.sessionDrafts.get(sessionId);
2780
2882
  if (!draft) return;
2781
- let keyboard;
2883
+ const finalMsgId = await draft.finalize();
2884
+ this.sessionDrafts.delete(sessionId);
2782
2885
  if (sessionId === this.assistantSession?.id) {
2783
- const fullText = draft.getBuffer();
2784
- if (fullText) {
2886
+ const fullText = this.sessionTextBuffers.get(sessionId);
2887
+ this.sessionTextBuffers.delete(sessionId);
2888
+ if (fullText && finalMsgId) {
2785
2889
  const detected = detectAction(fullText);
2786
2890
  if (detected) {
2787
2891
  const actionId = storeAction(detected);
2788
- keyboard = buildActionKeyboard(actionId, detected);
2892
+ const keyboard = buildActionKeyboard(actionId, detected);
2893
+ try {
2894
+ await this.bot.api.editMessageReplyMarkup(
2895
+ this.telegramConfig.chatId,
2896
+ finalMsgId,
2897
+ { reply_markup: keyboard }
2898
+ );
2899
+ } catch {
2900
+ }
2789
2901
  }
2790
2902
  }
2903
+ } else {
2904
+ this.sessionTextBuffers.delete(sessionId);
2791
2905
  }
2792
- await draft.finalize(keyboard);
2793
- this.sessionDrafts.delete(sessionId);
2794
2906
  }
2795
2907
  };
2796
2908
 
@@ -2808,4 +2920,4 @@ export {
2808
2920
  ApiServer,
2809
2921
  TelegramAdapter
2810
2922
  };
2811
- //# sourceMappingURL=chunk-IX63F4JG.js.map
2923
+ //# sourceMappingURL=chunk-HHQW27DT.js.map