RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/openclaw-openclaw-src-agents-tools-agents ↔ openclaw-openclaw-extensions-telegram-agents

Comparison

A · AGENTS.md · openclaw/openclawB · AGENTS.md · openclaw/openclaw
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections0390%
Commands0200%
Section tags0350%

What each file covers

Sections

0 shared · 3 only in A · 9 only in B
  • − Agent Tools Performance
  • − Guardrails
  • − Verification
  • + Telegram Plugin Guide
  • + Reliability Invariants
  • + Core drain contracts (do not re-implement in Telegram)
  • + Telegram-owned (transport + channel policy)
  • + Streaming
  • + Telegram API Ownership
  • + Context And Authorization
  • + Interactive Surfaces
  • + Review Standard

Commands

0 shared · 2 only in A · 0 only in B
  • − pnpm test <file>
  • − pnpm build

Section tags

0 shared · 3 only in A · 5 only in B
  • − test
  • − performance
  • − agent-behaviour
  • + code-style
  • + git-pr
  • + security
  • + api
  • + do-not

Line diff

+130 added−21 removed7 unchanged5.1% identical
openclaw/openclaw · src/agents/tools/AGENTS.md
@@ −1 @@
1<!-- Agent tool test performance notes for avoiding heavyweight plugin/channel runtime loads. -->
2 
3# Agent Tools Performance
 
 
 
4 
5Tool tests should not load full channel or plugin runtimes for static tool
6descriptions.
7 
8## Guardrails
9 
10- Message-tool discovery should flow through shared discovery helpers and
11 lightweight channel artifacts before falling back to a full channel plugin
12 load.
13- Channel-specific tool schemas, action lists, and static capabilities belong
14 in plugin-owned helpers that are reused by both the full plugin and the
15 lightweight artifact.
16- Do not add direct bundled-plugin imports to agent tool tests for schema or
17 capability assertions. If the production path needs the same data, promote a
18 small public artifact instead.
19- If a single assertion starts paying multi-second import/setup cost, split the
20 static descriptor path from runtime execution instead of adding more mocks
21 around the broad import.
22 
23## Verification
 
 
24 
25- For `src/agents/tools/*.test.ts` performance work, compare targeted file
26 runtime with `pnpm test <file>` before/after.
27- Run `pnpm build` when adding or changing bundled plugin artifacts.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28 
openclaw/openclaw · extensions/telegram/AGENTS.md
@@ +1 @@
1# Telegram Plugin Guide
2 
3Read this before any change under `extensions/telegram/`. These are intentional
4maintainer decisions and review-binding invariants, not incidental
5implementation details. Also read `extensions/AGENTS.md` for the plugin
6boundary rules.
7 
8Verified against Telegram Bot API 10.2, July 14 2026.
 
9 
10## Reliability Invariants
11 
12### Core drain contracts (do not re-implement in Telegram)
 
 
 
 
 
 
 
 
 
 
 
13 
14Owned by `src/channels/message/ingress-drain.ts` (+ claim-owner, retry-policy).
15Proof: `src/channels/message/ingress-drain.test.ts`,
16`ingress-claim-owner.test.ts`, `ingress-retry-policy.test.ts`.
17 
18- Completed rows tombstone via `complete()`, never `delete`.
19- Complete at turn adoption, not settle. Deferred holds the claim; watchdog
20 stays armed through deferral; dead-letter reason `handler-timeout`.
21- One retry policy: attempt floor **and** age gate (defaults 8 / 24h).
22- Claim refresh heartbeat while dispatching/deferred (`claimLeaseMs / 3`).
23- Never silently complete on transient failure — release/fail via disposition.
24- Pre-adoption supersede tombstones; post-adoption interruption is core-owned
25 (reply-run registry / queue interrupt).
26 
27### Telegram-owned (transport + channel policy)
28 
29- Durable-before-ack on both transports. Polling: ingress worker advances its
30 offset only after the parent's committed spool enqueue
31 (`writeTelegramSpooledUpdate`). Webhook: respond 200 only after the spool
32 write; non-200 on write failure is the redelivery contract.
33- `update_id`↔event-id encoding and per-chat/topic lane derivation stay in
34 `telegram-ingress-spool.ts` / sequential-key.
35- Polling and webhook both: enqueue then pump
36 `createTelegramTransportIngressDrain(...).drainOnce()` — no private claim
37 loops.
38- Stall timeout: `OPENCLAW_TELEGRAM_SPOOLED_HANDLER_TIMEOUT_MS` →
39 `adoptionStallTimeoutMs` (default 5 min) via
40 `resolveTelegramAdoptionStallTimeoutMs`.
41- Non-retryable classifier: `telegram-ingress-non-retryable.ts`
42 (missing harness, dispatch-dedupe rollback).
43- Supersede predicate: `telegram-ingress-supersede.ts` — only abort text /
44 authorized-looking explicit commands (and ambient room_event pending) may
45 supersede pre-adoption work. Normal messages never supersede.
46- room_event ambient work shares the sequential lane so a later user turn can
47 supersede it pre-adoption; adopted user turns are never touched (core drain
48 supersede is pre-adoption only).
49- No per-message full-store writes. Hot-path SQLite writes are per-entry.
50 Rewriting a cache on every send or read stalls the event loop, and that
51 stall masquerades as a polling stall (the sent-message-cache regression).
52- Transport error classification. The getUpdates worker retries Bot API 5xx
53 and 429 locally, honoring `parameters.retry_after`; 401/404 stay fatal; 409
54 must propagate to the parent session, which owns webhook-conflict recovery.
55 Bot API errors carry `error_code`, not `.code`; parse non-2xx bodies
56 defensively (a 502 HTML page is not JSON).
57- Send funnel parity. The durable funnel (`send.ts`) and the streaming funnel
58 (`bot/delivery.*`) must degrade identically: rich-entity 400 falls back to
59 plain text, caption parse 400 falls back to a plain caption, quote-not-found
60 400 falls back to a legacy reply. New recoveries go into the shared
61 predicates (`send-error-predicates.ts`, `reply-parameters.ts`), never into
62 one funnel only.
63- Outbound flood waits honor `retry_after` up to
64 `TELEGRAM_OUTBOUND_RETRY_AFTER_CAP_MS`; do not re-clamp Telegram sends to the
65 generic channel retry ceiling.
66- Webhook security ordering. The secret header is validated first
67 (constant-time compare, single-header enforcement, connection close on 401);
68 the request rate limit budgets only failed-auth attempts so Telegram's own
69 delivery is never throttled.
70- Every owned undici transport gets closed on all exit paths: polling session,
71 webhook shutdown and startup failure, probe-cache eviction.
72 
73## Streaming
74 
75- Do not reintroduce `sendMessageDraft` for answer streaming. Telegram drafts
76 are ephemeral 30-second previews in private chats; final delivery still
77 requires a separate `sendMessage`. OpenClaw uses `sendMessage` plus
78 `editMessageText`, then finalizes in place so the user sees one persistent
79 answer.
80- Streaming owns one visible preview message. Edit it forward. Do not send an
81 extra final bubble unless the final edit genuinely failed.
82- Keep the first-preview debounce. If a provider sends token-sized deltas,
83 coalesce them into cumulative preview text instead of removing the debounce.
84- Respect Telegram limits in the Telegram layer. Text over 4096 chars chains
85 into continuation messages. Polls keep the current Bot API 12-option cap.
86 
87## Telegram API Ownership
88 
89- Prefer grammY primitives and Telegram-native helpers when they model the
90 behavior directly. Avoid custom Bot API wrappers for behavior grammY already
91 owns.
92- Throttling is bot-token scoped. All Telegram API clients for the same token
93 share one grammY `apiThrottler()` instance.
94- Do not silently retry failed topic sends without topic metadata. A
95 wrong-surface success is worse than a loud Telegram error.
96- DM topics and forum topics are distinct. `direct_messages_topic_id` and
97 `message_thread_id` are not interchangeable.
98 
99## Context And Authorization
100 
101- Reply context comes from OpenClaw-observed messages. Bot API updates expose
102 `reply_to_message`, but there is no arbitrary `getMessage(chat, id)`
103 hydration path later.
104- Current local chat context must outrank stale reply ancestry in the prompt.
105 Old replied-to messages should not look like the active conversation.
106- The group history window is always on for groups and bounded by
107 `historyLimit`. Do not reintroduce prompt-history gating modes; that
108 regression blinded ambient rooms.
109- The group history window is rolling. Use self-entry watermark selection for
110 "since your last reply" views; do not reintroduce destructive clears because
111 room events are not persisted to the session and cleared context is
112 unrecoverable.
113- Pairing is DM-only. Group and topic authorization need explicit config
114 allowlists.
115- Telegram allowlists use numeric sender IDs. Usernames are optional, mutable,
116 and not a reliable arbitrary-user lookup key in the Bot API.
117- Group and channel visible replies are policy-controlled. Normal room replies
118 stay private unless `messages.groupChat.visibleReplies: "automatic"` is set
119 or the agent explicitly calls `message.send`.
120 
121## Interactive Surfaces
122 
123- Native callbacks stay structured. Approval, native command, plugin, select,
124 and multiselect callbacks must not fall through as raw callback text.
125- Preserve callback values exactly, including delimiters such as `env|prod`.
126- Native slash commands should remain fast-pathable before full workspace and
127 agent-turn setup.
128 
129## Review Standard
130 
131- Telegram behavior PRs need real Telegram proof when they touch transport,
132 streaming, topics, callbacks, authorization, or reply context. Prefer the
133 bot-to-bot QA lane or an equivalent live Telegram probe over synthetic-only
134 validation.
135- Reliability PRs (spool, drain, retry, ack, offset paths) need crash-window
136 or restart-replay test proof, not just happy-path tests.
137 
@@ −1 +1 @@
1−<!-- Agent tool test performance notes for avoiding heavyweight plugin/channel runtime loads. -->
1+# Telegram Plugin Guide
22  
3−# Agent Tools Performance
3+Read this before any change under `extensions/telegram/`. These are intentional
4+maintainer decisions and review-binding invariants, not incidental
5+implementation details. Also read `extensions/AGENTS.md` for the plugin
6+boundary rules.
47  
5−Tool tests should not load full channel or plugin runtimes for static tool
6−descriptions.
8+Verified against Telegram Bot API 10.2, July 14 2026.
79  
8−## Guardrails
10+## Reliability Invariants
911  
10−- Message-tool discovery should flow through shared discovery helpers and
11− lightweight channel artifacts before falling back to a full channel plugin
12− load.
13−- Channel-specific tool schemas, action lists, and static capabilities belong
14− in plugin-owned helpers that are reused by both the full plugin and the
15− lightweight artifact.
16−- Do not add direct bundled-plugin imports to agent tool tests for schema or
17− capability assertions. If the production path needs the same data, promote a
18− small public artifact instead.
19−- If a single assertion starts paying multi-second import/setup cost, split the
20− static descriptor path from runtime execution instead of adding more mocks
21− around the broad import.
12+### Core drain contracts (do not re-implement in Telegram)
2213  
23−## Verification
14+Owned by `src/channels/message/ingress-drain.ts` (+ claim-owner, retry-policy).
15+Proof: `src/channels/message/ingress-drain.test.ts`,
16+`ingress-claim-owner.test.ts`, `ingress-retry-policy.test.ts`.
2417  
25−- For `src/agents/tools/*.test.ts` performance work, compare targeted file
26− runtime with `pnpm test <file>` before/after.
27−- Run `pnpm build` when adding or changing bundled plugin artifacts.
18+- Completed rows tombstone via `complete()`, never `delete`.
19+- Complete at turn adoption, not settle. Deferred holds the claim; watchdog
20+ stays armed through deferral; dead-letter reason `handler-timeout`.
21+- One retry policy: attempt floor **and** age gate (defaults 8 / 24h).
22+- Claim refresh heartbeat while dispatching/deferred (`claimLeaseMs / 3`).
23+- Never silently complete on transient failure — release/fail via disposition.
24+- Pre-adoption supersede tombstones; post-adoption interruption is core-owned
25+ (reply-run registry / queue interrupt).
26+ 
27+### Telegram-owned (transport + channel policy)
28+ 
29+- Durable-before-ack on both transports. Polling: ingress worker advances its
30+ offset only after the parent's committed spool enqueue
31+ (`writeTelegramSpooledUpdate`). Webhook: respond 200 only after the spool
32+ write; non-200 on write failure is the redelivery contract.
33+- `update_id`↔event-id encoding and per-chat/topic lane derivation stay in
34+ `telegram-ingress-spool.ts` / sequential-key.
35+- Polling and webhook both: enqueue then pump
36+ `createTelegramTransportIngressDrain(...).drainOnce()` — no private claim
37+ loops.
38+- Stall timeout: `OPENCLAW_TELEGRAM_SPOOLED_HANDLER_TIMEOUT_MS` →
39+ `adoptionStallTimeoutMs` (default 5 min) via
40+ `resolveTelegramAdoptionStallTimeoutMs`.
41+- Non-retryable classifier: `telegram-ingress-non-retryable.ts`
42+ (missing harness, dispatch-dedupe rollback).
43+- Supersede predicate: `telegram-ingress-supersede.ts` — only abort text /
44+ authorized-looking explicit commands (and ambient room_event pending) may
45+ supersede pre-adoption work. Normal messages never supersede.
46+- room_event ambient work shares the sequential lane so a later user turn can
47+ supersede it pre-adoption; adopted user turns are never touched (core drain
48+ supersede is pre-adoption only).
49+- No per-message full-store writes. Hot-path SQLite writes are per-entry.
50+ Rewriting a cache on every send or read stalls the event loop, and that
51+ stall masquerades as a polling stall (the sent-message-cache regression).
52+- Transport error classification. The getUpdates worker retries Bot API 5xx
53+ and 429 locally, honoring `parameters.retry_after`; 401/404 stay fatal; 409
54+ must propagate to the parent session, which owns webhook-conflict recovery.
55+ Bot API errors carry `error_code`, not `.code`; parse non-2xx bodies
56+ defensively (a 502 HTML page is not JSON).
57+- Send funnel parity. The durable funnel (`send.ts`) and the streaming funnel
58+ (`bot/delivery.*`) must degrade identically: rich-entity 400 falls back to
59+ plain text, caption parse 400 falls back to a plain caption, quote-not-found
60+ 400 falls back to a legacy reply. New recoveries go into the shared
61+ predicates (`send-error-predicates.ts`, `reply-parameters.ts`), never into
62+ one funnel only.
63+- Outbound flood waits honor `retry_after` up to
64+ `TELEGRAM_OUTBOUND_RETRY_AFTER_CAP_MS`; do not re-clamp Telegram sends to the
65+ generic channel retry ceiling.
66+- Webhook security ordering. The secret header is validated first
67+ (constant-time compare, single-header enforcement, connection close on 401);
68+ the request rate limit budgets only failed-auth attempts so Telegram's own
69+ delivery is never throttled.
70+- Every owned undici transport gets closed on all exit paths: polling session,
71+ webhook shutdown and startup failure, probe-cache eviction.
72+ 
73+## Streaming
74+ 
75+- Do not reintroduce `sendMessageDraft` for answer streaming. Telegram drafts
76+ are ephemeral 30-second previews in private chats; final delivery still
77+ requires a separate `sendMessage`. OpenClaw uses `sendMessage` plus
78+ `editMessageText`, then finalizes in place so the user sees one persistent
79+ answer.
80+- Streaming owns one visible preview message. Edit it forward. Do not send an
81+ extra final bubble unless the final edit genuinely failed.
82+- Keep the first-preview debounce. If a provider sends token-sized deltas,
83+ coalesce them into cumulative preview text instead of removing the debounce.
84+- Respect Telegram limits in the Telegram layer. Text over 4096 chars chains
85+ into continuation messages. Polls keep the current Bot API 12-option cap.
86+ 
87+## Telegram API Ownership
88+ 
89+- Prefer grammY primitives and Telegram-native helpers when they model the
90+ behavior directly. Avoid custom Bot API wrappers for behavior grammY already
91+ owns.
92+- Throttling is bot-token scoped. All Telegram API clients for the same token
93+ share one grammY `apiThrottler()` instance.
94+- Do not silently retry failed topic sends without topic metadata. A
95+ wrong-surface success is worse than a loud Telegram error.
96+- DM topics and forum topics are distinct. `direct_messages_topic_id` and
97+ `message_thread_id` are not interchangeable.
98+ 
99+## Context And Authorization
100+ 
101+- Reply context comes from OpenClaw-observed messages. Bot API updates expose
102+ `reply_to_message`, but there is no arbitrary `getMessage(chat, id)`
103+ hydration path later.
104+- Current local chat context must outrank stale reply ancestry in the prompt.
105+ Old replied-to messages should not look like the active conversation.
106+- The group history window is always on for groups and bounded by
107+ `historyLimit`. Do not reintroduce prompt-history gating modes; that
108+ regression blinded ambient rooms.
109+- The group history window is rolling. Use self-entry watermark selection for
110+ "since your last reply" views; do not reintroduce destructive clears because
111+ room events are not persisted to the session and cleared context is
112+ unrecoverable.
113+- Pairing is DM-only. Group and topic authorization need explicit config
114+ allowlists.
115+- Telegram allowlists use numeric sender IDs. Usernames are optional, mutable,
116+ and not a reliable arbitrary-user lookup key in the Bot API.
117+- Group and channel visible replies are policy-controlled. Normal room replies
118+ stay private unless `messages.groupChat.visibleReplies: "automatic"` is set
119+ or the agent explicitly calls `message.send`.
120+ 
121+## Interactive Surfaces
122+ 
123+- Native callbacks stay structured. Approval, native command, plugin, select,
124+ and multiselect callbacks must not fall through as raw callback text.
125+- Preserve callback values exactly, including delimiters such as `env|prod`.
126+- Native slash commands should remain fast-pathable before full workspace and
127+ agent-turn setup.
128+ 
129+## Review Standard
130+ 
131+- Telegram behavior PRs need real Telegram proof when they touch transport,
132+ streaming, topics, callbacks, authorization, or reply context. Prefer the
133+ bot-to-bot QA lane or an equivalent live Telegram probe over synthetic-only
134+ validation.
135+- Reliability PRs (spool, drain, retry, ack, offset paths) need crash-window
136+ or restart-replay test proof, not just happy-path tests.
28137  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack