Summary
The Multica agent cannot read images (or any uploaded files) posted in a Slack channel. Uploaded files on a Slack message (slack.Message.Files) are ignored on every path — real-time ingest and on-demand history reads alike. The agent only ever receives plain text, so a shared image is never downloaded, stored, or even surfaced as a text hint that "an image exists here."
This is a missing capability, not a regression — there is no Slack image/file handling implemented anywhere. Filing so other users hitting the same thing know it's a known gap.
Impact / how it shows up
- Post an image only (no caption) in a channel/DM the bot is in → the message is dropped entirely; the agent doesn't even know an image was sent.
- Post an image with a caption → the agent sees only the caption text; the image is invisible (no URL, no filename, not even an
[image] placeholder).
- In a channel/group, an image with no
@bot mention is not ingested at all.
Where it happens (root cause)
Two independent code paths, same gap — m.Files is never read:
1. Real-time ingest — server/internal/integrations/slack/inbound.go
buildInbound() normalizes every Slack message to Type: channel.MsgTypeText and copies only the text; m.Files is never touched and MediaRefs stays empty. The file_share subtype flows through the same text-only path.
- Group messages are only treated as addressed-to-bot when the text
@mentions the bot, so an image-only channel post isn't ingested.
- Persistence (
server/internal/integrations/channel/engine/session.go, AppendUserMessage → CreateChatMessage) stores only the text Content; no media is stored.
2. On-demand history read (multica chat history / multica chat thread) — server/internal/integrations/slack/history.go
flattenSlackText() builds text from top-level text → attachments → Block Kit blocks, and never reads m.Files.
- An image-only message flattens to
"" and is dropped as a system/join marker in normalizePage (if text == "" { continue }).
- The agent-facing contract
channel.HistoryMessage (server/internal/integrations/channel/history.go) has only a Text field — no media field — so even a willing reader can't express an image in the current shape.
Cross-platform note
channel.MediaRef / channel.MsgTypeImage exist but are effectively unused scaffolding — no adapter populates MediaRefs and nothing downstream consumes it. Feishu/Lark maps the MsgType enum but likewise stores text only. So no channel currently delivers media to the agent; Slack is just where users hit it first. There is also no Slack file-download code (nothing fetches url_private with the bot token). slack-go already exposes url_private / url_private_download / mimetype / permalink on File; none of it is used today.
Suggested direction
- Stop-gap: in
flattenSlackText, emit a text placeholder for m.Files (e.g. [image: foo.png], optionally with permalink) so image-only messages are no longer dropped and the agent knows an image exists and can follow the link. Add a media field to HistoryMessage.
- Full solution: capture
m.Files into MediaRefs, download via url_private (bot-token auth) into object storage, and feed images into the agent's multimodal context — the cross-platform media support MediaRef was originally scaffolded for.
Internal ref: MUL-4359
Summary
The Multica agent cannot read images (or any uploaded files) posted in a Slack channel. Uploaded files on a Slack message (
slack.Message.Files) are ignored on every path — real-time ingest and on-demand history reads alike. The agent only ever receives plain text, so a shared image is never downloaded, stored, or even surfaced as a text hint that "an image exists here."This is a missing capability, not a regression — there is no Slack image/file handling implemented anywhere. Filing so other users hitting the same thing know it's a known gap.
Impact / how it shows up
[image]placeholder).@botmention is not ingested at all.Where it happens (root cause)
Two independent code paths, same gap —
m.Filesis never read:1. Real-time ingest —
server/internal/integrations/slack/inbound.gobuildInbound()normalizes every Slack message toType: channel.MsgTypeTextand copies only the text;m.Filesis never touched andMediaRefsstays empty. Thefile_sharesubtype flows through the same text-only path.@mentionsthe bot, so an image-only channel post isn't ingested.server/internal/integrations/channel/engine/session.go,AppendUserMessage→CreateChatMessage) stores only the textContent; no media is stored.2. On-demand history read (
multica chat history/multica chat thread) —server/internal/integrations/slack/history.goflattenSlackText()builds text from top-level text → attachments → Block Kit blocks, and never readsm.Files.""and is dropped as a system/join marker innormalizePage(if text == "" { continue }).channel.HistoryMessage(server/internal/integrations/channel/history.go) has only aTextfield — no media field — so even a willing reader can't express an image in the current shape.Cross-platform note
channel.MediaRef/channel.MsgTypeImageexist but are effectively unused scaffolding — no adapter populatesMediaRefsand nothing downstream consumes it. Feishu/Lark maps theMsgTypeenum but likewise stores text only. So no channel currently delivers media to the agent; Slack is just where users hit it first. There is also no Slack file-download code (nothing fetchesurl_privatewith the bot token). slack-go already exposesurl_private/url_private_download/mimetype/permalinkonFile; none of it is used today.Suggested direction
flattenSlackText, emit a text placeholder form.Files(e.g.[image: foo.png], optionally withpermalink) so image-only messages are no longer dropped and the agent knows an image exists and can follow the link. Add a media field toHistoryMessage.m.FilesintoMediaRefs, download viaurl_private(bot-token auth) into object storage, and feed images into the agent's multimodal context — the cross-platform media supportMediaRefwas originally scaffolded for.Internal ref: MUL-4359