switchroom 0.16.47 → 0.17.0
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/agent-scheduler/index.js +3 -1
- package/dist/auth-broker/index.js +24 -8
- package/dist/cli/drive-write-pretool.mjs +0 -5
- package/dist/cli/notion-write-pretool.mjs +3 -1
- package/dist/cli/switchroom.js +1358 -1030
- package/dist/cli/ui/index.html +84 -12
- package/dist/host-control/main.js +53 -17
- package/dist/vault/approvals/kernel-server.js +4 -1
- package/dist/vault/broker/server.js +201 -56
- package/package.json +3 -3
- package/profiles/_base/cron-session.sh.hbs +1 -1
- package/profiles/_base/start.sh.hbs +54 -3
- package/skills/switchroom-architecture/telegram.md +8 -15
- package/skills/switchroom-cli/SKILL.md +4 -5
- package/skills/telegram-test-harness/SKILL.md +1 -1
- package/telegram-plugin/README.md +18 -29
- package/telegram-plugin/bridge/bridge.ts +1 -41
- package/telegram-plugin/bridge/tool-filter.ts +3 -4
- package/telegram-plugin/dist/bridge/bridge.js +8 -43
- package/telegram-plugin/dist/gateway/gateway.js +682 -773
- package/telegram-plugin/dist/server.js +8 -43
- package/telegram-plugin/gateway/busy-key-reaper.ts +113 -0
- package/telegram-plugin/gateway/disconnect-flush.ts +11 -0
- package/telegram-plugin/gateway/escalation-bridge-gate.ts +46 -0
- package/telegram-plugin/gateway/gate-parity-probe.ts +102 -0
- package/telegram-plugin/gateway/gateway.ts +518 -624
- package/telegram-plugin/gateway/inbound-delivery-confirm.ts +89 -7
- package/telegram-plugin/gateway/inbound-spool.ts +108 -10
- package/telegram-plugin/gateway/model-command.ts +51 -3
- package/telegram-plugin/gateway/pending-inbound-buffer.ts +26 -0
- package/telegram-plugin/gateway/represent-guard.ts +28 -11
- package/telegram-plugin/gateway/status-pin-store.ts +124 -45
- package/telegram-plugin/gateway/worker-feed-dispatch.ts +19 -0
- package/telegram-plugin/history.ts +5 -0
- package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +1 -2
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +9 -1
- package/telegram-plugin/registry/subagents-schema.ts +126 -1
- package/telegram-plugin/registry/turns-schema.ts +65 -1
- package/telegram-plugin/session-tail.ts +26 -4
- package/telegram-plugin/slot-banner-driver.ts +42 -2
- package/telegram-plugin/status-query-telemetry.ts +100 -0
- package/telegram-plugin/stream-reply-handler.ts +15 -16
- package/telegram-plugin/subagent-watcher.ts +182 -30
- package/telegram-plugin/tests/buffer-gate-broadened.test.ts +4 -10
- package/telegram-plugin/tests/busy-key-reaper.test.ts +191 -0
- package/telegram-plugin/tests/emission-authority-facade.test.ts +11 -17
- package/telegram-plugin/tests/emission-determinism-wiring.test.ts +5 -26
- package/telegram-plugin/tests/escalation-bridge-gate.test.ts +38 -0
- package/telegram-plugin/tests/gate-parity-probe.test.ts +171 -0
- package/telegram-plugin/tests/gateway-disconnect-flush.test.ts +13 -0
- package/telegram-plugin/tests/gateway-outbound-redact.test.ts +14 -11
- package/telegram-plugin/tests/inbound-delivery-confirm.test.ts +146 -0
- package/telegram-plugin/tests/inbound-spool.test.ts +143 -0
- package/telegram-plugin/tests/model-command.test.ts +54 -1
- package/telegram-plugin/tests/multitopic-routing-wiring.test.ts +5 -11
- package/telegram-plugin/tests/nested-worker-visibility-harness.test.ts +329 -0
- package/telegram-plugin/tests/pending-inbound-buffer.test.ts +53 -0
- package/telegram-plugin/tests/progress-update-redact.test.ts +99 -0
- package/telegram-plugin/tests/registry-turns.test.ts +67 -0
- package/telegram-plugin/tests/represent-guard.test.ts +42 -6
- package/telegram-plugin/tests/resume-inbound-builder.test.ts +1 -0
- package/telegram-plugin/tests/session-tail.test.ts +10 -1
- package/telegram-plugin/tests/slot-banner-boot-recovery.test.ts +246 -0
- package/telegram-plugin/tests/status-pin-boot-recovery.test.ts +0 -14
- package/telegram-plugin/tests/status-pin-store.test.ts +220 -5
- package/telegram-plugin/tests/status-query-telemetry.test.ts +115 -0
- package/telegram-plugin/tests/subagent-nested-dispatch.test.ts +209 -0
- package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +37 -0
- package/telegram-plugin/tests/subagent-watcher-boot-promotion-replay.test.ts +167 -0
- package/telegram-plugin/tests/subagent-watcher-env-thresholds.test.ts +46 -3
- package/telegram-plugin/tests/subagent-watcher-stall-notification.test.ts +70 -0
- package/telegram-plugin/tests/tool-activity-summary.test.ts +16 -0
- package/telegram-plugin/tests/tool-filter.test.ts +1 -3
- package/telegram-plugin/tests/tool-label-pretool.test.ts +1 -4
- package/telegram-plugin/tests/turn-flush-safety.test.ts +222 -1
- package/telegram-plugin/tests/worker-activity-feed.test.ts +202 -9
- package/telegram-plugin/tests/worker-feed-dispatch.test.ts +25 -0
- package/telegram-plugin/tests/worker-visibility-prose-silent-harness.test.ts +295 -0
- package/telegram-plugin/tool-activity-summary.ts +19 -0
- package/telegram-plugin/turn-flush-safety.ts +16 -1
- package/telegram-plugin/uat/scenarios/jtbd-answer-pings.test.ts +8 -9
- package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-visibility-dm.test.ts +1 -1
- package/telegram-plugin/uat/scenarios/jtbd-narration-intent-dm.test.ts +1 -1
- package/telegram-plugin/worker-activity-feed.ts +75 -15
- package/vendor/hindsight-memory/CHANGELOG.md +24 -0
- package/vendor/hindsight-memory/README.md +5 -0
- package/vendor/hindsight-memory/scripts/lib/client.py +31 -1
- package/vendor/hindsight-memory/scripts/lib/config.py +41 -2
- package/vendor/hindsight-memory/scripts/lib/content.py +4 -1
- package/vendor/hindsight-memory/scripts/lib/daemon.py +11 -2
- package/vendor/hindsight-memory/scripts/recall.py +74 -1
- package/vendor/hindsight-memory/scripts/retain.py +8 -1
- package/vendor/hindsight-memory/scripts/tests/test_config_client_casts.py +111 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_integration.py +85 -1
- package/vendor/hindsight-memory/scripts/tests/test_recall_tag_filters.py +107 -0
- package/vendor/hindsight-memory/settings.json +4 -0
- package/vendor/hindsight-memory/tests/test_client.py +130 -0
- package/vendor/hindsight-memory/tests/test_config.py +47 -0
- package/vendor/hindsight-memory/tests/test_content.py +18 -0
- package/vendor/hindsight-memory/tests/test_hooks.py +62 -0
- package/telegram-plugin/gateway/error-envelope-card.ts +0 -64
- package/telegram-plugin/gateway/resolve-calling-subagent.ts +0 -78
- package/telegram-plugin/silent-reply.ts +0 -58
- package/telegram-plugin/tests/error-envelope-unlock-card.test.ts +0 -79
- package/telegram-plugin/tests/resolve-calling-subagent.test.ts +0 -269
- package/telegram-plugin/tests/silent-reply-guard.test.ts +0 -122
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Switchroom ships an enhanced `switchroom-telegram` MCP plugin that replaces the official marketplace plugin. It is the default — no configuration needed.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 9 MCP tools
|
|
6
6
|
|
|
7
7
|
| Tool | What it does |
|
|
8
8
|
|------|-------------|
|
|
9
|
-
| `reply` | Send text, photos, or documents. Supports threading, topic routing, file attachments. |
|
|
10
|
-
| `stream_reply` | Edit a single message in place as work progresses (~1/sec throttle). Use for long tasks to avoid chat spam. |
|
|
9
|
+
| `reply` | Send text, photos, or documents — the single final-answer tool. Chunks anything over Telegram's 4096-char limit. Supports threading, topic routing, file attachments. |
|
|
11
10
|
| `react` | Add emoji reactions to messages (Telegram whitelist: 👍 👎 ❤️ 🔥 👀 🎉 etc). |
|
|
12
11
|
| `edit_message` | Update a previously sent message. Edits are silent (no push notification). |
|
|
13
12
|
| `delete_message` | Remove a bot-sent message (48h Telegram API limit). |
|
|
@@ -37,19 +36,13 @@ A local SQLite database (`telegram/history.db`) records every message. After a C
|
|
|
37
36
|
|
|
38
37
|
History survives process restarts and session resets.
|
|
39
38
|
|
|
40
|
-
##
|
|
39
|
+
## Progress while working
|
|
41
40
|
|
|
42
|
-
For tasks
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
3. stream_reply(chat_id, "Done! Here's the result: ...", done=true) ← locks
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Pass the **full current text** on each call (not a delta). The plugin throttles to ~1/sec.
|
|
51
|
-
|
|
52
|
-
After `done=true`, send a separate `reply` if you want a push notification to the user's device (edits are silent).
|
|
41
|
+
For long tasks you do not need to narrate progress by editing a message. The
|
|
42
|
+
plugin renders an event-driven progress card (Plan → Run → Done with live tool
|
|
43
|
+
bullets, elapsed time, and status emoji) for free while the turn is in-flight.
|
|
44
|
+
Send the final answer once, with `reply` — it chunks anything over Telegram's
|
|
45
|
+
4096-char limit. For an explicit mid-turn check-in use `progress_update`.
|
|
53
46
|
|
|
54
47
|
## Formatting
|
|
55
48
|
|
|
@@ -10,7 +10,7 @@ This skill is the reference for running `switchroom` CLI commands against existi
|
|
|
10
10
|
|
|
11
11
|
**Four commands to know:**
|
|
12
12
|
- `switchroom update` — full operator path: pulls images + applies config + recreates containers + runs doctor (since v0.7.8 / #918). What you want 95% of the time.
|
|
13
|
-
- `switchroom apply` —
|
|
13
|
+
- `switchroom apply` — **host/operator-only**, for structural changes: refresh per-agent scaffolds and (re)write `~/.switchroom/compose/docker-compose.yml`. Its full per-agent scaffold **cannot run from inside an agent container** (no vault at the container HOME, no `docker compose` v2 plugin) — that's correct by construction, not a bug. Version rolls do NOT need it: drive the **hostd rollout** (`mcp__hostd__rollout`), which runs a `--compose-only` apply plus a per-agent restart-reconcile that refreshes each agent's templates automatically. Reserve a host-side `sudo switchroom apply` for compose regeneration / new-agent scaffolding.
|
|
14
14
|
- `switchroom restart [agent]` — bounces a stuck or wedged agent
|
|
15
15
|
- `switchroom version` — shows what's running (versions + health summary)
|
|
16
16
|
|
|
@@ -59,7 +59,7 @@ switchroom update --rebuild # source-checkout users: also git pull + npm bu
|
|
|
59
59
|
|
|
60
60
|
`switchroom update` is the operator path. The CLI self-elevates via sudo internally for the per-agent scaffold dirs that need root — no need for `sudo HOME=… PATH=…` incantations.
|
|
61
61
|
|
|
62
|
-
If you only need the config-reconcile half without restarting agents, `switchroom apply` writes `~/.switchroom/compose/docker-compose.yml` and refreshes per-agent scaffolds without touching running containers. The operator runs the docker bring-up themselves.
|
|
62
|
+
If you only need the config-reconcile half without restarting agents, `switchroom apply` (run **on the host by the operator**) writes `~/.switchroom/compose/docker-compose.yml` and refreshes per-agent scaffolds without touching running containers. The operator runs the docker bring-up themselves. Note this full apply cannot run from inside an agent container by construction — to roll the fleet to a new version from an agent, use the hostd rollout (`mcp__hostd__rollout`) instead of a full apply.
|
|
63
63
|
|
|
64
64
|
From inside an agent's Telegram DM, the same flow is available as `/upgradestatus` (read-only) and `/update apply` (admin-gated).
|
|
65
65
|
|
|
@@ -265,12 +265,11 @@ If the user asks whether scheduled runs were missed during downtime: the schedul
|
|
|
265
265
|
|
|
266
266
|
## Telegram plugin reference — "what MCP tools", "how does reply work"
|
|
267
267
|
|
|
268
|
-
The `switchroom-telegram` plugin is an enhanced fork of the official Telegram MCP plugin and is the default for all switchroom agents. It exposes **
|
|
268
|
+
The `switchroom-telegram` plugin is an enhanced fork of the official Telegram MCP plugin and is the default for all switchroom agents. It exposes **9 MCP tools** (all prefixed `mcp__switchroom-telegram__`):
|
|
269
269
|
|
|
270
270
|
| Tool | Purpose |
|
|
271
271
|
|---|---|
|
|
272
|
-
| `reply` | Send a text/photo message
|
|
273
|
-
| `stream_reply` | Incrementally stream a long reply (edits the same message as tokens arrive) |
|
|
272
|
+
| `reply` | Send a text/photo message — the single final-answer tool; chunks anything over Telegram's 4096-char limit. Optional `reply_to` for threaded quotes |
|
|
274
273
|
| `react` | Emoji reaction on an inbound or outbound message |
|
|
275
274
|
| `edit_message` | Modify an earlier bot message's text |
|
|
276
275
|
| `delete_message` | Remove an earlier bot message |
|
|
@@ -191,4 +191,4 @@ Before writing the test, ask:
|
|
|
191
191
|
- `telegram-plugin/tests/fake-bot-api.test.ts` — meta-test of the fake;
|
|
192
192
|
read first when adding new fake-bot capabilities
|
|
193
193
|
- `telegram-plugin/tests/streaming-e2e.test.ts` — worked example of a
|
|
194
|
-
larger end-to-end test (PTY →
|
|
194
|
+
larger end-to-end test (PTY → internal stream-reply handler → done)
|
|
@@ -9,10 +9,12 @@ and substantially extended for long-running, multi-agent deployments.
|
|
|
9
9
|
The upstream plugin handles the basic send/receive wire protocol. This fork
|
|
10
10
|
adds the ergonomics and reliability that an always-on agent fleet needs:
|
|
11
11
|
|
|
12
|
-
- **
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
- **Live progress card** — an event-driven progress card (Plan → Run → Done
|
|
13
|
+
with live tool bullets, elapsed time, and status emoji) edits a single
|
|
14
|
+
message in place as work progresses, so users see live progress instead of
|
|
15
|
+
silent gaps followed by a wall-of-text. This is rendered by the plugin for
|
|
16
|
+
free while the turn is in-flight — the model just sends the final answer once
|
|
17
|
+
via `reply`.
|
|
16
18
|
- **Status reactions** — emoji lifecycle (👀 queued → 🤔 thinking → 👨💻 tool
|
|
17
19
|
use → 🔥 streaming → 👍 done) on the user's own message gives "I'm working"
|
|
18
20
|
feedback for free, plus stall watchdogs (🥱 30s idle, 😨 90s).
|
|
@@ -36,7 +38,7 @@ adds the ergonomics and reliability that an always-on agent fleet needs:
|
|
|
36
38
|
- **Switchroom slash-commands** — `/agents`, `/restart`, `/logs`, `/memory`,
|
|
37
39
|
`/grant`, `/dangerous`, `/permissions`, `/reconcile` etc., handled by the
|
|
38
40
|
plugin without consuming Claude Code tokens.
|
|
39
|
-
- **
|
|
41
|
+
- **11 MCP tools** — `reply`, `react`, `edit_message`,
|
|
40
42
|
`delete_message`, `forward_message`, `pin_message`, `send_typing`,
|
|
41
43
|
`download_attachment`, `get_recent_messages`, `send_checklist`,
|
|
42
44
|
`update_checklist` (the latter two ship native Telegram checklists,
|
|
@@ -196,40 +198,27 @@ When an inbound message is received, the plugin immediately reacts with an emoji
|
|
|
196
198
|
|
|
197
199
|
Set to an empty string `""` to disable. Only Telegram's fixed emoji whitelist is accepted (👍 👎 ❤ 🔥 👀 🎉 etc). A typing indicator is also sent automatically.
|
|
198
200
|
|
|
199
|
-
###
|
|
201
|
+
### Progress while working
|
|
200
202
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
| `chat_id` | yes | Target chat ID |
|
|
210
|
-
| `text` | yes | Full text snapshot (NOT a delta — pass the complete current content each call) |
|
|
211
|
-
| `done` | no | `true` on final call. After `done=true` the stream is locked and further calls are no-ops. Default `false`. |
|
|
212
|
-
| `format` | no | `"html"` (default), `"markdownv2"`, or `"text"` |
|
|
213
|
-
| `lane` | no | Optional lane name. Each lane gets its own Telegram message per chat+thread. Use `lane: "thinking"` to surface reasoning progress alongside the main answer stream. Omit for the default answer lane. |
|
|
214
|
-
| `message_thread_id` | no | Forum topic thread ID (auto-applied from the last inbound message if not specified) |
|
|
215
|
-
|
|
216
|
-
Hard-stops at 4096 chars (Telegram message limit). On edit-404 (the message
|
|
217
|
-
we're editing was deleted), the plugin sends a fresh message and continues
|
|
218
|
-
the stream against the new id. A short `idleMs` pre-send debounce coalesces
|
|
219
|
-
back-to-back snapshots before the first wire send, avoiding a redundant
|
|
220
|
-
edit when several updates arrive in the same tick.
|
|
203
|
+
For long tasks the model does **not** need to narrate progress or drive a
|
|
204
|
+
streaming message itself. The plugin renders an event-driven progress card
|
|
205
|
+
(Plan → Run → Done with live tool bullets, elapsed time, and status emoji)
|
|
206
|
+
for free while the turn is in-flight. Send the final answer once, with
|
|
207
|
+
`reply` — it chunks anything over Telegram's 4096-char limit. (The retired
|
|
208
|
+
`stream_reply` tool was a redundant, worse alias of `reply`; the internal
|
|
209
|
+
progress-card streaming that drove it is preserved and is what renders the
|
|
210
|
+
live card.)
|
|
221
211
|
|
|
222
212
|
### Manual streaming progress via `edit_message`
|
|
223
213
|
|
|
224
|
-
If you
|
|
225
|
-
edit loop yourself:
|
|
214
|
+
If you want to drive an in-place edit loop yourself:
|
|
226
215
|
|
|
227
216
|
1. Send an initial "thinking..." message with `reply` — note the returned `message_id`
|
|
228
217
|
2. Call `edit_message` with updated text as work progresses (edits are silent — no push notification)
|
|
229
218
|
3. Call `send_typing` between steps to keep the typing indicator alive (it expires after ~5s)
|
|
230
219
|
4. When done, send a **new** `reply` so the user's device pings with a push notification
|
|
231
220
|
|
|
232
|
-
In most cases
|
|
221
|
+
In most cases the automatic progress card is simpler and is the recommended path.
|
|
233
222
|
|
|
234
223
|
### `send_typing` tool
|
|
235
224
|
|
|
@@ -75,7 +75,7 @@ const mcp = new Server(
|
|
|
75
75
|
instructions: [
|
|
76
76
|
'The sender reads Telegram, not this session. Anything you want them to see must go through the reply tool — your transcript output never reaches their chat.',
|
|
77
77
|
'',
|
|
78
|
-
'Messages from Telegram arrive as <channel source="telegram" chat_id="..." message_id="..." user="..." ts="...">. If the tag has an image_path attribute, Read that file — it is a photo the sender attached. If the tag has attachment_file_id, call download_attachment with that file_id to fetch the file, then Read the returned path. A single message may carry SEVERAL attachments (a forwarded album or a text+multi-image burst): when attachment_count is set (>1), also handle the numbered siblings — image_path_2, image_path_3, … (Read each) and attachment_file_id_2, attachment_file_id_3, … (download_attachment each). Process every one, not just the first. Reply with the reply tool — pass chat_id back. The reply
|
|
78
|
+
'Messages from Telegram arrive as <channel source="telegram" chat_id="..." message_id="..." user="..." ts="...">. If the tag has an image_path attribute, Read that file — it is a photo the sender attached. If the tag has attachment_file_id, call download_attachment with that file_id to fetch the file, then Read the returned path. A single message may carry SEVERAL attachments (a forwarded album or a text+multi-image burst): when attachment_count is set (>1), also handle the numbered siblings — image_path_2, image_path_3, … (Read each) and attachment_file_id_2, attachment_file_id_3, … (download_attachment each). Process every one, not just the first. Reply with the reply tool — pass chat_id back. The reply tool quote-replies to the latest inbound user message by default, so you do NOT need to pass reply_to for normal responses. Pass reply_to (a message_id) only when quoting a specific earlier message, or pass quote:false to send a bare (non-quoted) message.',
|
|
79
79
|
'',
|
|
80
80
|
'reply accepts file paths (files: ["/abs/path.png"]) for attachments. Use react to add emoji reactions, edit_message for interim progress updates, and delete_message when you need to truly remove a message (prefer edit_message if you just want to change text — delete is for retraction). Edits don\'t trigger push notifications — when a long task completes, send a new reply so the user\'s device pings. Use send_typing to show a typing indicator during long operations. Use pin_message to pin important outputs. Use forward_message to quote/resurface earlier messages.',
|
|
81
81
|
'',
|
|
@@ -134,46 +134,6 @@ const TOOL_SCHEMAS = [
|
|
|
134
134
|
required: ['chat_id', 'text'],
|
|
135
135
|
},
|
|
136
136
|
},
|
|
137
|
-
{
|
|
138
|
-
name: 'stream_reply',
|
|
139
|
-
description:
|
|
140
|
-
'Post the final answer for this turn. The plugin renders an event-driven progress card (Plan → Run → Done with live tool bullets, elapsed time, and status emoji) for free while the turn is in-flight, so you do not need to narrate intermediate progress. Call `stream_reply` exactly once per turn with done=true and the complete answer text. Hard cap is 32768 chars (the rich-message wire limit) — longer text is dropped by a defensive guard, so use `reply` for anything that long (it chunks). Calling with done=false is an error in this environment (the progress card already owns the mid-turn surface). inline_keyboard adds tappable buttons under the final message — see `reply` for shape and constraints.',
|
|
141
|
-
inputSchema: {
|
|
142
|
-
type: 'object',
|
|
143
|
-
properties: {
|
|
144
|
-
chat_id: { type: 'string' },
|
|
145
|
-
text: { type: 'string', description: 'Full text snapshot. NOT a delta — pass the complete current content each call.' },
|
|
146
|
-
done: { type: 'boolean', description: 'Must be true. Posts this text as the final answer for the turn and locks the message.' },
|
|
147
|
-
message_thread_id: { type: 'string', description: 'Forum topic thread ID. Auto-applied from the last inbound message if not specified.' },
|
|
148
|
-
origin_turn_id: { type: 'string', description: 'In a forum supergroup, pass back the origin_turn_id attribute from the <channel> message you are answering. It pins the reply to that message\'s topic even if another topic\'s turn started meanwhile. Omit in DMs / single-topic chats.' },
|
|
149
|
-
format: { type: 'string', enum: ['html', 'markdownv2', 'text'], description: "Rendering mode. 'html' (default) converts markdown to Telegram HTML." },
|
|
150
|
-
reply_to: { type: 'string', description: 'Message ID to quote-reply to. Overrides the default (latest inbound).' },
|
|
151
|
-
quote: { type: 'boolean', description: 'Opt out of the default quote-reply behavior. Default: true. Ignored when reply_to is explicitly set.' },
|
|
152
|
-
protect_content: { type: 'boolean', description: 'When true, Telegram prevents the message from being forwarded or saved.' },
|
|
153
|
-
quote_text: { type: 'string', description: 'Surgical quote: specific text to highlight from the reply_to message. Requires reply_to.' },
|
|
154
|
-
disable_notification: { type: 'boolean', description: 'When true, the INITIAL message send is silent (no device ping). Has no effect on subsequent edits — Telegram never pings on editMessageText. Default false. Use for mid-turn stream starts you do not want to ping; omit on the final answer.' },
|
|
155
|
-
inline_keyboard: {
|
|
156
|
-
type: 'array',
|
|
157
|
-
description: '2D array of tappable buttons under the final message. Same shape and constraints as `reply.inline_keyboard` — each button has `text` and EXACTLY ONE of `url` or `callback_data`, plus optional `ack_text` (custom tap-toast; default "✓ received") and `single_use` (default true; set false to keep the keyboard tappable after a tap). Tap on a callback_data button is delivered to this agent as an inbound channel event with meta.button_callback_data set.',
|
|
158
|
-
items: {
|
|
159
|
-
type: 'array',
|
|
160
|
-
items: {
|
|
161
|
-
type: 'object',
|
|
162
|
-
properties: {
|
|
163
|
-
text: { type: 'string' },
|
|
164
|
-
url: { type: 'string' },
|
|
165
|
-
callback_data: { type: 'string' },
|
|
166
|
-
ack_text: { type: 'string', description: 'Toast text shown on tap. Default "✓ received".' },
|
|
167
|
-
single_use: { type: 'boolean', description: 'Default true. Set false to keep the keyboard tappable after this button is tapped.' },
|
|
168
|
-
},
|
|
169
|
-
required: ['text'],
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
required: ['chat_id', 'text'],
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
137
|
{
|
|
178
138
|
name: 'react',
|
|
179
139
|
description: 'Add an emoji reaction to a Telegram message. Telegram only accepts a fixed whitelist (👍 👎 ❤ 🔥 👀 🎉 etc) — non-whitelisted emoji will be rejected.',
|
|
@@ -30,13 +30,12 @@ export interface NamedTool {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Hot tools pinned loaded — must never defer. The reply path
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* Hot tools pinned loaded — must never defer. The reply path plus the
|
|
34
|
+
* frequently-used early-turn ops. Everything NOT in this set defers under
|
|
35
|
+
* tool-search.
|
|
36
36
|
*/
|
|
37
37
|
export const ALWAYS_LOAD_TOOLS: ReadonlySet<string> = new Set([
|
|
38
38
|
'reply',
|
|
39
|
-
'stream_reply',
|
|
40
39
|
'get_recent_messages',
|
|
41
40
|
'react',
|
|
42
41
|
'edit_message',
|
|
@@ -23169,7 +23169,7 @@ function findActiveSessionFile(projectsDir) {
|
|
|
23169
23169
|
}
|
|
23170
23170
|
function parseChannelMeta(content) {
|
|
23171
23171
|
const grab = (key) => {
|
|
23172
|
-
const m = content.match(new RegExp(
|
|
23172
|
+
const m = content.match(new RegExp(`(?:^|[\\s"'])${key}="([^"]+)"`));
|
|
23173
23173
|
return m ? m[1] : null;
|
|
23174
23174
|
};
|
|
23175
23175
|
return {
|
|
@@ -23377,7 +23377,12 @@ function projectSubagentLine(line, agentId, state) {
|
|
|
23377
23377
|
if (ct === "tool_use") {
|
|
23378
23378
|
const name = c.name ?? "";
|
|
23379
23379
|
if (name === "Agent" || name === "Task") {
|
|
23380
|
-
events.push({
|
|
23380
|
+
events.push({
|
|
23381
|
+
kind: "sub_agent_nested_spawn",
|
|
23382
|
+
agentId,
|
|
23383
|
+
toolUseId: c.id ?? null,
|
|
23384
|
+
input: c.input ?? undefined
|
|
23385
|
+
});
|
|
23381
23386
|
} else {
|
|
23382
23387
|
events.push({
|
|
23383
23388
|
kind: "sub_agent_tool_use",
|
|
@@ -24495,7 +24500,6 @@ function createIpcClient(options) {
|
|
|
24495
24500
|
// bridge/tool-filter.ts
|
|
24496
24501
|
var ALWAYS_LOAD_TOOLS = new Set([
|
|
24497
24502
|
"reply",
|
|
24498
|
-
"stream_reply",
|
|
24499
24503
|
"get_recent_messages",
|
|
24500
24504
|
"react",
|
|
24501
24505
|
"edit_message",
|
|
@@ -24647,7 +24651,7 @@ var mcp = new Server({ name: "telegram", version: "1.0.0" }, {
|
|
|
24647
24651
|
instructions: [
|
|
24648
24652
|
"The sender reads Telegram, not this session. Anything you want them to see must go through the reply tool \u2014 your transcript output never reaches their chat.",
|
|
24649
24653
|
"",
|
|
24650
|
-
'Messages from Telegram arrive as <channel source="telegram" chat_id="..." message_id="..." user="..." ts="...">. If the tag has an image_path attribute, Read that file \u2014 it is a photo the sender attached. If the tag has attachment_file_id, call download_attachment with that file_id to fetch the file, then Read the returned path. A single message may carry SEVERAL attachments (a forwarded album or a text+multi-image burst): when attachment_count is set (>1), also handle the numbered siblings \u2014 image_path_2, image_path_3, \u2026 (Read each) and attachment_file_id_2, attachment_file_id_3, \u2026 (download_attachment each). Process every one, not just the first. Reply with the reply tool \u2014 pass chat_id back. The reply
|
|
24654
|
+
'Messages from Telegram arrive as <channel source="telegram" chat_id="..." message_id="..." user="..." ts="...">. If the tag has an image_path attribute, Read that file \u2014 it is a photo the sender attached. If the tag has attachment_file_id, call download_attachment with that file_id to fetch the file, then Read the returned path. A single message may carry SEVERAL attachments (a forwarded album or a text+multi-image burst): when attachment_count is set (>1), also handle the numbered siblings \u2014 image_path_2, image_path_3, \u2026 (Read each) and attachment_file_id_2, attachment_file_id_3, \u2026 (download_attachment each). Process every one, not just the first. Reply with the reply tool \u2014 pass chat_id back. The reply tool quote-replies to the latest inbound user message by default, so you do NOT need to pass reply_to for normal responses. Pass reply_to (a message_id) only when quoting a specific earlier message, or pass quote:false to send a bare (non-quoted) message.',
|
|
24651
24655
|
"",
|
|
24652
24656
|
`reply accepts file paths (files: ["/abs/path.png"]) for attachments. Use react to add emoji reactions, edit_message for interim progress updates, and delete_message when you need to truly remove a message (prefer edit_message if you just want to change text \u2014 delete is for retraction). Edits don't trigger push notifications \u2014 when a long task completes, send a new reply so the user's device pings. Use send_typing to show a typing indicator during long operations. Use pin_message to pin important outputs. Use forward_message to quote/resurface earlier messages.`,
|
|
24653
24657
|
"",
|
|
@@ -24702,45 +24706,6 @@ var TOOL_SCHEMAS = [
|
|
|
24702
24706
|
required: ["chat_id", "text"]
|
|
24703
24707
|
}
|
|
24704
24708
|
},
|
|
24705
|
-
{
|
|
24706
|
-
name: "stream_reply",
|
|
24707
|
-
description: "Post the final answer for this turn. The plugin renders an event-driven progress card (Plan \u2192 Run \u2192 Done with live tool bullets, elapsed time, and status emoji) for free while the turn is in-flight, so you do not need to narrate intermediate progress. Call `stream_reply` exactly once per turn with done=true and the complete answer text. Hard cap is 32768 chars (the rich-message wire limit) \u2014 longer text is dropped by a defensive guard, so use `reply` for anything that long (it chunks). Calling with done=false is an error in this environment (the progress card already owns the mid-turn surface). inline_keyboard adds tappable buttons under the final message \u2014 see `reply` for shape and constraints.",
|
|
24708
|
-
inputSchema: {
|
|
24709
|
-
type: "object",
|
|
24710
|
-
properties: {
|
|
24711
|
-
chat_id: { type: "string" },
|
|
24712
|
-
text: { type: "string", description: "Full text snapshot. NOT a delta \u2014 pass the complete current content each call." },
|
|
24713
|
-
done: { type: "boolean", description: "Must be true. Posts this text as the final answer for the turn and locks the message." },
|
|
24714
|
-
message_thread_id: { type: "string", description: "Forum topic thread ID. Auto-applied from the last inbound message if not specified." },
|
|
24715
|
-
origin_turn_id: { type: "string", description: "In a forum supergroup, pass back the origin_turn_id attribute from the <channel> message you are answering. It pins the reply to that message's topic even if another topic's turn started meanwhile. Omit in DMs / single-topic chats." },
|
|
24716
|
-
format: { type: "string", enum: ["html", "markdownv2", "text"], description: "Rendering mode. 'html' (default) converts markdown to Telegram HTML." },
|
|
24717
|
-
reply_to: { type: "string", description: "Message ID to quote-reply to. Overrides the default (latest inbound)." },
|
|
24718
|
-
quote: { type: "boolean", description: "Opt out of the default quote-reply behavior. Default: true. Ignored when reply_to is explicitly set." },
|
|
24719
|
-
protect_content: { type: "boolean", description: "When true, Telegram prevents the message from being forwarded or saved." },
|
|
24720
|
-
quote_text: { type: "string", description: "Surgical quote: specific text to highlight from the reply_to message. Requires reply_to." },
|
|
24721
|
-
disable_notification: { type: "boolean", description: "When true, the INITIAL message send is silent (no device ping). Has no effect on subsequent edits \u2014 Telegram never pings on editMessageText. Default false. Use for mid-turn stream starts you do not want to ping; omit on the final answer." },
|
|
24722
|
-
inline_keyboard: {
|
|
24723
|
-
type: "array",
|
|
24724
|
-
description: '2D array of tappable buttons under the final message. Same shape and constraints as `reply.inline_keyboard` \u2014 each button has `text` and EXACTLY ONE of `url` or `callback_data`, plus optional `ack_text` (custom tap-toast; default "\u2713 received") and `single_use` (default true; set false to keep the keyboard tappable after a tap). Tap on a callback_data button is delivered to this agent as an inbound channel event with meta.button_callback_data set.',
|
|
24725
|
-
items: {
|
|
24726
|
-
type: "array",
|
|
24727
|
-
items: {
|
|
24728
|
-
type: "object",
|
|
24729
|
-
properties: {
|
|
24730
|
-
text: { type: "string" },
|
|
24731
|
-
url: { type: "string" },
|
|
24732
|
-
callback_data: { type: "string" },
|
|
24733
|
-
ack_text: { type: "string", description: 'Toast text shown on tap. Default "\u2713 received".' },
|
|
24734
|
-
single_use: { type: "boolean", description: "Default true. Set false to keep the keyboard tappable after this button is tapped." }
|
|
24735
|
-
},
|
|
24736
|
-
required: ["text"]
|
|
24737
|
-
}
|
|
24738
|
-
}
|
|
24739
|
-
}
|
|
24740
|
-
},
|
|
24741
|
-
required: ["chat_id", "text"]
|
|
24742
|
-
}
|
|
24743
|
-
},
|
|
24744
24709
|
{
|
|
24745
24710
|
name: "react",
|
|
24746
24711
|
description: "Add an emoji reaction to a Telegram message. Telegram only accepts a fixed whitelist (\uD83D\uDC4D \uD83D\uDC4E \u2764 \uD83D\uDD25 \uD83D\uDC40 \uD83C\uDF89 etc) \u2014 non-whitelisted emoji will be rejected.",
|