forked from admin/VolcanicAgenticCore
docs(telegram): message context, grouping and presence
InputDebounce config row, the Using it section (replies, quotes, forwards, local-time header, grouping window, eyes reaction, online message, forwards never count as the login code), the Inbound paragraph in CLAUDE.md, and spec status set to implemented.
This commit is contained in:
@@ -94,7 +94,10 @@ and `ClaudeCode` + `ClaudeCode.Bridge`. The Claude Code provider is the most int
|
||||
|
||||
Long polling (`Polling/`, with `ReconnectPolicy` backoff). Each private chat gets its own `AgentSession`
|
||||
(`Chats/ChatRegistry`), with workspace `<WorkspaceRoot>/<chatId>` and session scope `telegram-<chatId>`. Access is
|
||||
limited by `AllowedUserIds`. The first allowed id is the "owner": `OwnerLoginChannel` sends Claude Code re-login
|
||||
limited by `AllowedUserIds`. Incoming messages go through `Inbound/`: the router takes a `ChatInbox` lease per
|
||||
message in update order, `InboundComposer` builds its part (reply/forward headers from `MessageContext`, text and
|
||||
photo) in the background, and the inbox flushes a batch `InputDebounce` (600 ms) after the last message as one prompt
|
||||
with a local-time header. The first allowed id is the "owner": `OwnerLoginChannel` sends Claude Code re-login
|
||||
prompts to that chat. It resolves lazily to break the DI cycle ChatRegistry → session factory → extension → ChatRegistry.
|
||||
Answers go out complete, not streamed (`Rendering/`). Tests drive the host through `Support/FakeBotClient` and `ChatHost`.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Telegram message context, grouping and presence — design
|
||||
|
||||
Date: 2026-09-26
|
||||
Status: draft
|
||||
Status: implemented
|
||||
Depends on: `2026-09-26-telegram-attachments-design.md`, which plugs its content steps (files, speech) into
|
||||
`InboundComposer` and uses the renderer's `RunInOrderAsync` for notices and the `🎤` echo.
|
||||
Also `2026-09-26-scheduler-design.md` §7 (`ChatSettingsStore`, the chat's time zone for the timestamp header; if this spec
|
||||
|
||||
@@ -31,6 +31,7 @@ Environment variables, or the `Telegram` section of `appsettings.json` (`Telegra
|
||||
| `Telegram:WorkspaceRoot` | `~/.volcanic/telegram-workspaces` | Chat `<id>` works in `<root>/<id>`; put `AGENTS.md`, `PERSONA.md`, `MEMORY.md` there |
|
||||
| `Telegram:Model` | `claude-code/claude-opus-5-5` | Any `provider/model` the Claude Code provider serves |
|
||||
| `Telegram:EditInterval` | `00:00:01.5` | Minimum time between edits of the "Working..." status message |
|
||||
| `Telegram:InputDebounce` | `00:00:00.6` | How long the bot waits after a message for more before sending them to the agent as one request. `0` sends each message on its own. Must not be negative |
|
||||
| `Telegram:ReconnectInitialDelay` / `ReconnectMaxDelay` | `1 s` / `60 s` | Backoff after lost connection |
|
||||
| `PROCESS_ENV_ALLOW` | — | Comma-separated names or globs let through to `bash`, scheduled scripts and MCP servers despite the deny-list (e.g. `GH_TOKEN` for `gh`). Added to `ProcessEnvironment:Allow` |
|
||||
| `ProcessEnvironment:Deny` / `ProcessEnvironment:Allow` | built-in deny-list | Added to the defaults (`*_API_KEY`, `*_TOKEN`, `*_SECRET`, `*_PASSWORD`, their `Section__Key` forms and the named provider credentials), never replacing them. Allowing a name that is denied by name stops startup |
|
||||
@@ -53,7 +54,22 @@ Write normally. While the agent works, a status message stays at the bottom of t
|
||||
It lists the last five tool calls (`▶` running, `✓` done, `✗` failed) and is deleted when the run finishes.
|
||||
Answers are not streamed: each one is sent complete when the model finishes it (split into several messages past
|
||||
Telegram's 4096 character limit).
|
||||
A message sent while the agent works steers the current run. Photos (with or without a caption) are passed to the model.
|
||||
A message sent while the agent works steers the current run, and the bot reacts to it with 👀 so you can see it was
|
||||
added. Photos (with or without a caption) are passed to the model.
|
||||
|
||||
Along with your text, the agent sees:
|
||||
|
||||
- **Replies and quotes.** Reply to one of the bot's messages (or one of yours), or quote part of it, and the agent gets
|
||||
a line such as `[Reply to your message: "Which plant do you mean?"]` before your text.
|
||||
- **Forwards**, labelled with their source: `[Forwarded from Daily News (Anna K.)]`.
|
||||
- **The local time** you sent the message, in the chat's time zone (for now, the zone of the machine running the bot):
|
||||
`[Sat 2026-09-26 14:03 Europe/Berlin]`, once per request.
|
||||
|
||||
Messages sent within about 0.6 s of each other (`Telegram:InputDebounce`), such as a forward with your comment or
|
||||
an album, reach the agent as one request. Every message waits that long before it's sent.
|
||||
|
||||
After a start the bot sends `🟢 Online.` to the owner (the first id in `AllowedUserIds`), once. If the owner never
|
||||
started a chat with the bot, Telegram refuses the message; the bot logs that and carries on.
|
||||
|
||||
| Command | |
|
||||
|---|---|
|
||||
@@ -74,9 +90,9 @@ gets the re-login link and code prompt in their own private chat, regardless of
|
||||
it. That user must already have started a chat with the bot — Telegram bots cannot message a user first — or
|
||||
the login goes unanswered and the triggering request fails ("no code was entered"). The link, the steps and the
|
||||
code prompt arrive as one message. While that prompt is pending, the owner's next plain text message in that chat
|
||||
is taken as the code and is not sent to the agent; photos and `/commands` still behave normally. Don't ask the bot
|
||||
something else in the owner chat until the code is in: a second free-text question in that chat (for example from
|
||||
an extension) replaces the pending prompt and cancels the login. See
|
||||
is taken as the code and is not sent to the agent; photos and `/commands` still behave normally. A forwarded message
|
||||
never counts as the code. Don't ask the bot something else in the owner chat until the code is in: a second free-text
|
||||
question in that chat (for example from an extension) replaces the pending prompt and cancels the login. See
|
||||
[claude-code-provider.md](claude-code-provider.md#session-expiry-and-re-login).
|
||||
|
||||
## Security
|
||||
|
||||
Reference in New Issue
Block a user