Files
reply-end-controls/telegram-v1-design.md

5.4 KiB

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:

{
  "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:<messageId>
  • rec:stop:<messageId>

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?

Suggested V1 layout:

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