switchroom 0.16.46 → 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 +83 -81
- package/dist/auth-broker/index.js +104 -88
- package/dist/cli/autoaccept-poll.js +8 -8
- package/dist/cli/drive-write-pretool.mjs +10 -15
- package/dist/cli/notion-write-pretool.mjs +85 -83
- package/dist/cli/skill-validate-pretool.mjs +91 -91
- package/dist/cli/switchroom.js +1720 -1392
- package/dist/cli/ui/index.html +84 -12
- package/dist/host-control/main.js +209 -173
- package/dist/vault/approvals/kernel-server.js +86 -83
- package/dist/vault/broker/server.js +284 -139
- 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 +120 -155
- package/telegram-plugin/dist/gateway/gateway.js +1127 -1029
- package/telegram-plugin/dist/server.js +168 -203
- 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 +566 -631
- 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/vault-request-access-unlock-resume.test.ts +46 -0
- 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
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchroom",
|
|
3
3
|
"//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.17.0",
|
|
5
5
|
"description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"build": "node scripts/build.mjs",
|
|
25
25
|
"build:cli": "node scripts/build.mjs && bun build --compile --target=bun-linux-x64 --minify bin/switchroom.ts --outfile switchroom-linux-amd64",
|
|
26
26
|
"pretest": "npm run build",
|
|
27
|
-
"test": "vitest run && bun test telegram-plugin/tests/history.test.ts telegram-plugin/tests/cross-turn-card-gate.test.ts telegram-plugin/tests/emission-authority-open-gate.test.ts telegram-plugin/tests/emission-authority-ping-gate.test.ts telegram-plugin/tests/emission-authority-card-drain-gate.test.ts telegram-plugin/tests/per-topic-current-turn.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/
|
|
27
|
+
"test": "vitest run && bun test telegram-plugin/tests/history.test.ts telegram-plugin/tests/cross-turn-card-gate.test.ts telegram-plugin/tests/emission-authority-open-gate.test.ts telegram-plugin/tests/emission-authority-ping-gate.test.ts telegram-plugin/tests/emission-authority-card-drain-gate.test.ts telegram-plugin/tests/per-topic-current-turn.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/registry/subagents-bugs.test.ts telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts telegram-plugin/tests/subagent-nested-dispatch.test.ts telegram-plugin/tests/nested-worker-visibility-harness.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resume-inbound-builder.test.ts telegram-plugin/registry/api-registry.test.ts telegram-plugin/registry/turns-schema.test.ts telegram-plugin/tests/idle-footer-wiring.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts telegram-plugin/tests/status-query-telemetry.test.ts telegram-plugin/tests/reaction-trigger.test.ts telegram-plugin/tests/reaction-trigger-flow.test.ts telegram-plugin/gateway/webhook-ingest-server.test.ts telegram-plugin/tests/skill-proposal-card.test.ts",
|
|
28
28
|
"test:vitest": "vitest run",
|
|
29
|
-
"test:bun": "bun test src/vault/grants.test.ts src/vault/write-grants.test.ts src/vault/broker/server-grants.test.ts src/vault/broker/server-write-grants.test.ts src/vault/broker/server-mint-grant-passphrase-attest.test.ts src/vault/broker/server-passphrase-attest.test.ts src/vault/broker/server-mint-grant-posture-attest.test.ts src/vault/broker/server-admin-only-keys.test.ts src/vault/broker/client-token.test.ts src/vault/broker/server-unlock.test.ts src/vault/broker/auto-unlock.test.ts src/vault/broker/drift-detection.test.ts tests/vault-broker-passphrase.test.ts src/cli/vault-get-broker.test.ts src/vault/resolver-via-broker.test.ts src/vault/broker/scope.test.ts src/vault/broker/server.test.ts src/litellm/provision-apply-e2e.test.ts src/drive/disconnect.test.ts src/drive/grants.test.ts src/drive/oauth.test.ts src/drive/onboarding.test.ts src/drive/reconciler.test.ts src/drive/vault-slots.test.ts src/drive/wrapper.test.ts src/vault/approvals/kernel.test.ts src/vault/approvals/approval-origin.test.ts src/vault/approvals/schema-idempotent.test.ts src/vault/broker/server-approvals.test.ts telegram-plugin/tests/boot-probes.test.ts telegram-plugin/tests/boot-version-string.test.ts telegram-plugin/tests/history.test.ts telegram-plugin/tests/cross-turn-card-gate.test.ts telegram-plugin/tests/emission-authority-open-gate.test.ts telegram-plugin/tests/emission-authority-ping-gate.test.ts telegram-plugin/tests/emission-authority-card-drain-gate.test.ts telegram-plugin/tests/per-topic-current-turn.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/registry/subagents-bugs.test.ts telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resume-inbound-builder.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts telegram-plugin/tests/reaction-trigger.test.ts telegram-plugin/tests/reaction-trigger-flow.test.ts telegram-plugin/tests/subagent-watcher-workflow-visibility.test.ts telegram-plugin/uat/load-env.test.ts telegram-plugin/uat/feed-matcher.test.ts telegram-plugin/uat/uat-driver.test.ts telegram-plugin/gateway/webhook-ingest-server.test.ts telegram-plugin/tests/skill-proposal-card.test.ts",
|
|
29
|
+
"test:bun": "bun test src/vault/grants.test.ts src/vault/grants-db.test.ts src/vault/write-grants.test.ts src/vault/broker/server-grants.test.ts src/vault/broker/server-write-grants.test.ts src/vault/broker/server-mint-grant-passphrase-attest.test.ts src/vault/broker/server-passphrase-attest.test.ts src/vault/broker/server-mint-grant-posture-attest.test.ts src/vault/broker/server-admin-only-keys.test.ts src/vault/broker/client-token.test.ts src/vault/broker/server-unlock.test.ts src/vault/broker/auto-unlock.test.ts src/vault/broker/drift-detection.test.ts tests/vault-broker-passphrase.test.ts src/cli/vault-get-broker.test.ts src/vault/resolver-via-broker.test.ts src/vault/broker/scope.test.ts src/vault/broker/server.test.ts src/litellm/provision-apply-e2e.test.ts src/drive/disconnect.test.ts src/drive/grants.test.ts src/drive/oauth.test.ts src/drive/onboarding.test.ts src/drive/reconciler.test.ts src/drive/vault-slots.test.ts src/drive/wrapper.test.ts src/vault/approvals/kernel.test.ts src/vault/approvals/approval-origin.test.ts src/vault/approvals/schema-idempotent.test.ts src/vault/broker/server-approvals.test.ts telegram-plugin/tests/boot-probes.test.ts telegram-plugin/tests/boot-version-string.test.ts telegram-plugin/tests/history.test.ts telegram-plugin/tests/cross-turn-card-gate.test.ts telegram-plugin/tests/emission-authority-open-gate.test.ts telegram-plugin/tests/emission-authority-ping-gate.test.ts telegram-plugin/tests/emission-authority-card-drain-gate.test.ts telegram-plugin/tests/per-topic-current-turn.test.ts telegram-plugin/tests/history-reaper.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/registry/subagents-bugs.test.ts telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts telegram-plugin/tests/subagent-nested-dispatch.test.ts telegram-plugin/tests/nested-worker-visibility-harness.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resume-inbound-builder.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts telegram-plugin/tests/status-query-telemetry.test.ts telegram-plugin/tests/reaction-trigger.test.ts telegram-plugin/tests/reaction-trigger-flow.test.ts telegram-plugin/tests/subagent-watcher-workflow-visibility.test.ts telegram-plugin/uat/load-env.test.ts telegram-plugin/uat/feed-matcher.test.ts telegram-plugin/uat/uat-driver.test.ts telegram-plugin/gateway/webhook-ingest-server.test.ts telegram-plugin/tests/skill-proposal-card.test.ts",
|
|
30
30
|
"test:watch": "vitest",
|
|
31
31
|
"lint": "tsc --noEmit && node scripts/check-plugin-references.mjs && bash scripts/check-bot-api-wrapping.sh && node scripts/check-bun-test-imports.mjs && node scripts/check-no-pii-secrets.mjs && node scripts/check-vault-test-hermeticity.mjs && node scripts/check-no-broadcast-delivery.mjs && node scripts/check-stale-tool-descriptions.mjs && node scripts/check-web-subscription-honest.mjs",
|
|
32
32
|
"lint:tsc": "tsc --noEmit",
|
|
@@ -95,7 +95,7 @@ cd "{{agentDir}}" || exit 1
|
|
|
95
95
|
# can distinguish cron spend from main-session spend per agent.
|
|
96
96
|
# FAIL-OPEN: missing key OR unreachable proxy → strip routing env, fall back to
|
|
97
97
|
# direct OAuth. An outage must never take the cron session dark.
|
|
98
|
-
if [ -n "$SWITCHROOM_LITELLM" ] && command -v switchroom >/dev/null 2>&1; then
|
|
98
|
+
if [ -n "${SWITCHROOM_LITELLM:-}" ] && command -v switchroom >/dev/null 2>&1; then
|
|
99
99
|
sr_ll_key="$(switchroom vault get "litellm/{{name}}/api-key" 2>/dev/null || true)"
|
|
100
100
|
sr_ll_ok=""
|
|
101
101
|
if [ -z "$sr_ll_key" ]; then
|
|
@@ -64,7 +64,7 @@ if [ "$SWITCHROOM_RUNTIME" = "docker" ] && [ -z "$SWITCHROOM_DOCKER_TMUX_INNER"
|
|
|
64
64
|
#
|
|
65
65
|
# SWITCHROOM_AGENT_NAME is injected by compose env (compose.ts:1816)
|
|
66
66
|
# so it is available here, before the inner-pass export at line ~320.
|
|
67
|
-
if [ -n "$SWITCHROOM_LITELLM" ] && [ -z "$ANTHROPIC_CUSTOM_HEADERS" ] && command -v switchroom >/dev/null 2>&1; then
|
|
67
|
+
if [ -n "${SWITCHROOM_LITELLM:-}" ] && [ -z "$ANTHROPIC_CUSTOM_HEADERS" ] && command -v switchroom >/dev/null 2>&1; then
|
|
68
68
|
sr_ll_key="$(switchroom vault get "litellm/$SWITCHROOM_AGENT_NAME/api-key" 2>/dev/null || true)"
|
|
69
69
|
sr_ll_ok=""
|
|
70
70
|
if [ -z "$sr_ll_key" ]; then
|
|
@@ -657,8 +657,24 @@ mkdir -p "$TELEGRAM_STATE_DIR" 2>/dev/null || true
|
|
|
657
657
|
# .handoff-briefing.md and merged alongside (or instead of) .handoff.md.
|
|
658
658
|
HANDOFF_FILE="{{agentDir}}/.handoff.md"
|
|
659
659
|
HANDOFF_BRIEFING_FILE="{{agentDir}}/.handoff-briefing.md"
|
|
660
|
+
# Decide whether the on-disk briefing is stale and must be rebuilt (#2790).
|
|
661
|
+
# A clean shutdown leaves a non-empty .handoff.md; a *later* hard crash never
|
|
662
|
+
# fires the Stop hook, so that stale briefing would otherwise be re-injected
|
|
663
|
+
# — hiding the crashed session's turns and reorienting the agent from old
|
|
664
|
+
# context. Rebuild when .handoff.md is empty OR when the newest session JSONL
|
|
665
|
+
# is newer than .handoff.md (i.e. a session ran after the briefing was written).
|
|
666
|
+
_LATEST_JSONL=$(_find_latest_jsonl "$CLAUDE_CONFIG_DIR/projects")
|
|
667
|
+
_HANDOFF_STALE=0
|
|
660
668
|
if [ ! -s "$HANDOFF_FILE" ]; then
|
|
661
|
-
|
|
669
|
+
_HANDOFF_STALE=1
|
|
670
|
+
elif [ -n "$_LATEST_JSONL" ]; then
|
|
671
|
+
_JSONL_MOD=$(_stat_mtime "$_LATEST_JSONL")
|
|
672
|
+
_HANDOFF_MOD=$(_stat_mtime "$HANDOFF_FILE")
|
|
673
|
+
if [ "$_JSONL_MOD" -gt "$_HANDOFF_MOD" ]; then
|
|
674
|
+
_HANDOFF_STALE=1
|
|
675
|
+
fi
|
|
676
|
+
fi
|
|
677
|
+
if [ "$_HANDOFF_STALE" = "1" ]; then
|
|
662
678
|
if [ -n "$_LATEST_JSONL" ]; then
|
|
663
679
|
_LAST_MOD=$(_stat_mtime "$_LATEST_JSONL")
|
|
664
680
|
_NOW=$(date +%s)
|
|
@@ -704,6 +720,11 @@ $_HANDOFF_CONTENT"
|
|
|
704
720
|
APPEND_PROMPT="$_HANDOFF_CONTENT"
|
|
705
721
|
fi
|
|
706
722
|
fi
|
|
723
|
+
# Consume the briefing sidecars once injected (#2790). Leaving them on disk
|
|
724
|
+
# lets a later hard crash (which never fires the Stop hook to refresh them)
|
|
725
|
+
# re-serve this now-stale briefing on the next boot. Removing them means the
|
|
726
|
+
# staleness guard above starts from a clean slate every boot.
|
|
727
|
+
rm -f "$HANDOFF_BRIEFING_FILE" "$HANDOFF_FILE" 2>/dev/null || true
|
|
707
728
|
{{else}}
|
|
708
729
|
APPEND_PROMPT={{#if systemPromptAppendShellQuoted}}{{{systemPromptAppendShellQuoted}}}{{else}}""{{/if}}
|
|
709
730
|
{{/if}}
|
|
@@ -807,6 +828,36 @@ if command -v switchroom >/dev/null 2>&1; then
|
|
|
807
828
|
unset sr_wk_pair sr_wk_env sr_wk_key sr_wk_val
|
|
808
829
|
fi
|
|
809
830
|
|
|
831
|
+
# Fleet-wide webkite render config (#2805). Seed the image-baked default
|
|
832
|
+
# (/opt/switchroom/webkite/config.toml) into the XDG location webkite reads
|
|
833
|
+
# ($HOME/.config/webkite/config.toml) so JS-heavy SPA/booking pages render
|
|
834
|
+
# via the baked-in cloakbrowser instead of returning a static shell.
|
|
835
|
+
#
|
|
836
|
+
# REFRESH-from-image, not copy-if-absent. $HOME (/state/agent/home) is a
|
|
837
|
+
# host-PERSISTENT bind mount (see src/agents/compose.ts), so a copy-if-absent
|
|
838
|
+
# seed would write once and then the stale home copy would shadow every future
|
|
839
|
+
# image-shipped config update forever — the config would be un-updatable
|
|
840
|
+
# fleet-wide after first boot. Instead re-sync the target from the baked
|
|
841
|
+
# default whenever they differ, so an image bump always propagates.
|
|
842
|
+
#
|
|
843
|
+
# Operator override still wins: an operator-authored
|
|
844
|
+
# ~/.switchroom/webkite/config.toml is bind-mounted RO onto this exact target
|
|
845
|
+
# (compose.ts). We detect that mount and leave it untouched; even absent the
|
|
846
|
+
# mountpoint check, a cp onto the RO mount fails harmlessly and the override
|
|
847
|
+
# is preserved.
|
|
848
|
+
if [ -f /opt/switchroom/webkite/config.toml ]; then
|
|
849
|
+
sr_wk_target="$HOME/.config/webkite/config.toml"
|
|
850
|
+
if mountpoint -q "$sr_wk_target" 2>/dev/null; then
|
|
851
|
+
: # operator override bind-mounted RO — never clobber it
|
|
852
|
+
elif ! cmp -s /opt/switchroom/webkite/config.toml "$sr_wk_target" 2>/dev/null; then
|
|
853
|
+
mkdir -p "$HOME/.config/webkite" 2>/dev/null || true
|
|
854
|
+
cp /opt/switchroom/webkite/config.toml "$sr_wk_target" 2>/dev/null \
|
|
855
|
+
&& echo "webkite: synced fleet render config to \$HOME/.config/webkite/config.toml" >&2 \
|
|
856
|
+
|| echo "webkite: could not sync render config (non-fatal)" >&2
|
|
857
|
+
fi
|
|
858
|
+
unset sr_wk_target
|
|
859
|
+
fi
|
|
860
|
+
|
|
810
861
|
# LiteLLM routing (opt-in, #litellm). When SWITCHROOM_LITELLM is set (compose
|
|
811
862
|
# env, gated on litellm.enabled && keyConfirmed), route the unmodified `claude`
|
|
812
863
|
# CLI through the operator's LiteLLM proxy at ANTHROPIC_BASE_URL: fetch the
|
|
@@ -833,7 +884,7 @@ fi
|
|
|
833
884
|
# per-session cost/issue tracking is handled out-of-band by correlating
|
|
834
885
|
# LiteLLM's request log against switchroom's turn ledger, never by mutating the
|
|
835
886
|
# claude protocol.
|
|
836
|
-
if [ -n "$SWITCHROOM_LITELLM" ] && command -v switchroom >/dev/null 2>&1; then
|
|
887
|
+
if [ -n "${SWITCHROOM_LITELLM:-}" ] && command -v switchroom >/dev/null 2>&1; then
|
|
837
888
|
sr_ll_key="$(switchroom vault get "litellm/$SWITCHROOM_AGENT_NAME/api-key" 2>/dev/null || true)"
|
|
838
889
|
sr_ll_ok=""
|
|
839
890
|
if [ -z "$sr_ll_key" ]; then
|
|
@@ -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',
|