zai-org / zai-org/feedback

[Bug] ZCode Telegram bot: media album (multiple photos) only keeps 1 image in desktop session

Open
#198 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

priority: P2
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:

  1. It does not aggregate media_group_id
  2. The first photo starts a task
  3. Later album parts hit the taskRunning guard 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

  1. Link a Telegram bot in ZCode desktop and bind a user.
  2. In Telegram, select 3+ photos and send them as one album (optional caption on the first photo / album).
  3. Optionally include a short text caption describing the images.
  4. 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)
  • sendPrompt logs attachmentCount: 1
  • Remaining album parts are received by the bot runtime as extra provider callback events with empty text, but never reach a multi-attachment sendPrompt
  • 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.asarout/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 text or caption
  • Builds attachments from that one message only
  • Sets providerMessageId from that message's message_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

  1. Media group buffer in Telegram provider / before handleInboundMessage:
    • If message.media_group_id present → 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
  2. Use dedupe key like providerMessageId = media_group:${media_group_id}
  3. Do not apply taskRunning to partial group members before flush
  4. Keep attachment max (4) / 5MB limits, but prefer partial success + clear bot notice over silent drop
  5. 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)

  1. Send photos one by one, after previous task finishes (or /stop)
  2. Send a single long screenshot / PDF / zip as document
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.