[Bug] ZCode Telegram bot: media album (multiple photos) only keeps 1 image in desktop session
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 22
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
Summary
Sending multiple photos as one Telegram album to a linked ZCode desktop bot results in only one image appearing in the desktop session (attachmentCount: 1).
The host does receive every album part as a separate Telegram update, but:
- It does not aggregate
media_group_id - The first photo starts a task
- Later album parts hit the
taskRunningguard and are dropped without attaching images
This is a product/runtime bug in the built-in Telegram bot host path, not a UI-only rendering issue, and not a network/token issue.
Environment
| Item | Value |
|---|---|
| OS | macOS (Apple Silicon) |
| ZCode | 3.3.6 (3.3.6.3198, bundle id dev.zcode.app) |
| Feature | Built-in Telegram bot (long polling) |
| Related bot id (local) | bot-b9ccebcd-20ec-49a0-a160-6c208ce9b4de |
| Model channel | custom / OpenAI-compatible (repro is independent of model) |
Steps to reproduce
- Link a Telegram bot in ZCode desktop and bind a user.
- In Telegram, select 3+ photos and send them as one album (optional caption on the first photo / album).
- Optionally include a short text caption describing the images.
- Open the corresponding session on the ZCode desktop.
Expected
- One user turn in the desktop session
- All album photos attached (up to any documented attachment limit, e.g. 4)
- Caption / text appears once
Actual
- Desktop session shows only 1 image (usually the first / captioned one)
sendPromptlogsattachmentCount: 1- Remaining album parts are received by the bot runtime as extra
provider callbackevents with empty text, but never reach a multi-attachmentsendPrompt - Local attachment cache under
~/.zcode/v2/bot-attachments/<botId>/typically contains only one*-telegram-photo.jpg
Evidence (local logs, 2026-07-28)
From ~/.zcode/v2/logs/2026-07-28.log (timestamps local):
12:39:55 [bots] provider callback provider=telegram ... text=<user caption / question>
12:40:00 [zcode-task-service] sendPrompt 开始 {"attachmentCount":1, ...}
12:40:00 [zcode-agent-service] session/send 开始 {"attachmentCount":1, ...}
12:40:00 [bots] provider callback provider=telegram ... text= # empty caption photo #2
12:40:01 [bots] provider callback provider=telegram ... text= # empty caption photo #3
12:40:02 [bots] provider callback provider=telegram ... text= # empty caption photo #4
12:40:03 [bots] provider callback provider=telegram ... text= # empty caption photo #5
So:
- Multiple photo updates arrive at the host
- Only one prompt is sent, with a single attachment
- Later parts are not merged into that prompt
Root cause analysis (ZCode 3.3.6 host bundle)
Inspected packaged host code:
/Applications/ZCode.app/Contents/Resources/app.asar → out/host/index.js
1) Telegram album shape vs ZCode parsing
Telegram Bot API media albums are N separate message updates sharing media_group_id (usually only one has caption). They are not one message with N photos.
ZCode's readTelegramPrivateMessage / parseCallback path:
- Reads a single
update.message - Takes
textorcaption - Builds attachments from that one message only
- Sets
providerMessageIdfrom that message'smessage_id - Never reads
media_group_id - Host bundle has no
media_group/mediaGroup/media_group_id/ album aggregation logic
readTelegramPhotoAttachment correctly treats message.photo[] as multi-resolution of one image (at(-1) largest), not multi-image album.
2) First photo starts task; later parts rejected
handleMessage roughly:
if mode==task && activeTaskId && isContextActiveTaskRunning(context):
return taskRunning reply # do not process attachments
resolveInboundAttachments(...)
create/resume task + sendPromptInBackground(...)
Album timeline becomes:
| Order | Update | Behavior |
|---|---|---|
| #1 (often with caption) | create/start task, attachmentCount: 1 |
visible on desktop |
| #2..N (empty caption) | task already running | dropped by taskRunning path |
Per-actor inbound queue serializes handling, so later parts almost always see a running task after #1.
3) Secondary limits (not primary cause)
- Per-inbound attachment cap (
Vre = 4) - Per-file size cap (
5MB) - Long poll
allowed_updates: ["message","callback_query"]is fine for photos
Primary bug is missing media-group aggregation + running-task rejection of later album members.
Single-photo download path works (first image caches successfully), so this is not explained by token/proxy failure alone.
Suggested fix
- Media group buffer in Telegram provider / before
handleInboundMessage:- If
message.media_group_idpresent → buffer parts for ~800–1500ms (max wait ~5s) - On flush: merge non-empty caption/text once; concatenate attachments; sort by
message_id - Call inbound handling once
- If
- Use dedupe key like
providerMessageId = media_group:${media_group_id} - Do not apply
taskRunningto partial group members before flush - Keep attachment max (4) / 5MB limits, but prefer partial success + clear bot notice over silent drop
- Add logs:
media_group buffer start/flush parts=N attachments=M
Pseudo:
// on update with media_group_id:
buffer[botId:groupId].parts.push(parsed)
resetFlushTimer(1000)
// on flush:
merged = {
text: firstNonEmptyCaption(parts),
attachments: parts.flatMap(p => p.attachments).slice(0, 4),
actor.providerMessageId: `media_group:${groupId}`,
}
handleInboundMessage(merged)
Only relaxing taskRunning without aggregation is not enough (would create N separate prompts).
Workarounds (until fixed)
- Send photos one by one, after previous task finishes (or
/stop) - Send a single long screenshot / PDF / zip as document
- Avoid Telegram album multi-select for ZCode bot input
Why this matters
Remote Telegram control is a headline ZCode workflow. Users often send multiple screenshots for UI/code comparison. Silently keeping 1/N images causes wrong agent context with no obvious failure.
Attachments / extra detail
Happy to provide full log excerpts, attachment-cache listing, or a redacted host-path map if useful.
Related local write-up (for maintainers / power users): media-group aggregation missing in host Telegram runtime on 3.3.6.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with out/host/index.js in the packaged app.asar and trace readTelegramPrivateMessage, parseCallback, and handleMessage. Reproduce the album flow using the logs and verify that media_group_id updates are combined into one inbound task, with the caption once and up to four attachments, rather than being rejected by taskRunning.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100