# reply-end-controls - Telegram V1 Design ## Scope This project is Telegram-only. No Discord, Slack, or cross-channel abstraction is part of V1. However, the internal architecture should still be **plugin-oriented and reusable** so that multiple agents can adopt the same reply-end-controls behavior later without rewriting the logic. ## Product behavior At the end of every assistant reply sent to Telegram, attach two inline buttons: - `A. 繼續` - `B. 就這樣吧,不需要額外處理` Button selection must be captured and stored in conversation/session state. If the user types a new message instead of pressing a button, the typed message takes priority. ## V1 rules ### Rule 1 Every assistant reply gets reply-end buttons. ### Rule 2 If the user taps `繼續`: - store `lastChoice=continue` - allow follow-up behavior on later turns ### Rule 3 If the user taps `就這樣吧,不需要額外處理`: - store `lastChoice=stop` - suppress unnecessary continuation behavior on later turns ### Rule 4 If the user sends a new typed message, that input overrides the button state. ### Rule 5 After a button is clicked, the original message buttons should be updated so the selection is visually resolved and repeated clicks are reduced. ## State model Store this in Telegram conversation/session state: ```json { "replyEndControls": { "lastChoice": "continue | stop", "lastChoiceAt": "ISO timestamp", "sourceMessageId": "telegram message id", "sourceCallbackId": "telegram callback query id", "active": true } } ``` ## Telegram callback payloads Suggested callback data format: - `rec:continue` - `rec:stop` If message-scoped state is needed later, extend to: - `rec:continue:` - `rec:stop:` ## Technical flow ### Outbound reply flow 1. Assistant reply text is produced. 2. Telegram reply payload is decorated with inline keyboard. 3. Message is sent to Telegram. ### Callback flow 1. User clicks button. 2. Telegram sends callback query. 3. Callback handler parses `continue` or `stop`. 4. State is persisted. 5. Original message buttons are updated to reflect the chosen option. ### Next-turn behavior 1. A later turn begins. 2. Runtime checks `replyEndControls.lastChoice`. 3. If `stop`, do not proactively extend or continue the previous thread unless the user explicitly asks. 4. If `continue`, normal continuation behavior is allowed. ## Suggested implementation modules ### 1. Reply decorator Responsibility: - append Telegram inline keyboard to every assistant reply ### 2. Callback handler Responsibility: - receive Telegram callback queries - parse reply-end action - update state ### 3. State storage helper Responsibility: - persist and retrieve the latest reply-end selection for the current conversation/session ### 4. Behavior policy hook Responsibility: - inspect `lastChoice` - suppress proactive continuation when `stop` is active ## Plugin-oriented design goal Even though V1 is Telegram-only, implementation should be split so the feature can be reused by other agents. ### Required separation #### A. Channel-specific layer Telegram-only code: - inline keyboard rendering - callback query parsing - Telegram message edit/update behavior #### B. Agent-neutral control core Reusable logic: - reply-end choice state model - state persistence rules - Continue/Stop behavior policy - helpers for reading and updating `lastChoice` #### C. Agent integration adapter Per-agent integration points: - how a given agent/runtime appends controls to replies - how a given agent/runtime consults the stored choice before later turns This means V1 should not hard-code every behavior directly into Telegram handlers. Telegram should be the transport/integration layer, while the choice model and policy logic should stay reusable. ## Multi-agent reuse target The design should make it possible for future agents to reuse the same core with minimal custom work: - Agent A: Telegram assistant using OpenClaw - Agent B: another Telegram bot runtime - Agent C: future Slack/Discord version, if ever needed later The shared core should answer: - what choice was made? - when was it made? - is the conversation currently in `continue` or `stop` mode? - should the next assistant turn suppress proactive continuation? ## Recommended code layout Suggested V1 layout: ```text reply-end-controls/ ├── README.md ├── telegram-v1-design.md ├── core/ │ ├── state-model.md │ ├── policy.md │ └── callback-contract.md ├── telegram/ │ ├── reply-decorator.md │ ├── callback-handler.md │ └── message-update.md └── adapters/ └── openclaw.md ``` V1 does not need all of these files implemented yet, but the structure should guide the implementation so transport-specific code does not swallow the reusable core. ## Acceptance criteria for V1 V1 is complete when all of the following are true: 1. A normal Telegram assistant reply shows both buttons. 2. Clicking `繼續` is received and stored. 3. Clicking `就這樣吧,不需要額外處理` is received and stored. 4. After click, the original message is updated to show the choice state. 5. A new typed user message still works without pressing any button. 6. A later turn can read the stored choice and alter continuation behavior. ## Non-goals for V1 - multi-channel abstraction - governance integration - analytics dashboard - complex branching controls beyond `continue` and `stop`