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 +15 -4
- package/dist/index.js +693 -37
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
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.
|
|
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
|
|
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
|
|
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"] ||
|
|
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"] ||
|
|
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"] ||
|
|
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
|
|
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-
|
|
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(
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -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
|
|
591136
|
-
|
|
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(
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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}
|
|
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
|
|
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: "
|
|
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
|
|
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
|
-
|
|
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
|
},
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-agents-ai",
|
|
3
|
-
"version": "0.187.
|
|
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.
|
|
9
|
+
"version": "0.187.585",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "CC-BY-NC-4.0",
|
|
12
12
|
"dependencies": {
|
package/package.json
CHANGED