216 lines
5.4 KiB
Markdown
216 lines
5.4 KiB
Markdown
# 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:<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?
|
|
|
|
## 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`
|