PicoClaw

PicoClaw drops Slack image attachments at the channel edge

A PicoClaw report says Slack sends the image URL as plain text but omits media content, so downstream handling never receives the attachment. Telegram rich-table work and a prompt-cache ordering patch show the same project tightening how structured content crosses channel and context boundaries.

← Back to homeOriginal source ↗

sipeed/picoclaw issue #3338 is the inspected primary source: “[BUG] Slack does not attach image media content.” The related records below were inspected as supporting context rather than independent confirmation.

The facts

- sipeed/picoclaw issue #3338 was created 2026-08-17T00:10:35Z and was open at inspection; its title is “[BUG] Slack does not attach image media content.” - sipeed/picoclaw issue #3325 was created 2026-08-09T13:35:44Z and was open at inspection; its title is “[Feature] Render Telegram tables with rich messages.” - sipeed/picoclaw PR #3321 was created 2026-08-07T06:42:24Z and was open at inspection; its title is “fix(agent): move dynamic context after history to preserve prefix caching.” - The repository reported 29861 stars, 49 open issues, default branch main, and last push 2026-08-14T18:19:48Z. - The latest tagged-release baseline checked was nightly published 2026-07-02T01:26:53Z.

What changed

sipeed/picoclaw issue #3338 reports: Quick Summary Slack media uploads always fail with file.upload.v2: file size cannot be 0. SendMedia builds slack.UploadFileParameters without setting FileSize, so the slack-go SDK rejects every upload before any network call. Environment & Tools **PicoClaw Version:** picoclaw 0.3.1 (git: 2cf030d2) **Go Version:** 1.25.11 **AI Model & Provider:** Ollama - GLM-5.2:cloud **Operating System:** WSL Ubuntu 22.04 **Channels:** Slack Steps to Reproduce 1. Ask agent to generate a chart Actual Behavior The agent generates the chart but cannot send it to slack Expected Behavior The agent sends generated chart to the slack as a media Additional Context Root cause pkg/channels/slack/slack.go:213 builds slack.UploadFileParameters without FileSize, leaving it at zero-value: slack-go v0.23.1 rejects this before any network I/O (files.go:547): The v2 upload flow requires length upfront in files.getUploadURLExternal. The SDK does **not** derive the size from the File path. Likely origin Regression from #2802 (slack-go 0.17.3 → 0.23.0), later pinned by #2875. The legacy files.upload endpoint didn't require a size; the v2 three-step flow does. The call site was never updated. slack_test.go:219 doesn't catch it because it mocks uploadFileFn, bypassing SDK validation. Secondary bug: wrong error classification slack.go:221 maps the failure to channels.ErrTemporary. A deterministic permanent error triggers 3 useless retries (manager.go:1782) and misleads the agent into burning iterations on

sipeed/picoclaw issue #3325 reports: The Goal / Use Case PicoClaw currently sends Telegram replies through the classic sendMessage HTML/MarkdownV2 formatting path. Structured Markdown tables therefore degrade to plain text or monospaced code blocks instead of Telegram's native visual table UI. Telegram Bot API 10.1 introduced rich messages and sendRichMessage, and Bot API 10.2 added outgoing rich block entities such as InputRichBlockTable. PicoClaw should use this capability when a Telegram response contains genuinely tabular data while keeping compatibility with older Bot API servers. Proposed Solution Detect GitHub-Flavored Markdown tables and HTML blocks outside inline/fenced code examples. Send matching replies with sendRichMessage using rich Markdown, which supports both GFM tables and arbitrary supported rich HTML. Preserve reply parameters, forum topic IDs, edits, and streaming finalization. If Telegram rejects rich formatting, fall back first to a readable monospaced table and finally to aligned plain text. Add a Telegram-only output prompt that asks the model to use compact GFM tables for comparisons and repeated-field data. Cover detection, fallbacks, payloads, replies/topics, edits, streaming, and channel-scoped prompting with tests. Potential Implementation (Optional) Upgrade github.com/mymmrac/telego to a Bot API 10.2-compatible release and keep the table parser/delivery logic inside pkg/channels/telegram. Use rich Markdown rather than inventing a messageEntityTable entity; Telegram tables are rich-message blocks, not classic MessageEntity values.

sipeed/picoclaw PR #3321 reports: Description The per-request dynamic context block (## Current Time, ## Runtime, ## Current Session, ## Current Sender) currently sits inside the system message, ahead of the entire conversation history. Prefix caching is positional: changing any token invalidates every cached token after it. A minute-precision clock at the *front* of the prompt therefore invalidates the whole history roughly once per minute. On a host where a turn takes longer than a minute, that cost is paid on **every single turn** — measured at ~2.2 ms per history token, so a 6,000-token history burns about 13 s of pure re-prefill per turn before the model emits anything. This PR moves the block to the tail by default: after the history, carried on the current user message inside a tag. The static system prompt and the full history then stay byte-identical from turn to turn, so backends doing byte-prefix matching keep their KV cache. It also makes the static prompt identical across *all* users, sessions and cron runs, so they share one cached prefix instead of each paying a cold prefill. This matters most for local backends — llama.cpp, Ollama, and other OpenAI-compatible endpoints with no native caching mechanism. Anthropic (per-block cache_control) and OpenAI (prompt_cache_key) have their own mechanisms and are unaffected

Why it matters

An image link is not equivalent to an attached image when tools and models depend on typed media. Channel adapters must preserve content shape, not merely visible text. The operator test is whether the system remains bounded and its receipts still describe the action after failure, retry or restart.

Current

The primary record was open when captured on 2026-08-17. The tagged-release baseline was nightly published 2026-07-02T01:26:53Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.

Evidence

The primary URL is https://github.com/sipeed/picoclaw/issues/3338. Supporting records are https://github.com/sipeed/picoclaw/issues/3325 and https://github.com/sipeed/picoclaw/pull/3321. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.

Source boundary

Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.

Operator take

Normalize inbound media into one typed envelope, verify attachment retrieval and size limits, and keep presentation-only formatting separate from the prompt prefix used for caching. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.

Caveat

Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.

Source inspected; source state, environment and release boundary remain explicit.