open-agents-ai 0.187.584 → 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/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 "";
@@ -590819,7 +590820,7 @@ function getDefaultPolicy(context2) {
590819
590820
  case "terminal":
590820
590821
  return { blocked: /* @__PURE__ */ new Set(), allowed: /* @__PURE__ */ new Set() };
590821
590822
  case "telegram-admin-dm":
590822
- return { blocked: /* @__PURE__ */ new Set(["shell"]), allowed: /* @__PURE__ */ new Set() };
590823
+ return { blocked: /* @__PURE__ */ new Set(), allowed: /* @__PURE__ */ new Set() };
590823
590824
  case "telegram-admin-group":
590824
590825
  return { blocked: /* @__PURE__ */ new Set(), allowed: SAFE_GROUP_ADMIN_TOOLS };
590825
590826
  case "telegram-public":
@@ -590866,6 +590867,8 @@ var init_tool_policy = __esm({
590866
590867
  "memory_read",
590867
590868
  "memory_write",
590868
590869
  "memory_search",
590870
+ "todo_read",
590871
+ "todo_write",
590869
590872
  "web_search",
590870
590873
  "web_fetch",
590871
590874
  "task_complete"
@@ -590874,6 +590877,8 @@ var init_tool_policy = __esm({
590874
590877
  "memory_read",
590875
590878
  "memory_write",
590876
590879
  "memory_search",
590880
+ "todo_read",
590881
+ "todo_write",
590877
590882
  "web_search",
590878
590883
  "web_fetch",
590879
590884
  "web_crawl",
@@ -590945,6 +590950,60 @@ function sanitizeTelegramProgressText(text, maxLength) {
590945
590950
  const compact = stripTelegramHiddenThinking(text).replace(/\s+/g, " ").trim();
590946
590951
  return compact.length > maxLength ? compact.slice(0, Math.max(0, maxLength - 3)) + "..." : compact;
590947
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
+ }
590948
591007
  function formatTelegramProgressEvent(event) {
590949
591008
  if (event.type === "tool_call" && event.toolName === "task_complete") return null;
590950
591009
  if (event.type === "tool_result" && event.toolName === "task_complete") return null;
@@ -591185,14 +591244,24 @@ function normalizeTelegramUpdate(update2) {
591185
591244
  sourceUpdateType
591186
591245
  };
591187
591246
  }
591188
- function adaptTool5(tool) {
591247
+ function adaptTool5(tool, todoSessionId) {
591189
591248
  return {
591190
591249
  name: tool.name,
591191
591250
  description: tool.description,
591192
591251
  parameters: tool.parameters,
591193
591252
  async execute(args) {
591194
- const result = await tool.execute(args);
591195
- 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
+ }
591196
591265
  }
591197
591266
  };
591198
591267
  }
@@ -591309,7 +591378,7 @@ function renderTelegramSubAgentError(username, error) {
591309
591378
  process.stdout.write(` ${c3.dim("⎿")} ${c3.red("✘")} @${username}: ${c3.dim(preview)}
591310
591379
  `);
591311
591380
  }
591312
- var TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, TELEGRAM_ACTION_INTENT_RE, TELEGRAM_CODEBASE_CONTEXT_RE, TELEGRAM_COMMANDISH_RE, TELEGRAM_CHAT_INTENT_RE, 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;
591313
591382
  var init_telegram_bridge = __esm({
591314
591383
  "packages/cli/src/tui/telegram-bridge.ts"() {
591315
591384
  "use strict";
@@ -591374,10 +591443,27 @@ You are Open Agents replying in Telegram quick-chat mode.
591374
591443
 
591375
591444
  Rules:
591376
591445
  1. Reply directly to the Telegram user, conversationally and concisely.
591377
- 2. Do not inspect, summarize, or expose local files, paths, secrets, tool output, or runtime internals.
591378
- 3. Do not claim that you changed code, ran commands, or checked the workspace in quick-chat mode.
591379
- 4. If the user asks for codebase action while quick-chat mode is forced, tell them to switch Telegram to action mode or send a concrete action request in auto mode.
591380
- 5. For ordinary chat, status questions, greetings, quick explanations, and playful messages, answer immediately without tool-use narration.
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.
591381
591467
  `.trim();
591382
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;
591383
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;
@@ -591578,10 +591664,92 @@ Rules:
591578
591664
  }
591579
591665
  recordChatHistory(sessionKey, entry) {
591580
591666
  const existing = this.chatHistory.get(sessionKey) ?? [];
591581
- existing.push(entry);
591667
+ existing.push({ ...entry, ts: entry.ts ?? Date.now() });
591582
591668
  if (existing.length > 16) existing.splice(0, existing.length - 16);
591583
591669
  this.chatHistory.set(sessionKey, existing);
591584
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
+ }
591585
591753
  shouldFastChatReplyInGroup(msg) {
591586
591754
  if (msg.chatType === "private" || msg.guestQueryId) return true;
591587
591755
  const lower = msg.text.toLowerCase();
@@ -591865,6 +592033,7 @@ Join: ${newUrl}`);
591865
592033
  }
591866
592034
  const existing = this.subAgents.get(sessionKey);
591867
592035
  if (existing && !existing.aborted) {
592036
+ this.recordChatHistory(sessionKey, { role: "user", text: msg.text, mode: "steering" });
591868
592037
  if (existing.runner) {
591869
592038
  existing.runner.injectUserMessage(msg.text);
591870
592039
  this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "mid-conversation steering injected"));
@@ -591890,6 +592059,8 @@ Join: ${newUrl}`);
591890
592059
  typingInterval: null,
591891
592060
  liveMessageId: null,
591892
592061
  accumulated: "",
592062
+ assistantText: "",
592063
+ streamText: "",
591893
592064
  intermediateLines: [],
591894
592065
  lastEditMs: 0,
591895
592066
  aborted: false,
@@ -591937,6 +592108,8 @@ Join: ${newUrl}`);
591937
592108
  return;
591938
592109
  }
591939
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" });
591940
592113
  const finalHtml = convertMarkdownToTelegramHTML(finalText);
591941
592114
  if (subAgent.liveMessageId && !msg.guestQueryId) {
591942
592115
  await this.editLiveMessage(msg.chatId, subAgent.liveMessageId, finalHtml);
@@ -591971,8 +592144,98 @@ Join: ${newUrl}`);
591971
592144
  this.subAgentViewCallbacks?.onComplete(subAgent.viewId);
591972
592145
  }
591973
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();
592230
+ this.subAgentViewCallbacks?.onComplete(subAgent.viewId);
592231
+ }
592232
+ }
591974
592233
  /** Fast Telegram chat path: direct streamed completion, no tool loop. */
591975
592234
  async handleTelegramChatCompletion(msg, toolContext) {
592235
+ if (toolContext === "telegram-admin-dm") {
592236
+ await this.handleTelegramAdminChatAgent(msg, toolContext);
592237
+ return;
592238
+ }
591976
592239
  if (!this.shouldFastChatReplyInGroup(msg)) {
591977
592240
  this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "chat-mode discretion: skipped group chatter"));
591978
592241
  return;
@@ -592035,8 +592298,8 @@ Join: ${newUrl}`);
592035
592298
  typingInterval = null;
592036
592299
  }
592037
592300
  const cleaned = stripTelegramHiddenThinking(finalText || accumulated).trim() || "I heard you.";
592038
- this.recordChatHistory(sessionKey, { role: "user", text: msg.text });
592039
- this.recordChatHistory(sessionKey, { role: "assistant", text: cleaned });
592301
+ this.recordChatHistory(sessionKey, { role: "user", text: msg.text, mode: "chat" });
592302
+ this.recordChatHistory(sessionKey, { role: "assistant", text: cleaned, mode: "chat" });
592040
592303
  const finalHtml = convertMarkdownToTelegramHTML(cleaned);
592041
592304
  if (liveMessageId && !msg.guestQueryId) {
592042
592305
  await this.editLiveMessage(msg.chatId, liveMessageId, finalHtml);
@@ -592078,11 +592341,16 @@ Join: ${newUrl}`);
592078
592341
  const history = this.chatHistory.get(sessionKey) ?? [];
592079
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;
592080
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());
592081
592345
  const messages2 = [
592082
592346
  {
592083
592347
  role: "system",
592084
592348
  content: `${TELEGRAM_CHAT_MODE_PROMPT}
592085
592349
 
592350
+ ## Runtime Context
592351
+
592352
+ ${runtime}
592353
+
592086
592354
  ${safety}
592087
592355
 
592088
592356
  ${groupHint}`
@@ -592135,7 +592403,7 @@ ${mediaContext}` : ""}`
592135
592403
  return stripTelegramHiddenThinking(accumulated).trim();
592136
592404
  }
592137
592405
  /** Run a sub-agent for a Telegram message */
592138
- async runSubAgent(msg, subAgent, mediaContext = "") {
592406
+ async runSubAgent(msg, subAgent, mediaContext = "", profile = "action") {
592139
592407
  const config = this.agentConfig;
592140
592408
  const repoRoot = this.repoRoot;
592141
592409
  const modelTier = getModelTier(config.model);
@@ -592143,21 +592411,25 @@ ${mediaContext}` : ""}`
592143
592411
  const isAdminDM = ctx3 === "telegram-admin-dm";
592144
592412
  const isAdminGroup = ctx3 === "telegram-admin-group";
592145
592413
  const isGroup = msg.chatType !== "private";
592414
+ const sessionContext = this.buildTelegramSessionContext(msg, ctx3, profile, modelTier);
592146
592415
  const backend = new OllamaAgenticBackend(
592147
592416
  config.backendUrl,
592148
592417
  config.model,
592149
592418
  config.apiKey
592150
592419
  );
592151
592420
  const runner = new AgenticRunner(backend, {
592152
- maxTurns: isAdminDM ? 30 : isAdminGroup ? 12 : 8,
592153
- maxTokens: isAdminDM ? 8192 : 2048,
592421
+ maxTurns: isAdminDM ? profile === "chat" ? 16 : 30 : isAdminGroup ? 12 : 8,
592422
+ maxTokens: isAdminDM ? profile === "chat" ? 6144 : 8192 : 2048,
592154
592423
  temperature: 0.3,
592155
592424
  requestTimeoutMs: config.timeoutMs,
592156
592425
  taskTimeoutMs: isAdminDM ? config.timeoutMs * 3 : config.timeoutMs,
592157
592426
  compactionThreshold: modelTier === "small" ? 8e3 : 16e3,
592158
592427
  modelTier,
592159
- streamEnabled: true
592428
+ streamEnabled: true,
592429
+ dynamicContext: sessionContext.context,
592430
+ sessionId: sessionContext.sessionId
592160
592431
  });
592432
+ runner.setWorkingDirectory(repoRoot);
592161
592433
  subAgent.runner = runner;
592162
592434
  if (subAgent.pendingMessages.length > 0) {
592163
592435
  for (const queued of subAgent.pendingMessages) {
@@ -592166,7 +592438,7 @@ ${mediaContext}` : ""}`
592166
592438
  this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, `replayed ${subAgent.pendingMessages.length} queued message(s)`));
592167
592439
  subAgent.pendingMessages.length = 0;
592168
592440
  }
592169
- const tools = this.buildSubAgentTools(ctx3, repoRoot, msg.chatId);
592441
+ const tools = this.buildSubAgentTools(ctx3, repoRoot, msg.chatId, sessionContext.sessionId);
592170
592442
  runner.registerTools(tools);
592171
592443
  runner.onEvent((event) => {
592172
592444
  if (subAgent.aborted) return;
@@ -592179,6 +592451,10 @@ ${mediaContext}` : ""}`
592179
592451
  this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `${event.success ? "ok" : "fail"}: ${event.toolName}: ${preview}`);
592180
592452
  } else if (event.type === "status" && event.content) {
592181
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;
592182
592458
  }
592183
592459
  if (subAgent.liveMessageId && !msg.guestQueryId) {
592184
592460
  if (event.type === "stream_token" && event.streamKind === "content" && event.content) {
@@ -592205,7 +592481,7 @@ ${mediaContext}` : ""}`
592205
592481
  });
592206
592482
  let systemPrompt;
592207
592483
  if (isAdminDM) {
592208
- systemPrompt = ADMIN_DM_PROMPT;
592484
+ systemPrompt = profile === "chat" ? ADMIN_CHAT_PROFILE_PROMPT : ADMIN_DM_PROMPT;
592209
592485
  } else if (isAdminGroup) {
592210
592486
  systemPrompt = ADMIN_GROUP_PROMPT;
592211
592487
  } else {
@@ -592217,7 +592493,14 @@ ${GROUP_REPLY_DISCRETION_PROMPT}` : "";
592217
592493
  const chatLabel = isGroup ? ` in group "${msg.chatTitle || "unknown"}"` : "";
592218
592494
  let userPrompt;
592219
592495
  if (isAdminDM) {
592220
- 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}:
592221
592504
  ${msg.text}`;
592222
592505
  } else {
592223
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.";
@@ -592239,22 +592522,29 @@ Respond concisely and safely.`;
592239
592522
  ${mediaContext}`;
592240
592523
  }
592241
592524
  const systemCtx = isAdminDM ? `Working directory: ${repoRoot}
592242
- 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.`;
592243
592528
  const result = await runner.run(userPrompt, systemCtx);
592244
- 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
+ });
592245
592535
  }
592246
592536
  /**
592247
592537
  * Build tool set based on tool context, filtered through the policy system.
592248
592538
  * All possible tools are instantiated, then applyToolPolicy filters them.
592249
592539
  */
592250
- buildSubAgentTools(context2, repoRoot, chatId) {
592540
+ buildSubAgentTools(context2, repoRoot, chatId, todoSessionId) {
592251
592541
  const taskComplete = {
592252
592542
  name: "task_complete",
592253
- 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.",
592254
592544
  parameters: {
592255
592545
  type: "object",
592256
592546
  properties: {
592257
- 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" }
592258
592548
  },
592259
592549
  required: ["summary"]
592260
592550
  },
@@ -592262,7 +592552,21 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
592262
592552
  return { success: true, output: args["summary"] || "Done." };
592263
592553
  }
592264
592554
  };
592265
- 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 = [
592266
592570
  // File tools
592267
592571
  new FileReadTool(repoRoot),
592268
592572
  new GrepSearchTool(repoRoot),
@@ -592272,6 +592576,8 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
592272
592576
  new MemoryReadTool(repoRoot),
592273
592577
  new MemoryWriteTool(repoRoot),
592274
592578
  new MemorySearchTool(repoRoot),
592579
+ new TodoReadTool(),
592580
+ new TodoWriteTool(),
592275
592581
  // Web tools
592276
592582
  new WebFetchTool(),
592277
592583
  new WebSearchTool(),
@@ -592286,7 +592592,62 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
592286
592592
  new TranscribeFileTool(repoRoot),
592287
592593
  new TranscribeUrlTool(repoRoot)
592288
592594
  ];
592289
- 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));
592290
592651
  adaptedTools = applyToolPolicy(adaptedTools, context2, this.toolPolicyConfig);
592291
592652
  if (context2 !== "telegram-admin-dm") {
592292
592653
  const memWriteIdx = adaptedTools.findIndex((t2) => t2.name === "memory_write");
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.584",
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.584",
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.584",
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",