open-agents-ai 0.187.583 → 0.187.585

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/README.md CHANGED
@@ -3365,7 +3365,7 @@ All settings commands accept `--local` to save to project `.oa/settings.json` in
3365
3365
 
3366
3366
  `/platforms menu` opens a keyboard-driven connectivity surface for platform status and onboarding. The same surface is available through `/gateway menu`.
3367
3367
 
3368
- Supported adapter IDs are `telegram`, `discord`, `slack`, `matrix`, and `webhook`. Telegram is wired into the existing bridge controls, so the menu can save the bot token, save the admin user ID, start the bridge, stop it, and show status. The other platform adapters expose the shared connector configuration surface: enable/disable, token environment variable, base URL or webhook URL, default target/channel/room, polling vs webhook mode, redacted config display, and status/health reporting.
3368
+ Supported adapter IDs are `telegram`, `discord`, `slack`, `matrix`, and `webhook`. Telegram is wired into the existing bridge controls, so the menu can save the bot token, save the admin user ID, set the interaction mode, start the bridge, stop it, and show status. The other platform adapters expose the shared connector configuration surface: enable/disable, token environment variable, base URL or webhook URL, default target/channel/room, polling vs webhook mode, redacted config display, and status/health reporting.
3369
3369
 
3370
3370
  Use environment variables for credentials:
3371
3371
 
@@ -3416,7 +3416,7 @@ The steering sub-agent uses the same model and backend as the main agent with `m
3416
3416
 
3417
3417
  <div align="right"><a href="#top">back to top</a></div>
3418
3418
 
3419
- Connect the agent to a Telegram bot. Each incoming message spawns a dedicated sub-agent that handles the conversation independently — visible in the terminal waterfall alongside other agent activity.
3419
+ Connect the agent to a Telegram bot. Telegram can run in auto, chat, or action mode: conversational messages get rapid streamed replies in chat mode, while codebase/file/run requests use dedicated action sub-agents that are visible in the terminal waterfall alongside other agent activity.
3420
3420
 
3421
3421
  ```bash
3422
3422
  /telegram --key <token> # Save bot token (persisted to .oa/settings.json)
@@ -3424,6 +3424,7 @@ Connect the agent to a Telegram bot. Each incoming message spawns a dedicated su
3424
3424
  /telegram # Toggle bridge on/off (uses saved key)
3425
3425
  /telegram status # Show connection status + active sub-agents
3426
3426
  /telegram stop # Disconnect and kill all sub-agents
3427
+ /telegram mode auto|chat|action # Set interaction routing profile
3427
3428
  /telegram auth # Show a one-time TUI-only admin auth code
3428
3429
  /telegram auth cancel # Cancel the pending admin auth code
3429
3430
  /telegram bot <username> <text> # Send bot-to-bot message by @username
@@ -3438,7 +3439,17 @@ Connect the agent to a Telegram bot. Each incoming message spawns a dedicated su
3438
3439
  /telegram delete-reactions <chat> --user <id> # Delete recent reactions
3439
3440
  ```
3440
3441
 
3441
- The bot token and admin ID are persisted to project settings, so you only need to set them once. After that, bare `/telegram` toggles the bridge on and off like a service watchdog.
3442
+ The bot token, admin ID, and interaction mode are persisted to settings, so you only need to set them once. After that, bare `/telegram` toggles the bridge on and off like a service watchdog.
3443
+
3444
+ ### Telegram Interaction Modes
3445
+
3446
+ Use `/telegram mode auto|chat|action` to control how inbound Telegram messages are routed:
3447
+
3448
+ - **auto** — short greetings, quick questions, playful messages, and conversational turns use fast streamed chat replies; explicit codebase/file/command/run/test requests use action sub-agents.
3449
+ - **chat** — every non-command message gets a direct quick-chat completion with no tool loop. This is best for rapid back-and-forth conversation.
3450
+ - **action** — every non-command message runs through the Telegram sub-agent path with the configured tool policy.
3451
+
3452
+ Telegram quick-chat views and action sub-agent views both appear as blue plane-labeled items in the systems header. Clicking one swaps the main scrollable window to that Telegram-only content buffer; press Esc to return to the primary view.
3442
3453
 
3443
3454
  ### Telegram Admin Authentication
3444
3455
 
@@ -3462,7 +3473,7 @@ The Telegram bridge handles modern Bot API traffic directly:
3462
3473
  - **Direct-message channels** — direct-message channel/topic metadata is preserved on normalized Telegram messages for routing and future adapter logic.
3463
3474
  - **Drafts and profile chat reads** — `/telegram draft` can set or clear message drafts, and `/telegram personal <user_id> <limit>` fetches recent messages from a user's profile personal chat.
3464
3475
  - **Reactions/admin helpers** — `/telegram delete-reaction` removes a message reaction, `/telegram delete-reactions` removes recent reactions by a user/chat, and `/telegram admins <chat> [--bots]` can include bot administrators.
3465
- - **TUI sub-agent visibility** — Telegram conversations register as blue plane-labeled sub-agent views in the systems panel and show an active plane indicator in the footer while the bridge or Telegram sub-agents are active.
3476
+ - **TUI Telegram visibility** — Telegram quick-chat and action conversations register as blue plane-labeled views in the systems panel; clicking a view swaps the main scrollable window to that Telegram-only buffer, and the footer shows an active plane indicator while the bridge or Telegram work is active.
3466
3477
 
3467
3478
  ### Admin Slash Command Passthrough
3468
3479
 
package/dist/index.js CHANGED
@@ -528118,6 +528118,7 @@ var init_agenticRunner = __esm({
528118
528118
  compactionThreshold: options2?.compactionThreshold ?? 4e4,
528119
528119
  deepContext: options2?.deepContext ?? false,
528120
528120
  dynamicContext: options2?.dynamicContext ?? "",
528121
+ sessionId: options2?.sessionId ?? "",
528121
528122
  streamEnabled: options2?.streamEnabled ?? false,
528122
528123
  thinking: options2?.thinking ?? true,
528123
528124
  bruteForce: options2?.bruteForce ?? true,
@@ -528792,7 +528793,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
528792
528793
  }
528793
528794
  readSessionTodos() {
528794
528795
  try {
528795
- const sid = process.env["OA_SESSION_ID"] || this._sessionId || "default";
528796
+ const sid = this._sessionId || process.env["OA_SESSION_ID"] || "default";
528796
528797
  const safe = sid.replace(/[^a-zA-Z0-9_.-]/g, "_");
528797
528798
  const fp = _pathJoin(_osHomedir(), ".open-agents", "todos", `${safe}.json`);
528798
528799
  if (!_fsExistsSync(fp))
@@ -530787,7 +530788,7 @@ Respond with your assessment, then take action.`;
530787
530788
  }
530788
530789
  this._fileRegistry.clear();
530789
530790
  this._memexArchive.clear();
530790
- this._sessionId = process.env["OA_SESSION_ID"] && String(process.env["OA_SESSION_ID"]) || `session-${Date.now()}`;
530791
+ this._sessionId = this.options.sessionId && String(this.options.sessionId) || process.env["OA_SESSION_ID"] && String(process.env["OA_SESSION_ID"]) || `session-${Date.now()}`;
530791
530792
  this._appState = createAppState({
530792
530793
  sessionId: this._sessionId,
530793
530794
  model: this.backend.model ?? "",
@@ -530935,7 +530936,7 @@ TASK: ${task}` : task;
530935
530936
  messages2.push({ role: "system", content: _directive });
530936
530937
  const _todos = buildDecompositionTodos(_decomp.modules);
530937
530938
  try {
530938
- const sid = process.env["OA_SESSION_ID"] || this._sessionId || "default";
530939
+ const sid = this._sessionId || process.env["OA_SESSION_ID"] || "default";
530939
530940
  const safe = sid.replace(/[^a-zA-Z0-9_.-]/g, "_");
530940
530941
  const fp = _pathJoin(_osHomedir(), ".open-agents", "todos", `${safe}.json`);
530941
530942
  const dir = _pathJoin(_osHomedir(), ".open-agents", "todos");
@@ -536441,7 +536442,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
536441
536442
  */
536442
536443
  formatCompletedTodoAnchors() {
536443
536444
  try {
536444
- const sessionId = process.env["OA_SESSION_ID"] || this._sessionId;
536445
+ const sessionId = this._sessionId || process.env["OA_SESSION_ID"] || "default";
536445
536446
  const todos = readTodos(sessionId);
536446
536447
  if (todos.length === 0)
536447
536448
  return "";
@@ -549063,6 +549064,7 @@ var init_command_registry = __esm({
549063
549064
  ["/telegram", "Toggle Telegram bridge on/off (uses saved key)"],
549064
549065
  ["/telegram status", "Show Telegram bridge status"],
549065
549066
  ["/telegram stop", "Disconnect Telegram bridge"],
549067
+ ["/telegram mode auto|chat|action", "Set Telegram interaction routing: auto, fast chat, or action sub-agent"],
549066
549068
  ["/telegram auth", "Show a TUI-only one-time code for Telegram admin authentication"],
549067
549069
  ["/telegram auth cancel", "Cancel the pending Telegram admin authentication code"],
549068
549070
  ["/telegram bot <username> <text>", "Send a Bot API bot-to-bot message by @username"],
@@ -558482,6 +558484,8 @@ var init_status_bar = __esm({
558482
558484
  zones.push({ w: 2, render: () => "" });
558483
558485
  const voiceLabel = this._voiceActive ? ` ${this._voiceModelId || "voice"} ` : " voice ";
558484
558486
  zones.push({ w: voiceLabel.length + 2, render: () => "" });
558487
+ const telegramLabel = this._telegramStatus.activeSubAgents > 0 ? ` ✈ tg ${this._telegramStatus.activeSubAgents} ` : " ✈ tg ";
558488
+ zones.push({ w: telegramLabel.length + 2, render: () => "" });
558485
558489
  zones.push({ w: 9, render: () => "" });
558486
558490
  let pages = [];
558487
558491
  let cur = [];
@@ -559608,7 +559612,7 @@ var init_status_bar = __esm({
559608
559612
  * If currently on the "systems" panel, re-render to show updated agent list. */
559609
559613
  renderAgentTabs() {
559610
559614
  if (!this.active) return;
559611
- if (this.currentHeaderPanel === "systems") {
559615
+ if (String(this.currentHeaderPanel).startsWith("sys-")) {
559612
559616
  this.refreshHeaderContent();
559613
559617
  }
559614
559618
  }
@@ -579313,6 +579317,7 @@ sleep 1
579313
579317
  case "telegram":
579314
579318
  case "tg": {
579315
579319
  const parts = arg ? arg.split(/\s+/) : [];
579320
+ const isLocal = hasLocal;
579316
579321
  if (parts[0] === "stop" || parts[0] === "off") {
579317
579322
  if (ctx3.isTelegramActive?.()) {
579318
579323
  ctx3.telegramStop?.();
@@ -579325,6 +579330,23 @@ sleep 1
579325
579330
  ctx3.telegramStatus?.();
579326
579331
  return "handled";
579327
579332
  }
579333
+ if (parts[0] === "mode" || parts[0] === "profile") {
579334
+ const requested = parts.slice(1).find((part) => !part.startsWith("--"));
579335
+ if (!requested) {
579336
+ const current = ctx3.getTelegramSettings?.()?.mode ?? "auto";
579337
+ renderInfo(`Telegram interaction mode: ${c3.bold(current)}`);
579338
+ renderInfo("Modes: auto (chat vs action), chat (fast replies), action (sub-agent tool loop).");
579339
+ return "handled";
579340
+ }
579341
+ if (requested !== "auto" && requested !== "chat" && requested !== "action") {
579342
+ renderWarning("Usage: /telegram mode auto|chat|action [--local]");
579343
+ return "handled";
579344
+ }
579345
+ ctx3.saveTelegramSettings?.({ mode: requested, local: isLocal });
579346
+ ctx3.telegramSetInteractionMode?.(requested);
579347
+ renderInfo(`Telegram interaction mode set to ${c3.bold(requested)}${isLocal ? " (project)" : " (global)"}.`);
579348
+ return "handled";
579349
+ }
579328
579350
  if (parts[0] === "auth" || parts[0] === "authenticate") {
579329
579351
  if (parts[1] === "cancel") {
579330
579352
  const cancelled = ctx3.telegramCancelAdminAuth?.() ?? false;
@@ -579500,7 +579522,6 @@ sleep 1
579500
579522
  }
579501
579523
  return "handled";
579502
579524
  }
579503
- const isLocal = parts.includes("--local");
579504
579525
  const keyIdx = parts.indexOf("--key");
579505
579526
  const adminIdx = parts.indexOf("--admin");
579506
579527
  if (keyIdx !== -1 || adminIdx !== -1) {
@@ -579570,6 +579591,7 @@ sleep 1
579570
579591
  renderInfo(" /telegram Toggle on/off");
579571
579592
  renderInfo(" /telegram stop Stop bridge");
579572
579593
  renderInfo(" /telegram status Show status");
579594
+ renderInfo(" /telegram mode auto|chat|action Set interaction routing profile");
579573
579595
  renderInfo(" /telegram auth Show one-time admin auth code");
579574
579596
  renderInfo(" /telegram auth cancel Cancel pending admin auth code");
579575
579597
  renderInfo(" /telegram bot <username> <text> Send bot-to-bot message");
@@ -580072,6 +580094,15 @@ async function showConfigEditor(ctx3) {
580072
580094
  value: String(merged.telegramAdmin ?? "[not set]"),
580073
580095
  detail: String(merged.telegramAdmin ?? "[not set]")
580074
580096
  },
580097
+ {
580098
+ key: "telegramMode",
580099
+ label: "telegramMode",
580100
+ kind: "enum",
580101
+ value: String(merged.telegramMode ?? "auto"),
580102
+ detail: String(merged.telegramMode ?? "auto"),
580103
+ options: ["auto", "chat", "action"],
580104
+ settingsKey: "telegramMode"
580105
+ },
580075
580106
  // -- Actions --
580076
580107
  {
580077
580108
  key: "__h_actions__",
@@ -580337,6 +580368,7 @@ async function showPlatformOnboardingMenu(ctx3, id) {
580337
580368
  { key: "telegram-status", label: "Status", detail: "Show bridge status" },
580338
580369
  { key: "telegram-token", label: "Set bot token", detail: "Saved to existing Telegram settings" },
580339
580370
  { key: "telegram-admin", label: "Set admin user id", detail: "Restricts remote admin controls" },
580371
+ { key: "telegram-mode", label: "Interaction mode", detail: ctx3.getTelegramSettings?.()?.mode ?? "auto" },
580340
580372
  { key: "telegram-start", label: "Start bridge", detail: "Uses saved token" },
580341
580373
  { key: "telegram-stop", label: "Stop bridge", detail: "Disconnect long polling" }
580342
580374
  ] : [
@@ -580415,7 +580447,13 @@ async function showPlatformOnboardingMenu(ctx3, id) {
580415
580447
  if (!result.confirmed || !result.key) return;
580416
580448
  if (id === "telegram") {
580417
580449
  if (result.key === "telegram-status") ctx3.telegramStatus?.();
580418
- else if (result.key === "telegram-start") {
580450
+ else if (result.key === "telegram-mode") {
580451
+ const current2 = ctx3.getTelegramSettings?.()?.mode ?? "auto";
580452
+ const next = current2 === "auto" ? "chat" : current2 === "chat" ? "action" : "auto";
580453
+ ctx3.saveTelegramSettings?.({ mode: next });
580454
+ ctx3.telegramSetInteractionMode?.(next);
580455
+ renderInfo(`Telegram interaction mode set to ${next}.`);
580456
+ } else if (result.key === "telegram-start") {
580419
580457
  const settings = ctx3.getTelegramSettings?.() ?? {};
580420
580458
  if (!settings.key) renderWarning("No Telegram bot token configured.");
580421
580459
  else await ctx3.telegramStart?.(settings.key, settings.admin);
@@ -590782,7 +590820,7 @@ function getDefaultPolicy(context2) {
590782
590820
  case "terminal":
590783
590821
  return { blocked: /* @__PURE__ */ new Set(), allowed: /* @__PURE__ */ new Set() };
590784
590822
  case "telegram-admin-dm":
590785
- return { blocked: /* @__PURE__ */ new Set(["shell"]), allowed: /* @__PURE__ */ new Set() };
590823
+ return { blocked: /* @__PURE__ */ new Set(), allowed: /* @__PURE__ */ new Set() };
590786
590824
  case "telegram-admin-group":
590787
590825
  return { blocked: /* @__PURE__ */ new Set(), allowed: SAFE_GROUP_ADMIN_TOOLS };
590788
590826
  case "telegram-public":
@@ -590829,6 +590867,8 @@ var init_tool_policy = __esm({
590829
590867
  "memory_read",
590830
590868
  "memory_write",
590831
590869
  "memory_search",
590870
+ "todo_read",
590871
+ "todo_write",
590832
590872
  "web_search",
590833
590873
  "web_fetch",
590834
590874
  "task_complete"
@@ -590837,6 +590877,8 @@ var init_tool_policy = __esm({
590837
590877
  "memory_read",
590838
590878
  "memory_write",
590839
590879
  "memory_search",
590880
+ "todo_read",
590881
+ "todo_write",
590840
590882
  "web_search",
590841
590883
  "web_fetch",
590842
590884
  "web_crawl",
@@ -590857,6 +590899,28 @@ import { mkdirSync as mkdirSync58, existsSync as existsSync100, unlinkSync as un
590857
590899
  import { join as join117, resolve as resolve35, basename as basename21 } from "node:path";
590858
590900
  import { writeFile as writeFileAsync } from "node:fs/promises";
590859
590901
  import { createHash as createHash18, randomInt } from "node:crypto";
590902
+ function classifyTelegramInteraction(text, mode = "auto", options2 = {}) {
590903
+ if (mode === "chat") return "chat";
590904
+ if (mode === "action") return "action";
590905
+ const trimmed = text.trim();
590906
+ if (!trimmed) return "chat";
590907
+ if (options2.isSlashCommand || trimmed.startsWith("/")) return "action";
590908
+ if (options2.hasMedia) return "action";
590909
+ const hasAction = TELEGRAM_ACTION_INTENT_RE.test(trimmed);
590910
+ const hasCodebaseContext = TELEGRAM_CODEBASE_CONTEXT_RE.test(trimmed) || TELEGRAM_COMMANDISH_RE.test(trimmed) || /[`'"]?[\w./-]+\.(?:ts|tsx|js|jsx|mjs|cjs|json|md|py|rs|go|java|css|scss|html|yml|yaml|toml|sh|sql)[`'"]?/i.test(trimmed);
590911
+ if (hasAction && hasCodebaseContext) return "action";
590912
+ if (/^(please\s+|pls\s+|can you\s+|could you\s+|we need to\s+|i need you to\s+)?(fix|implement|patch|edit|refactor|run|test|build|install|debug|commit|deploy|publish)\b/i.test(trimmed)) {
590913
+ return "action";
590914
+ }
590915
+ if (TELEGRAM_COMMANDISH_RE.test(trimmed)) return "action";
590916
+ if (trimmed.includes("```") && hasAction) return "action";
590917
+ if (trimmed.length > 360 && hasAction) return "action";
590918
+ if (/\b(write|draft)\b.*\b(poem|story|joke|email|message|caption|song|haiku)\b/i.test(trimmed)) return "chat";
590919
+ if (TELEGRAM_CHAT_INTENT_RE.test(trimmed)) return "chat";
590920
+ if (/[??]\s*$/.test(trimmed) && !hasAction) return "chat";
590921
+ if (trimmed.length <= 180 && !hasCodebaseContext && !hasAction) return "chat";
590922
+ return hasAction ? "action" : "chat";
590923
+ }
590860
590924
  function convertMarkdownToTelegramHTML(md) {
590861
590925
  let html = md;
590862
590926
  html = html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -590886,6 +590950,60 @@ function sanitizeTelegramProgressText(text, maxLength) {
590886
590950
  const compact = stripTelegramHiddenThinking(text).replace(/\s+/g, " ").trim();
590887
590951
  return compact.length > maxLength ? compact.slice(0, Math.max(0, maxLength - 3)) + "..." : compact;
590888
590952
  }
590953
+ function truncateTelegramContext(text, maxLength) {
590954
+ const trimmed = text.trim();
590955
+ if (trimmed.length <= maxLength) return trimmed;
590956
+ return `${trimmed.slice(0, Math.max(0, maxLength - 80)).trimEnd()}
590957
+
590958
+ [Telegram context truncated; use tools for full detail.]`;
590959
+ }
590960
+ function buildTelegramRuntimeContext(now = /* @__PURE__ */ new Date(), repoRoot) {
590961
+ const date = new Intl.DateTimeFormat("en-US", {
590962
+ weekday: "long",
590963
+ year: "numeric",
590964
+ month: "long",
590965
+ day: "numeric"
590966
+ }).format(now);
590967
+ const time = new Intl.DateTimeFormat("en-US", {
590968
+ hour: "numeric",
590969
+ minute: "2-digit",
590970
+ second: "2-digit",
590971
+ timeZoneName: "short"
590972
+ }).format(now);
590973
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || process.env["TZ"] || "system";
590974
+ return [
590975
+ `Current date: ${date}`,
590976
+ `Current time: ${time}`,
590977
+ `Current ISO timestamp: ${now.toISOString()}`,
590978
+ `Timezone: ${timezone}`,
590979
+ repoRoot ? `Working directory: ${repoRoot}` : ""
590980
+ ].filter(Boolean).join("\n");
590981
+ }
590982
+ function telegramSessionIdFromKey(sessionKey) {
590983
+ return `telegram-${createHash18("sha1").update(sessionKey).digest("hex").slice(0, 16)}`;
590984
+ }
590985
+ function formatTelegramConversationHistory(history, maxEntries = 12) {
590986
+ const recent = history.filter((entry) => entry.text.trim()).slice(-maxEntries);
590987
+ if (recent.length === 0) return "";
590988
+ return recent.map((entry) => {
590989
+ const who = entry.role === "assistant" ? "Assistant" : "Telegram user";
590990
+ const mode = entry.mode ? `/${entry.mode}` : "";
590991
+ return `${who}${mode}: ${entry.text.trim()}`;
590992
+ }).join("\n");
590993
+ }
590994
+ function selectTelegramFinalResponse(args) {
590995
+ const candidates = [
590996
+ args.assistantText,
590997
+ args.streamText,
590998
+ args.accumulated,
590999
+ args.summary
591000
+ ];
591001
+ for (const candidate of candidates) {
591002
+ const cleaned = stripTelegramHiddenThinking(candidate || "").trim();
591003
+ if (cleaned) return cleaned;
591004
+ }
591005
+ return "";
591006
+ }
590889
591007
  function formatTelegramProgressEvent(event) {
590890
591008
  if (event.type === "tool_call" && event.toolName === "task_complete") return null;
590891
591009
  if (event.type === "tool_result" && event.toolName === "task_complete") return null;
@@ -591126,14 +591244,24 @@ function normalizeTelegramUpdate(update2) {
591126
591244
  sourceUpdateType
591127
591245
  };
591128
591246
  }
591129
- function adaptTool5(tool) {
591247
+ function adaptTool5(tool, todoSessionId) {
591130
591248
  return {
591131
591249
  name: tool.name,
591132
591250
  description: tool.description,
591133
591251
  parameters: tool.parameters,
591134
591252
  async execute(args) {
591135
- const result = await tool.execute(args);
591136
- return { success: result.success, output: result.output, error: result.error };
591253
+ const previousTodoSession = todoSessionId ? getTodoSessionId() : "";
591254
+ if (todoSessionId && (tool.name === "todo_write" || tool.name === "todo_read")) {
591255
+ setTodoSessionId(todoSessionId);
591256
+ }
591257
+ try {
591258
+ const result = await tool.execute(args);
591259
+ return { success: result.success, output: result.output, error: result.error };
591260
+ } finally {
591261
+ if (todoSessionId && (tool.name === "todo_write" || tool.name === "todo_read")) {
591262
+ setTodoSessionId(previousTodoSession);
591263
+ }
591264
+ }
591137
591265
  }
591138
591266
  };
591139
591267
  }
@@ -591160,11 +591288,13 @@ function mimeForPath(path11, fallbackKind) {
591160
591288
  if (fallbackKind === "video") return "video/mp4";
591161
591289
  return "application/octet-stream";
591162
591290
  }
591163
- function renderTelegramStart(botUsername, adminId) {
591291
+ function renderTelegramStart(botUsername, adminId, mode = "auto") {
591164
591292
  process.stdout.write(`
591165
591293
  ${c3.cyan("✈")} ${c3.bold("Telegram Bridge")} connected as @${botUsername}
591166
591294
  `);
591167
- process.stdout.write(` ${c3.dim("Sub-agent mode: each message spawns a dedicated agent")}
591295
+ process.stdout.write(` ${c3.dim(`Interaction mode: ${mode}`)}
591296
+ `);
591297
+ process.stdout.write(` ${c3.dim("Auto mode uses quick chat for conversational turns and sub-agents for action requests")}
591168
591298
  `);
591169
591299
  if (adminId) {
591170
591300
  process.stdout.write(` ${c3.dim(`Admin: ${adminId} (full memory + tools)`)}
@@ -591178,17 +591308,19 @@ function renderTelegramStart(botUsername, adminId) {
591178
591308
 
591179
591309
  `);
591180
591310
  }
591181
- function renderTelegramStatus(active, botUsername, adminId, activeSubAgents) {
591311
+ function renderTelegramStatus(active, botUsername, adminId, activeSubAgents, mode = "auto") {
591182
591312
  if (active) {
591183
591313
  process.stdout.write(`
591184
591314
  ${c3.green("●")} Telegram bridge: ${c3.bold("ACTIVE")} (@${botUsername ?? "?"})
591315
+ `);
591316
+ process.stdout.write(` Mode: ${mode}
591185
591317
  `);
591186
591318
  if (adminId) {
591187
591319
  process.stdout.write(` Admin: ${adminId}
591188
591320
  `);
591189
591321
  }
591190
591322
  if (activeSubAgents && activeSubAgents > 0) {
591191
- process.stdout.write(` Active sub-agents: ${activeSubAgents}
591323
+ process.stdout.write(` Active Telegram work: ${activeSubAgents}
591192
591324
  `);
591193
591325
  }
591194
591326
  process.stdout.write(` ${c3.dim("Use /telegram to toggle off")}
@@ -591246,7 +591378,7 @@ function renderTelegramSubAgentError(username, error) {
591246
591378
  process.stdout.write(` ${c3.dim("⎿")} ${c3.red("✘")} @${username}: ${c3.dim(preview)}
591247
591379
  `);
591248
591380
  }
591249
- var TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, GROUP_REPLY_DISCRETION_PROMPT, MEDIA_CACHE_TTL_MS, TelegramBridge;
591381
+ var TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_ACTION_INTENT_RE, TELEGRAM_CODEBASE_CONTEXT_RE, TELEGRAM_COMMANDISH_RE, TELEGRAM_CHAT_INTENT_RE, MEDIA_CACHE_TTL_MS, TelegramBridge;
591250
591382
  var init_telegram_bridge = __esm({
591251
591383
  "packages/cli/src/tui/telegram-bridge.ts"() {
591252
591384
  "use strict";
@@ -591306,6 +591438,37 @@ REPLY DISCRETION: You are in a group chat. Only respond if:
591306
591438
  If the message is casual group chatter not directed at you, use task_complete
591307
591439
  with summary "no_reply" to silently skip without responding.
591308
591440
  `.trim();
591441
+ TELEGRAM_CHAT_MODE_PROMPT = `
591442
+ You are Open Agents replying in Telegram quick-chat mode.
591443
+
591444
+ Rules:
591445
+ 1. Reply directly to the Telegram user, conversationally and concisely.
591446
+ 2. For public/group users, do not inspect, summarize, or expose local files, paths, secrets, tool output, or runtime internals.
591447
+ 3. For admin private DMs, quick-chat is a response style, not a capability downgrade: use the provided context and tools when needed.
591448
+ 4. For ordinary chat, status questions, greetings, quick explanations, and playful messages, answer immediately without tool-use narration.
591449
+ 5. For date/time questions, use the authoritative runtime context in this request. Do not infer dates from prior messages.
591450
+ `.trim();
591451
+ ADMIN_CHAT_PROFILE_PROMPT = `
591452
+ You are replying to the authenticated Telegram admin in a private DM.
591453
+ Quick-chat is a conversational response profile, not a restricted mode.
591454
+
591455
+ Capabilities:
591456
+ 1. You have the same admin-grade context and tools as an action run.
591457
+ 2. Use tools when they are required to answer accurately. Do not claim you lack logs, history, workspace access, or tooling if the context/tools provide a way to inspect them.
591458
+ 3. If the message is a substantial codebase task, delegate focused work with full_sub_agent or another available agent tool, then report the spawned agent/status or result.
591459
+ 4. If the message is a simple conversational question, answer directly from context without unnecessary tool use.
591460
+ 5. The final Telegram message must be the answer to send to the admin, not a meta-summary such as "answered the question".
591461
+ `.trim();
591462
+ TELEGRAM_ACTION_RESPONSE_CONTRACT = `
591463
+ Telegram response contract:
591464
+ - The final task_complete summary is the exact message that will be sent to Telegram.
591465
+ - Do not summarize the fact that you answered; send the answer itself.
591466
+ - If you delegated long-running work, include the sub-agent id/status and what the admin should expect next.
591467
+ `.trim();
591468
+ TELEGRAM_ACTION_INTENT_RE = /\b(implement|fix|patch|edit|write|create|delete|remove|refactor|run|execute|test|build|install|debug|investigate|diagnose|validate|commit|push|pull|merge|rebase|deploy|publish|read|open|inspect|grep|search|find|list|apply|change|update)\b/i;
591469
+ TELEGRAM_CODEBASE_CONTEXT_RE = /\b(repo|repository|codebase|workspace|working directory|file|files|folder|directory|src|source|test|tests|package|pnpm|npm|node|git|branch|commit|pr|pull request|issue|shell|terminal|cli|command|function|class|component|endpoint|api)\b/i;
591470
+ TELEGRAM_COMMANDISH_RE = /(^|\s)(pnpm|npm|node|git|rg|grep|sed|cat|ls|cd|mkdir|rm|mv|cp|curl|docker|pytest|vitest|tsc)\b/i;
591471
+ TELEGRAM_CHAT_INTENT_RE = /\b(hi|hello|hey|thanks|thank you|lol|haha|joke|how are you|what's up|whats up|can you hear|are you there|explain|what is|what are|why|how does|tell me|opinion|quick question)\b/i;
591309
591472
  MEDIA_CACHE_TTL_MS = 30 * 60 * 1e3;
591310
591473
  TelegramBridge = class {
591311
591474
  constructor(botToken, onMessage, agentConfig, repoRoot, toolPolicyConfig) {
@@ -591327,6 +591490,7 @@ with summary "no_reply" to silently skip without responding.
591327
591490
  active: false,
591328
591491
  botUsername: "",
591329
591492
  supportsGuestQueries: false,
591493
+ interactionMode: "auto",
591330
591494
  startedAt: "",
591331
591495
  messagesReceived: 0,
591332
591496
  messagesSent: 0,
@@ -591336,6 +591500,12 @@ with summary "no_reply" to silently skip without responding.
591336
591500
  adminUserId = null;
591337
591501
  /** Active sub-agents by chat/guest session key */
591338
591502
  subAgents = /* @__PURE__ */ new Map();
591503
+ /** Active direct chat completions, counted with Telegram activity in the TUI */
591504
+ activeChatViews = /* @__PURE__ */ new Set();
591505
+ /** Lightweight chat history by chat/guest session key */
591506
+ chatHistory = /* @__PURE__ */ new Map();
591507
+ /** Telegram interaction routing profile */
591508
+ interactionMode = "auto";
591339
591509
  /** Event handler for forwarding sub-agent events to parent TUI */
591340
591510
  onSubAgentEvent = null;
591341
591511
  /** Tool policy config — user overrides from config */
@@ -591375,6 +591545,13 @@ with summary "no_reply" to silently skip without responding.
591375
591545
  setAdmin(userId) {
591376
591546
  this.adminUserId = userId;
591377
591547
  }
591548
+ setInteractionMode(mode) {
591549
+ this.interactionMode = mode;
591550
+ this.state.interactionMode = mode;
591551
+ }
591552
+ getInteractionMode() {
591553
+ return this.interactionMode;
591554
+ }
591378
591555
  /** Update tool policy config at runtime (e.g., from /disable command) */
591379
591556
  setToolPolicyConfig(config) {
591380
591557
  this.toolPolicyConfig = config;
@@ -591418,7 +591595,7 @@ with summary "no_reply" to silently skip without responding.
591418
591595
  return this.polling;
591419
591596
  }
591420
591597
  get stats() {
591421
- return { ...this.state, activeSubAgents: this.subAgents.size };
591598
+ return { ...this.state, activeSubAgents: this.activeTelegramInteractionCount() };
591422
591599
  }
591423
591600
  get botUsername() {
591424
591601
  return this.state.botUsername;
@@ -591476,9 +591653,110 @@ with summary "no_reply" to silently skip without responding.
591476
591653
  if (msg.guestQueryId) return `guest:${msg.guestQueryId}`;
591477
591654
  return `chat:${String(msg.chatId)}`;
591478
591655
  }
591656
+ activeTelegramInteractionCount() {
591657
+ return this.subAgents.size + this.activeChatViews.size;
591658
+ }
591659
+ refreshActiveTelegramInteractionCount() {
591660
+ this.state.activeSubAgents = this.activeTelegramInteractionCount();
591661
+ }
591479
591662
  canUseChatActions(msg) {
591480
591663
  return !msg.guestQueryId && (typeof msg.chatId === "number" || String(msg.chatId).startsWith("@"));
591481
591664
  }
591665
+ recordChatHistory(sessionKey, entry) {
591666
+ const existing = this.chatHistory.get(sessionKey) ?? [];
591667
+ existing.push({ ...entry, ts: entry.ts ?? Date.now() });
591668
+ if (existing.length > 16) existing.splice(0, existing.length - 16);
591669
+ this.chatHistory.set(sessionKey, existing);
591670
+ }
591671
+ buildTelegramWorkspaceContext(modelTier, budget = 14e3) {
591672
+ if (!this.repoRoot) return "";
591673
+ try {
591674
+ const ctx3 = buildProjectContext(this.repoRoot);
591675
+ return truncateTelegramContext(formatContextForPrompt(ctx3, modelTier), budget);
591676
+ } catch (err) {
591677
+ const reason = err instanceof Error ? err.message : String(err);
591678
+ return `Workspace context unavailable: ${reason}`;
591679
+ }
591680
+ }
591681
+ buildPrimaryTuiSessionContext(telegramSessionId) {
591682
+ const primarySessionId = process.env["OA_SESSION_ID"] || process.env["OA_TUI_SESSION_ID"] || "";
591683
+ if (!primarySessionId || primarySessionId === telegramSessionId) return "";
591684
+ try {
591685
+ const todos = readTodos(primarySessionId);
591686
+ if (todos.length === 0) {
591687
+ return `Primary TUI session id: ${primarySessionId}
591688
+ No active checklist items are recorded for that session.`;
591689
+ }
591690
+ const lines = todos.slice(0, 18).map((todo) => {
591691
+ const blocker = todo.blocker ? ` - blocked: ${todo.blocker}` : "";
591692
+ return `- [${todo.status}] ${todo.content}${blocker}`;
591693
+ });
591694
+ const suffix = todos.length > lines.length ? `
591695
+ ... ${todos.length - lines.length} more item(s)` : "";
591696
+ return `Primary TUI session id: ${primarySessionId}
591697
+ Current checklist:
591698
+ ${lines.join("\n")}${suffix}`;
591699
+ } catch (err) {
591700
+ const reason = err instanceof Error ? err.message : String(err);
591701
+ return `Primary TUI session id: ${primarySessionId}
591702
+ Checklist unavailable: ${reason}`;
591703
+ }
591704
+ }
591705
+ buildTelegramSessionContext(msg, toolContext, profile, modelTier) {
591706
+ const sessionKey = this.sessionKeyForMessage(msg);
591707
+ const sessionId = telegramSessionIdFromKey(sessionKey);
591708
+ const isAdminDM = toolContext === "telegram-admin-dm";
591709
+ const isAdminGroup = toolContext === "telegram-admin-group";
591710
+ const history = formatTelegramConversationHistory(this.chatHistory.get(sessionKey) ?? [], isAdminDM ? 14 : 8);
591711
+ const chatLabel = msg.chatType !== "private" ? `Telegram group: ${msg.chatTitle || "unknown"}` : "Telegram private chat";
591712
+ const sections = [
591713
+ `## Telegram Runtime Context
591714
+
591715
+ ${buildTelegramRuntimeContext(/* @__PURE__ */ new Date(), isAdminDM ? this.repoRoot : void 0)}`,
591716
+ `## Telegram Session
591717
+
591718
+ Session key: ${sessionKey}
591719
+ Todo/session id: ${sessionId}
591720
+ Profile: ${profile}
591721
+ Tool context: ${toolContext}
591722
+ ${chatLabel}`,
591723
+ TELEGRAM_ACTION_RESPONSE_CONTRACT
591724
+ ];
591725
+ if (history) {
591726
+ sections.push(`## Recent Telegram Conversation
591727
+
591728
+ ${history}`);
591729
+ }
591730
+ if (isAdminDM) {
591731
+ sections.push(`## Admin Capability Contract
591732
+
591733
+ ${ADMIN_CHAT_PROFILE_PROMPT}`);
591734
+ const primarySessionContext = this.buildPrimaryTuiSessionContext(sessionId);
591735
+ if (primarySessionContext) sections.push(`## Primary TUI Session State
591736
+
591737
+ ${primarySessionContext}`);
591738
+ const workspaceContext = this.buildTelegramWorkspaceContext(modelTier, profile === "chat" ? 16e3 : 24e3);
591739
+ if (workspaceContext) sections.push(`## Workspace Context
591740
+
591741
+ ${workspaceContext}`);
591742
+ } else if (isAdminGroup) {
591743
+ sections.push(`## Telegram Safety Contract
591744
+
591745
+ ${ADMIN_GROUP_PROMPT}`);
591746
+ } else {
591747
+ sections.push(`## Telegram Safety Contract
591748
+
591749
+ ${TELEGRAM_SAFETY_PROMPT}`);
591750
+ }
591751
+ return { sessionKey, sessionId, context: sections.join("\n\n") };
591752
+ }
591753
+ shouldFastChatReplyInGroup(msg) {
591754
+ if (msg.chatType === "private" || msg.guestQueryId) return true;
591755
+ const lower = msg.text.toLowerCase();
591756
+ const botMention = this.state.botUsername ? lower.includes(`@${this.state.botUsername.toLowerCase()}`) : false;
591757
+ if (botMention || msg.replyToMessageId) return true;
591758
+ return /[??]/.test(msg.text) || /\b(help|question|how|what|why|when|where|can you|could you|explain)\b/i.test(msg.text);
591759
+ }
591482
591760
  async handleAdminAuthCommand(msg) {
591483
591761
  const normalized = msg.text.trim();
591484
591762
  const lower = normalized.toLowerCase();
@@ -591542,6 +591820,7 @@ with summary "no_reply" to silently skip without responding.
591542
591820
  active: true,
591543
591821
  botUsername: me.result?.username ?? "unknown",
591544
591822
  supportsGuestQueries: Boolean(me.result?.supports_guest_queries),
591823
+ interactionMode: this.interactionMode,
591545
591824
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
591546
591825
  messagesReceived: 0,
591547
591826
  messagesSent: 0,
@@ -591571,6 +591850,8 @@ with summary "no_reply" to silently skip without responding.
591571
591850
  if (agent.typingInterval) clearInterval(agent.typingInterval);
591572
591851
  }
591573
591852
  this.subAgents.clear();
591853
+ this.activeChatViews.clear();
591854
+ this.refreshActiveTelegramInteractionCount();
591574
591855
  }
591575
591856
  // ── Typing indicator ──────────────────────────────────────────────────
591576
591857
  /** Start sending "typing" indicator every 4 seconds */
@@ -591752,6 +592033,7 @@ Join: ${newUrl}`);
591752
592033
  }
591753
592034
  const existing = this.subAgents.get(sessionKey);
591754
592035
  if (existing && !existing.aborted) {
592036
+ this.recordChatHistory(sessionKey, { role: "user", text: msg.text, mode: "steering" });
591755
592037
  if (existing.runner) {
591756
592038
  existing.runner.injectUserMessage(msg.text);
591757
592039
  this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "mid-conversation steering injected"));
@@ -591761,6 +592043,14 @@ Join: ${newUrl}`);
591761
592043
  }
591762
592044
  return;
591763
592045
  }
592046
+ const route = classifyTelegramInteraction(msg.text, this.interactionMode, {
592047
+ hasMedia: !!msg.media || !!msg.poll || !!msg.livePhoto,
592048
+ isSlashCommand: msg.text.trim().startsWith("/")
592049
+ });
592050
+ if (route === "chat") {
592051
+ await this.handleTelegramChatCompletion(msg, toolContext);
592052
+ return;
592053
+ }
591764
592054
  const subAgent = {
591765
592055
  chatId: msg.chatId,
591766
592056
  username: msg.username,
@@ -591769,6 +592059,8 @@ Join: ${newUrl}`);
591769
592059
  typingInterval: null,
591770
592060
  liveMessageId: null,
591771
592061
  accumulated: "",
592062
+ assistantText: "",
592063
+ streamText: "",
591772
592064
  intermediateLines: [],
591773
592065
  lastEditMs: 0,
591774
592066
  aborted: false,
@@ -591776,7 +592068,7 @@ Join: ${newUrl}`);
591776
592068
  pendingMessages: []
591777
592069
  };
591778
592070
  this.subAgents.set(sessionKey, subAgent);
591779
- this.state.activeSubAgents = this.subAgents.size;
592071
+ this.refreshActiveTelegramInteractionCount();
591780
592072
  this.subAgentViewCallbacks?.onRegister(
591781
592073
  subAgent.viewId,
591782
592074
  `✈ @${msg.username || "telegram"}`,
@@ -591816,6 +592108,8 @@ Join: ${newUrl}`);
591816
592108
  return;
591817
592109
  }
591818
592110
  const finalText = stripTelegramHiddenThinking(result || "").trim() || "I couldn't generate a response. Please try again.";
592111
+ this.recordChatHistory(sessionKey, { role: "user", text: msg.text, mode: "action" });
592112
+ this.recordChatHistory(sessionKey, { role: "assistant", text: finalText, mode: "action" });
591819
592113
  const finalHtml = convertMarkdownToTelegramHTML(finalText);
591820
592114
  if (subAgent.liveMessageId && !msg.guestQueryId) {
591821
592115
  await this.editLiveMessage(msg.chatId, subAgent.liveMessageId, finalHtml);
@@ -591846,12 +592140,270 @@ Join: ${newUrl}`);
591846
592140
  }
591847
592141
  } finally {
591848
592142
  this.subAgents.delete(sessionKey);
591849
- this.state.activeSubAgents = this.subAgents.size;
592143
+ this.refreshActiveTelegramInteractionCount();
592144
+ this.subAgentViewCallbacks?.onComplete(subAgent.viewId);
592145
+ }
592146
+ }
592147
+ /** Admin quick-chat: conversational profile with full admin context/tools. */
592148
+ async handleTelegramAdminChatAgent(msg, toolContext) {
592149
+ const sessionKey = this.sessionKeyForMessage(msg);
592150
+ const subAgent = {
592151
+ chatId: msg.chatId,
592152
+ username: msg.username,
592153
+ viewId: `${this.viewIdForMessage(msg)}-chat`,
592154
+ runner: null,
592155
+ typingInterval: null,
592156
+ liveMessageId: null,
592157
+ accumulated: "",
592158
+ assistantText: "",
592159
+ streamText: "",
592160
+ intermediateLines: ["💬 Contextual admin chat"],
592161
+ lastEditMs: 0,
592162
+ aborted: false,
592163
+ toolContext,
592164
+ pendingMessages: []
592165
+ };
592166
+ this.subAgents.set(sessionKey, subAgent);
592167
+ this.refreshActiveTelegramInteractionCount();
592168
+ this.subAgentViewCallbacks?.onRegister(
592169
+ subAgent.viewId,
592170
+ `✈ @${msg.username || "telegram"}`,
592171
+ `Telegram admin chat: ${msg.text.slice(0, 160)}`
592172
+ );
592173
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `✈ Telegram admin chat from @${msg.username}: ${msg.text}`);
592174
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `route: chat (${this.interactionMode}) with admin tools`);
592175
+ this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "running");
592176
+ if (this.canUseChatActions(msg)) {
592177
+ subAgent.typingInterval = this.startTypingIndicator(msg.chatId);
592178
+ }
592179
+ this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, `admin chat with full context/tools (${this.interactionMode})`));
592180
+ try {
592181
+ if (!msg.guestQueryId) {
592182
+ subAgent.liveMessageId = await this.sendLiveMessage(
592183
+ msg.chatId,
592184
+ renderTelegramLiveProgressHTML(subAgent.intermediateLines, ""),
592185
+ msg.chatType !== "private" ? msg.messageId : void 0
592186
+ );
592187
+ }
592188
+ let mediaContext = "";
592189
+ if (msg.media) {
592190
+ mediaContext = await this.processMedia(msg);
592191
+ }
592192
+ const result = await this.runSubAgent(msg, subAgent, mediaContext, "chat");
592193
+ if (subAgent.typingInterval) {
592194
+ clearInterval(subAgent.typingInterval);
592195
+ subAgent.typingInterval = null;
592196
+ }
592197
+ const finalText = stripTelegramHiddenThinking(result || "").trim() || "I heard you.";
592198
+ this.recordChatHistory(sessionKey, { role: "user", text: msg.text, mode: "chat" });
592199
+ this.recordChatHistory(sessionKey, { role: "assistant", text: finalText, mode: "chat" });
592200
+ const finalHtml = convertMarkdownToTelegramHTML(finalText);
592201
+ if (subAgent.liveMessageId && !msg.guestQueryId) {
592202
+ await this.editLiveMessage(msg.chatId, subAgent.liveMessageId, finalHtml);
592203
+ } else {
592204
+ await this.replyToTelegramMessage(msg, finalHtml, {
592205
+ html: true,
592206
+ replyToMessageId: msg.chatType !== "private" ? msg.messageId : void 0
592207
+ });
592208
+ }
592209
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${finalText}`);
592210
+ this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
592211
+ } catch (err) {
592212
+ if (subAgent.typingInterval) {
592213
+ clearInterval(subAgent.typingInterval);
592214
+ subAgent.typingInterval = null;
592215
+ }
592216
+ const errMsg = err instanceof Error ? err.message : String(err);
592217
+ this.tuiWrite(() => renderTelegramSubAgentError(msg.username, errMsg));
592218
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `error: ${errMsg}`);
592219
+ this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "failed");
592220
+ if (subAgent.liveMessageId && !msg.guestQueryId) {
592221
+ await this.editLiveMessage(msg.chatId, subAgent.liveMessageId, `❌ Error: ${escapeTelegramHTML(errMsg)}`).catch(() => {
592222
+ });
592223
+ } else {
592224
+ await this.replyToTelegramMessage(msg, "Sorry, I couldn't process that Telegram chat message.").catch(() => {
592225
+ });
592226
+ }
592227
+ } finally {
592228
+ this.subAgents.delete(sessionKey);
592229
+ this.refreshActiveTelegramInteractionCount();
591850
592230
  this.subAgentViewCallbacks?.onComplete(subAgent.viewId);
591851
592231
  }
591852
592232
  }
592233
+ /** Fast Telegram chat path: direct streamed completion, no tool loop. */
592234
+ async handleTelegramChatCompletion(msg, toolContext) {
592235
+ if (toolContext === "telegram-admin-dm") {
592236
+ await this.handleTelegramAdminChatAgent(msg, toolContext);
592237
+ return;
592238
+ }
592239
+ if (!this.shouldFastChatReplyInGroup(msg)) {
592240
+ this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "chat-mode discretion: skipped group chatter"));
592241
+ return;
592242
+ }
592243
+ const sessionKey = this.sessionKeyForMessage(msg);
592244
+ const viewId = `${this.viewIdForMessage(msg)}-chat`;
592245
+ let typingInterval = null;
592246
+ let liveMessageId = null;
592247
+ let accumulated = "";
592248
+ let lastEditMs = 0;
592249
+ let lastViewWriteMs = 0;
592250
+ const progressLines = [`💬 Quick chat mode (${this.interactionMode})`];
592251
+ this.activeChatViews.add(viewId);
592252
+ this.refreshActiveTelegramInteractionCount();
592253
+ this.subAgentViewCallbacks?.onRegister(
592254
+ viewId,
592255
+ `✈ @${msg.username || "telegram"}`,
592256
+ `Telegram quick chat: ${msg.text.slice(0, 160)}`
592257
+ );
592258
+ this.subAgentViewCallbacks?.onWrite(viewId, `✈ Telegram quick chat from @${msg.username}: ${msg.text}`);
592259
+ this.subAgentViewCallbacks?.onWrite(viewId, `route: chat (${this.interactionMode})`);
592260
+ this.subAgentViewCallbacks?.onStatus(viewId, "running");
592261
+ if (this.canUseChatActions(msg)) {
592262
+ typingInterval = this.startTypingIndicator(msg.chatId);
592263
+ }
592264
+ this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, `chat-mode fast reply (${this.interactionMode})`));
592265
+ try {
592266
+ if (!msg.guestQueryId) {
592267
+ liveMessageId = await this.sendLiveMessage(
592268
+ msg.chatId,
592269
+ renderTelegramLiveProgressHTML(progressLines, ""),
592270
+ msg.chatType !== "private" ? msg.messageId : void 0
592271
+ );
592272
+ }
592273
+ const mediaContext = msg.media || msg.livePhoto ? "Attachment received. Quick-chat mode does not inspect media; use action mode for media analysis." : "";
592274
+ const finalText = await this.runTelegramChatCompletion(
592275
+ msg,
592276
+ toolContext,
592277
+ mediaContext,
592278
+ (nextText) => {
592279
+ accumulated = nextText;
592280
+ const now = Date.now();
592281
+ if (now - lastViewWriteMs > 900) {
592282
+ lastViewWriteMs = now;
592283
+ this.subAgentViewCallbacks?.onWrite(viewId, `stream: ${sanitizeTelegramProgressText(nextText, 180)}`);
592284
+ }
592285
+ if (liveMessageId && !msg.guestQueryId && now - lastEditMs > 900) {
592286
+ lastEditMs = now;
592287
+ this.editLiveMessage(
592288
+ msg.chatId,
592289
+ liveMessageId,
592290
+ renderTelegramLiveProgressHTML(progressLines, accumulated)
592291
+ ).catch(() => {
592292
+ });
592293
+ }
592294
+ }
592295
+ );
592296
+ if (typingInterval) {
592297
+ clearInterval(typingInterval);
592298
+ typingInterval = null;
592299
+ }
592300
+ const cleaned = stripTelegramHiddenThinking(finalText || accumulated).trim() || "I heard you.";
592301
+ this.recordChatHistory(sessionKey, { role: "user", text: msg.text, mode: "chat" });
592302
+ this.recordChatHistory(sessionKey, { role: "assistant", text: cleaned, mode: "chat" });
592303
+ const finalHtml = convertMarkdownToTelegramHTML(cleaned);
592304
+ if (liveMessageId && !msg.guestQueryId) {
592305
+ await this.editLiveMessage(msg.chatId, liveMessageId, finalHtml);
592306
+ } else {
592307
+ await this.replyToTelegramMessage(msg, finalHtml, {
592308
+ html: true,
592309
+ replyToMessageId: msg.chatType !== "private" ? msg.messageId : void 0
592310
+ });
592311
+ }
592312
+ this.subAgentViewCallbacks?.onWrite(viewId, `completed: ${cleaned}`);
592313
+ this.subAgentViewCallbacks?.onStatus(viewId, "completed");
592314
+ } catch (err) {
592315
+ if (typingInterval) {
592316
+ clearInterval(typingInterval);
592317
+ typingInterval = null;
592318
+ }
592319
+ const errMsg = err instanceof Error ? err.message : String(err);
592320
+ this.tuiWrite(() => renderTelegramSubAgentError(msg.username, errMsg));
592321
+ this.subAgentViewCallbacks?.onWrite(viewId, `error: ${errMsg}`);
592322
+ this.subAgentViewCallbacks?.onStatus(viewId, "failed");
592323
+ if (liveMessageId && !msg.guestQueryId) {
592324
+ await this.editLiveMessage(msg.chatId, liveMessageId, `❌ Error: ${escapeTelegramHTML(errMsg)}`).catch(() => {
592325
+ });
592326
+ } else {
592327
+ await this.replyToTelegramMessage(msg, "Sorry, I couldn't process that quick chat message.").catch(() => {
592328
+ });
592329
+ }
592330
+ } finally {
592331
+ this.activeChatViews.delete(viewId);
592332
+ this.refreshActiveTelegramInteractionCount();
592333
+ this.subAgentViewCallbacks?.onComplete(viewId);
592334
+ }
592335
+ }
592336
+ buildTelegramChatMessages(msg, toolContext, mediaContext = "") {
592337
+ const isAdminDM = toolContext === "telegram-admin-dm";
592338
+ const isAdminGroup = toolContext === "telegram-admin-group";
592339
+ const isGroup = msg.chatType !== "private";
592340
+ const sessionKey = this.sessionKeyForMessage(msg);
592341
+ const history = this.chatHistory.get(sessionKey) ?? [];
592342
+ const safety = isAdminDM ? "Admin private DM. The user is trusted, but quick-chat mode still has no tool access." : isAdminGroup ? ADMIN_GROUP_PROMPT : TELEGRAM_SAFETY_PROMPT;
592343
+ const groupHint = isGroup ? `Telegram group: ${msg.chatTitle || "unknown"}. Keep the reply short and relevant.` : "Telegram private chat.";
592344
+ const runtime = buildTelegramRuntimeContext(/* @__PURE__ */ new Date());
592345
+ const messages2 = [
592346
+ {
592347
+ role: "system",
592348
+ content: `${TELEGRAM_CHAT_MODE_PROMPT}
592349
+
592350
+ ## Runtime Context
592351
+
592352
+ ${runtime}
592353
+
592354
+ ${safety}
592355
+
592356
+ ${groupHint}`
592357
+ },
592358
+ ...history.slice(-8).map((entry) => ({
592359
+ role: entry.role,
592360
+ content: entry.text
592361
+ }))
592362
+ ];
592363
+ const chatLabel = isGroup ? ` in group "${msg.chatTitle || "unknown"}"` : "";
592364
+ messages2.push({
592365
+ role: "user",
592366
+ content: `Telegram message from @${msg.username}${chatLabel}:
592367
+ ${msg.text}${mediaContext ? `
592368
+
592369
+ ${mediaContext}` : ""}`
592370
+ });
592371
+ return messages2;
592372
+ }
592373
+ async runTelegramChatCompletion(msg, toolContext, mediaContext, onToken) {
592374
+ const config = this.agentConfig;
592375
+ const backend = new OllamaAgenticBackend(
592376
+ config.backendUrl,
592377
+ config.model,
592378
+ config.apiKey
592379
+ );
592380
+ const request = {
592381
+ messages: this.buildTelegramChatMessages(msg, toolContext, mediaContext),
592382
+ tools: [],
592383
+ temperature: 0.4,
592384
+ maxTokens: 700,
592385
+ timeoutMs: Math.min(config.timeoutMs ?? 3e4, 3e4),
592386
+ think: false
592387
+ };
592388
+ let accumulated = "";
592389
+ const streamable = backend;
592390
+ if (typeof streamable.chatCompletionStream === "function") {
592391
+ for await (const chunk of streamable.chatCompletionStream(request)) {
592392
+ if (chunk.type === "content" && !chunk.thinking && chunk.content) {
592393
+ accumulated += chunk.content;
592394
+ onToken(accumulated);
592395
+ }
592396
+ }
592397
+ }
592398
+ if (!accumulated.trim()) {
592399
+ const result = await backend.chatCompletion(request);
592400
+ accumulated = result.choices[0]?.message?.content ?? "";
592401
+ if (accumulated) onToken(accumulated);
592402
+ }
592403
+ return stripTelegramHiddenThinking(accumulated).trim();
592404
+ }
591853
592405
  /** Run a sub-agent for a Telegram message */
591854
- async runSubAgent(msg, subAgent, mediaContext = "") {
592406
+ async runSubAgent(msg, subAgent, mediaContext = "", profile = "action") {
591855
592407
  const config = this.agentConfig;
591856
592408
  const repoRoot = this.repoRoot;
591857
592409
  const modelTier = getModelTier(config.model);
@@ -591859,21 +592411,25 @@ Join: ${newUrl}`);
591859
592411
  const isAdminDM = ctx3 === "telegram-admin-dm";
591860
592412
  const isAdminGroup = ctx3 === "telegram-admin-group";
591861
592413
  const isGroup = msg.chatType !== "private";
592414
+ const sessionContext = this.buildTelegramSessionContext(msg, ctx3, profile, modelTier);
591862
592415
  const backend = new OllamaAgenticBackend(
591863
592416
  config.backendUrl,
591864
592417
  config.model,
591865
592418
  config.apiKey
591866
592419
  );
591867
592420
  const runner = new AgenticRunner(backend, {
591868
- maxTurns: isAdminDM ? 30 : isAdminGroup ? 12 : 8,
591869
- maxTokens: isAdminDM ? 8192 : 2048,
592421
+ maxTurns: isAdminDM ? profile === "chat" ? 16 : 30 : isAdminGroup ? 12 : 8,
592422
+ maxTokens: isAdminDM ? profile === "chat" ? 6144 : 8192 : 2048,
591870
592423
  temperature: 0.3,
591871
592424
  requestTimeoutMs: config.timeoutMs,
591872
592425
  taskTimeoutMs: isAdminDM ? config.timeoutMs * 3 : config.timeoutMs,
591873
592426
  compactionThreshold: modelTier === "small" ? 8e3 : 16e3,
591874
592427
  modelTier,
591875
- streamEnabled: true
592428
+ streamEnabled: true,
592429
+ dynamicContext: sessionContext.context,
592430
+ sessionId: sessionContext.sessionId
591876
592431
  });
592432
+ runner.setWorkingDirectory(repoRoot);
591877
592433
  subAgent.runner = runner;
591878
592434
  if (subAgent.pendingMessages.length > 0) {
591879
592435
  for (const queued of subAgent.pendingMessages) {
@@ -591882,7 +592438,7 @@ Join: ${newUrl}`);
591882
592438
  this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, `replayed ${subAgent.pendingMessages.length} queued message(s)`));
591883
592439
  subAgent.pendingMessages.length = 0;
591884
592440
  }
591885
- const tools = this.buildSubAgentTools(ctx3, repoRoot, msg.chatId);
592441
+ const tools = this.buildSubAgentTools(ctx3, repoRoot, msg.chatId, sessionContext.sessionId);
591886
592442
  runner.registerTools(tools);
591887
592443
  runner.onEvent((event) => {
591888
592444
  if (subAgent.aborted) return;
@@ -591895,6 +592451,10 @@ Join: ${newUrl}`);
591895
592451
  this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `${event.success ? "ok" : "fail"}: ${event.toolName}: ${preview}`);
591896
592452
  } else if (event.type === "status" && event.content) {
591897
592453
  this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `status: ${event.content}`);
592454
+ } else if (event.type === "assistant_text" && event.content) {
592455
+ subAgent.assistantText = event.content;
592456
+ } else if (event.type === "stream_end" && event.content) {
592457
+ subAgent.streamText = event.content;
591898
592458
  }
591899
592459
  if (subAgent.liveMessageId && !msg.guestQueryId) {
591900
592460
  if (event.type === "stream_token" && event.streamKind === "content" && event.content) {
@@ -591921,7 +592481,7 @@ Join: ${newUrl}`);
591921
592481
  });
591922
592482
  let systemPrompt;
591923
592483
  if (isAdminDM) {
591924
- systemPrompt = ADMIN_DM_PROMPT;
592484
+ systemPrompt = profile === "chat" ? ADMIN_CHAT_PROFILE_PROMPT : ADMIN_DM_PROMPT;
591925
592485
  } else if (isAdminGroup) {
591926
592486
  systemPrompt = ADMIN_GROUP_PROMPT;
591927
592487
  } else {
@@ -591933,7 +592493,14 @@ ${GROUP_REPLY_DISCRETION_PROMPT}` : "";
591933
592493
  const chatLabel = isGroup ? ` in group "${msg.chatTitle || "unknown"}"` : "";
591934
592494
  let userPrompt;
591935
592495
  if (isAdminDM) {
591936
- userPrompt = `Telegram message from admin @${msg.username}:
592496
+ const profileLine = profile === "chat" ? "Handle this as contextual Telegram chat: answer directly if simple, use tools/delegation if needed." : "Handle this as Telegram action work: complete the requested task or clearly report the blocker.";
592497
+ userPrompt = `${systemPrompt}
592498
+
592499
+ ${TELEGRAM_ACTION_RESPONSE_CONTRACT}
592500
+
592501
+ ${profileLine}
592502
+
592503
+ Telegram message from admin @${msg.username}:
591937
592504
  ${msg.text}`;
591938
592505
  } else {
591939
592506
  const toolHint = "You have access to isolated per-chat memory (memory_write, memory_read, memory_search) scoped to this conversation. You can remember facts about this user and retrieve them later. You also have web_search and web_fetch to look up information.";
@@ -591955,22 +592522,29 @@ Respond concisely and safely.`;
591955
592522
  ${mediaContext}`;
591956
592523
  }
591957
592524
  const systemCtx = isAdminDM ? `Working directory: ${repoRoot}
591958
- Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} chat. Respond concisely. Safety filter: ACTIVE.`;
592525
+ Telegram admin: @${msg.username}
592526
+ Telegram profile: ${profile}
592527
+ Todo/session id: ${sessionContext.sessionId}` : `Telegram ${isGroup ? "group" : "public"} chat. Respond concisely. Safety filter: ACTIVE.`;
591959
592528
  const result = await runner.run(userPrompt, systemCtx);
591960
- return result.summary || subAgent.accumulated || "";
592529
+ return selectTelegramFinalResponse({
592530
+ assistantText: subAgent.assistantText,
592531
+ streamText: subAgent.streamText,
592532
+ accumulated: subAgent.accumulated,
592533
+ summary: result.summary
592534
+ });
591961
592535
  }
591962
592536
  /**
591963
592537
  * Build tool set based on tool context, filtered through the policy system.
591964
592538
  * All possible tools are instantiated, then applyToolPolicy filters them.
591965
592539
  */
591966
- buildSubAgentTools(context2, repoRoot, chatId) {
592540
+ buildSubAgentTools(context2, repoRoot, chatId, todoSessionId) {
591967
592541
  const taskComplete = {
591968
592542
  name: "task_complete",
591969
- description: "Signal that your response is ready to send to the Telegram user. Use summary 'no_reply' to silently skip responding.",
592543
+ description: "Signal that your response is ready to send to the Telegram user. The summary must be the exact final Telegram message, not a meta-summary. Use summary 'no_reply' to silently skip responding.",
591970
592544
  parameters: {
591971
592545
  type: "object",
591972
592546
  properties: {
591973
- summary: { type: "string", description: "The response to send to the Telegram user, or 'no_reply' to skip" }
592547
+ summary: { type: "string", description: "Exact response to send to the Telegram user, or 'no_reply' to skip" }
591974
592548
  },
591975
592549
  required: ["summary"]
591976
592550
  },
@@ -591978,7 +592552,21 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
591978
592552
  return { success: true, output: args["summary"] || "Done." };
591979
592553
  }
591980
592554
  };
591981
- const allTools = [
592555
+ const fullSubAgentTool = new FullSubAgentTool(
592556
+ repoRoot,
592557
+ this.agentConfig?.model,
592558
+ this.agentConfig?.backendUrl,
592559
+ {
592560
+ onViewRegister: (id, label) => this.subAgentViewCallbacks?.onRegister(id, `✈ ${label}`, "Telegram delegated full sub-agent"),
592561
+ onViewWrite: (id, text) => this.subAgentViewCallbacks?.onWrite(id, text),
592562
+ onViewStatus: (id, status) => {
592563
+ if (status === "completed" || status === "failed" || status === "running") {
592564
+ this.subAgentViewCallbacks?.onStatus(id, status);
592565
+ }
592566
+ }
592567
+ }
592568
+ );
592569
+ const sharedReadMemoryWebTools = [
591982
592570
  // File tools
591983
592571
  new FileReadTool(repoRoot),
591984
592572
  new GrepSearchTool(repoRoot),
@@ -591988,6 +592576,8 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
591988
592576
  new MemoryReadTool(repoRoot),
591989
592577
  new MemoryWriteTool(repoRoot),
591990
592578
  new MemorySearchTool(repoRoot),
592579
+ new TodoReadTool(),
592580
+ new TodoWriteTool(),
591991
592581
  // Web tools
591992
592582
  new WebFetchTool(),
591993
592583
  new WebSearchTool(),
@@ -592002,7 +592592,62 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
592002
592592
  new TranscribeFileTool(repoRoot),
592003
592593
  new TranscribeUrlTool(repoRoot)
592004
592594
  ];
592005
- let adaptedTools = allTools.map(adaptTool5);
592595
+ const adminTools = [
592596
+ new ShellTool(repoRoot),
592597
+ new FileReadTool(repoRoot),
592598
+ new FileWriteTool(repoRoot),
592599
+ new FileEditTool(repoRoot),
592600
+ new FilePatchTool(repoRoot),
592601
+ new BatchEditTool(repoRoot),
592602
+ new GrepSearchTool(repoRoot),
592603
+ new GlobFindTool(repoRoot),
592604
+ new ListDirectoryTool(repoRoot),
592605
+ new SessionSearchTool(repoRoot),
592606
+ new ExploreToolsTool(),
592607
+ new CodebaseMapTool(repoRoot),
592608
+ new DiagnosticTool(repoRoot),
592609
+ new GitInfoTool(repoRoot),
592610
+ new PhaseRecallTool(repoRoot),
592611
+ new LogExploreTool(repoRoot),
592612
+ new FileExploreTool(repoRoot),
592613
+ new WorkingNotesTool(),
592614
+ new ProjectScaffoldingTool(),
592615
+ new TodoReadTool(),
592616
+ new TodoWriteTool(),
592617
+ new MemoryReadTool(repoRoot),
592618
+ new MemoryWriteTool(repoRoot),
592619
+ new MemorySearchTool(repoRoot),
592620
+ new WebFetchTool(),
592621
+ new WebSearchTool(),
592622
+ new WebCrawlTool(repoRoot),
592623
+ new StructuredReadTool(repoRoot),
592624
+ new StructuredFileTool(repoRoot),
592625
+ new CodeSandboxTool(repoRoot),
592626
+ new ImageReadTool(repoRoot),
592627
+ new ScreenshotTool(repoRoot),
592628
+ new OCRTool(repoRoot),
592629
+ new OcrImageAdvancedTool(repoRoot),
592630
+ new VisionTool(repoRoot),
592631
+ new OcrPdfTool(repoRoot),
592632
+ new PdfToTextTool(repoRoot),
592633
+ new TranscribeFileTool(repoRoot),
592634
+ new TranscribeUrlTool(repoRoot),
592635
+ new YouTubeDownloadTool(repoRoot),
592636
+ new BrowserActionTool(),
592637
+ new CarbonylBrowserTool(),
592638
+ new PlaywrightBrowserTool(),
592639
+ new ImageGenerateTool(repoRoot, this.agentConfig?.backendUrl),
592640
+ new NotebookEditTool(),
592641
+ new RepoMapTool(repoRoot),
592642
+ new ImportGraphTool(repoRoot),
592643
+ new SymbolSearchTool(repoRoot),
592644
+ new ImpactAnalysisTool(repoRoot),
592645
+ new CodeNeighborsTool(repoRoot),
592646
+ new ProcessHealthTool(),
592647
+ fullSubAgentTool
592648
+ ];
592649
+ const allTools = context2 === "telegram-admin-dm" ? adminTools : sharedReadMemoryWebTools;
592650
+ let adaptedTools = allTools.map((tool) => adaptTool5(tool, todoSessionId));
592006
592651
  adaptedTools = applyToolPolicy(adaptedTools, context2, this.toolPolicyConfig);
592007
592652
  if (context2 !== "telegram-admin-dm") {
592008
592653
  const memWriteIdx = adaptedTools.findIndex((t2) => t2.name === "memory_write");
@@ -622073,6 +622718,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
622073
622718
  currentConfig,
622074
622719
  repoRoot
622075
622720
  );
622721
+ telegramBridge.setInteractionMode(savedSettings.telegramMode ?? "auto");
622076
622722
  if (adminId) {
622077
622723
  telegramBridge.setAdmin(adminId);
622078
622724
  }
@@ -622185,7 +622831,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
622185
622831
  );
622186
622832
  });
622187
622833
  writeContent(
622188
- () => renderTelegramStart(telegramBridge.botUsername, adminId)
622834
+ () => renderTelegramStart(telegramBridge.botUsername, adminId, savedSettings.telegramMode ?? "auto")
622189
622835
  );
622190
622836
  showPrompt();
622191
622837
  },
@@ -622204,7 +622850,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
622204
622850
  getTelegramSettings() {
622205
622851
  return {
622206
622852
  key: savedSettings.telegramKey,
622207
- admin: savedSettings.telegramAdmin
622853
+ admin: savedSettings.telegramAdmin,
622854
+ mode: savedSettings.telegramMode
622208
622855
  };
622209
622856
  },
622210
622857
  saveTelegramSettings(settings) {
@@ -622214,9 +622861,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
622214
622861
  if (settings.admin !== void 0) {
622215
622862
  savedSettings.telegramAdmin = settings.admin;
622216
622863
  }
622864
+ if (settings.mode !== void 0) {
622865
+ savedSettings.telegramMode = settings.mode;
622866
+ }
622217
622867
  const payload = {
622218
622868
  ...settings.key !== void 0 ? { telegramKey: settings.key } : {},
622219
- ...settings.admin !== void 0 ? { telegramAdmin: settings.admin } : {}
622869
+ ...settings.admin !== void 0 ? { telegramAdmin: settings.admin } : {},
622870
+ ...settings.mode !== void 0 ? { telegramMode: settings.mode } : {}
622220
622871
  };
622221
622872
  if (settings.local) {
622222
622873
  saveProjectSettings(repoRoot, payload);
@@ -622224,6 +622875,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
622224
622875
  saveGlobalSettings(payload);
622225
622876
  }
622226
622877
  },
622878
+ telegramSetInteractionMode(mode) {
622879
+ savedSettings.telegramMode = mode;
622880
+ telegramBridge?.setInteractionMode(mode);
622881
+ },
622227
622882
  telegramStatus() {
622228
622883
  const active = telegramBridge?.isActive ?? false;
622229
622884
  const botUser = active ? telegramBridge?.botUsername : void 0;
@@ -622233,7 +622888,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
622233
622888
  active,
622234
622889
  botUser,
622235
622890
  savedSettings.telegramAdmin,
622236
- subAgents
622891
+ subAgents,
622892
+ savedSettings.telegramMode ?? "auto"
622237
622893
  )
622238
622894
  );
622239
622895
  },
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.583",
3
+ "version": "0.187.585",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.583",
9
+ "version": "0.187.585",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.583",
3
+ "version": "0.187.585",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",