AGENTS.md
extensions/telegram/AGENTS.mdAGENTS.md
Quality
59/100
Scores the file, not the repository.Length
943 words
9 headings · 0 code blocksRepository
385k
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.1# Telegram Plugin Guide23Read this before any change under `extensions/telegram/`. These are intentional4maintainer decisions and review-binding invariants, not incidental5implementation details. Also read `extensions/AGENTS.md` for the plugin6boundary rules.78Verified against Telegram Bot API 10.2, July 14 2026.910## Reliability Invariants1112### Core drain contracts (do not re-implement in Telegram)1314Owned 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`.1718- Completed rows tombstone via `complete()`, never `delete`.19- Complete at turn adoption, not settle. Deferred holds the claim; watchdog20 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-owned25 (reply-run registry / queue interrupt).2627### Telegram-owned (transport + channel policy)2829- Durable-before-ack on both transports. Polling: ingress worker advances its30 offset only after the parent's committed spool enqueue31 (`writeTelegramSpooledUpdate`). Webhook: respond 200 only after the spool32 write; non-200 on write failure is the redelivery contract.33- `update_id`↔event-id encoding and per-chat/topic lane derivation stay in34 `telegram-ingress-spool.ts` / sequential-key.35- Polling and webhook both: enqueue then pump36 `createTelegramTransportIngressDrain(...).drainOnce()` — no private claim37 loops.38- Stall timeout: `OPENCLAW_TELEGRAM_SPOOLED_HANDLER_TIMEOUT_MS` →39 `adoptionStallTimeoutMs` (default 5 min) via40 `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) may45 supersede pre-adoption work. Normal messages never supersede.46- room_event ambient work shares the sequential lane so a later user turn can47 supersede it pre-adoption; adopted user turns are never touched (core drain48 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 that51 stall masquerades as a polling stall (the sent-message-cache regression).52- Transport error classification. The getUpdates worker retries Bot API 5xx53 and 429 locally, honoring `parameters.retry_after`; 401/404 stay fatal; 40954 must propagate to the parent session, which owns webhook-conflict recovery.55 Bot API errors carry `error_code`, not `.code`; parse non-2xx bodies56 defensively (a 502 HTML page is not JSON).57- Send funnel parity. The durable funnel (`send.ts`) and the streaming funnel58 (`bot/delivery.*`) must degrade identically: rich-entity 400 falls back to59 plain text, caption parse 400 falls back to a plain caption, quote-not-found60 400 falls back to a legacy reply. New recoveries go into the shared61 predicates (`send-error-predicates.ts`, `reply-parameters.ts`), never into62 one funnel only.63- Outbound flood waits honor `retry_after` up to64 `TELEGRAM_OUTBOUND_RETRY_AFTER_CAP_MS`; do not re-clamp Telegram sends to the65 generic channel retry ceiling.66- Webhook security ordering. The secret header is validated first67 (constant-time compare, single-header enforcement, connection close on 401);68 the request rate limit budgets only failed-auth attempts so Telegram's own69 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.7273## Streaming7475- Do not reintroduce `sendMessageDraft` for answer streaming. Telegram drafts76 are ephemeral 30-second previews in private chats; final delivery still77 requires a separate `sendMessage`. OpenClaw uses `sendMessage` plus78 `editMessageText`, then finalizes in place so the user sees one persistent79 answer.80- Streaming owns one visible preview message. Edit it forward. Do not send an81 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 chains85 into continuation messages. Polls keep the current Bot API 12-option cap.8687## Telegram API Ownership8889- Prefer grammY primitives and Telegram-native helpers when they model the90 behavior directly. Avoid custom Bot API wrappers for behavior grammY already91 owns.92- Throttling is bot-token scoped. All Telegram API clients for the same token93 share one grammY `apiThrottler()` instance.94- Do not silently retry failed topic sends without topic metadata. A95 wrong-surface success is worse than a loud Telegram error.96- DM topics and forum topics are distinct. `direct_messages_topic_id` and97 `message_thread_id` are not interchangeable.9899## Context And Authorization100101- Reply context comes from OpenClaw-observed messages. Bot API updates expose102 `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 by107 `historyLimit`. Do not reintroduce prompt-history gating modes; that108 regression blinded ambient rooms.109- The group history window is rolling. Use self-entry watermark selection for110 "since your last reply" views; do not reintroduce destructive clears because111 room events are not persisted to the session and cleared context is112 unrecoverable.113- Pairing is DM-only. Group and topic authorization need explicit config114 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 replies118 stay private unless `messages.groupChat.visibleReplies: "automatic"` is set119 or the agent explicitly calls `message.send`.120121## Interactive Surfaces122123- 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 and127 agent-turn setup.128129## Review Standard130131- Telegram behavior PRs need real Telegram proof when they touch transport,132 streaming, topics, callbacks, authorization, or reply context. Prefer the133 bot-to-bot QA lane or an equivalent live Telegram probe over synthetic-only134 validation.135- Reliability PRs (spool, drain, retry, ack, offset paths) need crash-window136 or restart-replay test proof, not just happy-path tests.137
Also in openclaw/openclaw
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| openclaw/openclawsrc/agents/embedded-agent-runner/run/AGENTS.md · 385k | AGENTS.md | teststyleperformance | 47/100 | 3 days ago | |
| openclaw/openclawsrc/agents/tools/AGENTS.md · 385k | AGENTS.md | testperformanceagent-behaviour | 51/100 | 3 days ago | |
| openclaw/openclawsrc/plugin-sdk/AGENTS.md · 385k | AGENTS.md | styledo-not | 67/100 | 3 days ago | |
| openclaw/openclawsrc/plugins/AGENTS.md · 385k | AGENTS.md | styledo-not | 62/100 | 3 days ago | |
| openclaw/openclawtest/helpers/AGENTS.md · 385k | AGENTS.md | buildteststyle | 51/100 | 3 days ago | |
| openclaw/openclawscripts/AGENTS.md · 385k | AGENTS.md | teststylegitsecurity+1 | 83/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| n8n-io/n8npackages/@n8n/agents/AGENTS.md · 199k | AGENTS.md | buildteststylearch+3 | 100/100 | 3 days ago | |
| TryGhost/Ghoste2e/AGENTS.md · 55k | AGENTS.md | setupteststylearch+2 | 100/100 | 3 days ago | |
| duckduckgo/content-scope-scriptsspecial-pages/AGENTS.md · 70 | AGENTS.md | buildteststylearch+3 | 100/100 | 3 days ago | |
| mui/material-uiAGENTS.md · 99k | AGENTS.md | setupbuildtestlint-format+9 | 100/100 | 3 days ago | |
| aaif-goose/gooseAGENTS.md · 52k | AGENTS.md | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| wpscanteam/wpscanAGENTS.md · 9.7k | AGENTS.md | setupbuildteststyle+6 | 100/100 | 2 days ago | |
| trick77/agents-md-syncAGENTS.md · 2 | AGENTS.md | setupbuildteststyle+5 | 100/100 | 3 days ago | |
| code-yeongyu/oh-my-openagentpackages/web/AGENTS.md · 67k | AGENTS.md | setupbuildtestlint-format+6 | 100/100 | 2 days ago |
