fix(napcat): encode bridged images as base64 - #191
Conversation
Convert outbound Image and Record components to base64:// so session bridge file:// copies reach NapCat without sharing AstrBot's filesystem. Fixes #190 AI-Generated: true Generated-At: 2026-09-14T15:07:58Z
Prefer HTTP, existing base64, and NapCat cache names so native echo still works. Encode readable local copies for session bridge, log failures, and omit unreadable filesystem refs. Fixes #190 AI-Generated: true Generated-At: 2026-09-14T16:03:00Z
AI-assisted reviewCannot use GitHub “request changes” on this PR (same author). Treat this as the separate AI review required by VerdictNot ready to merge. The Telegram → NapCat What works
Blocking
for value in candidates:
if _is_raw_filesystem_ref(value):
logger.warning("[NapCat] Omitting unreadable outbound %s", ...)
return NoneInbound NapCat records already look like this (
On a Linux AstrBot host those paths Suggested policy:
Add a regression test with the inbound Record shape above (and an image whose only URL is Non-blocking
Human maintainer review is still required before merge. |
Encode only AstrBot-readable local copies as base64. Unreadable file:// and cache paths belong to NapCat and stay pass-through. Fixes #190 AI-Generated: true Generated-At: 2026-09-14T22:08:23Z
Summary
/session watchand/session connectforwarded Telegram photos into NapCatQQ as unusablefile://URIs. NapCat now encodes readable localImageandRecordcopies asbase64://, so the OneBot process does not need AstrBot's filesystem. HTTP, existingbase64://, and NapCat cache names still pass through.Related issue
Fixes #190
Root cause
Session bridge materializes deferred Telegram media to a temp
file://copy. NapCat_append_media_outbound_segmentcopiedfile/pathinto the OneBot image segment. A NapCat process in another container or on another host cannot read the AstrBot path.The first patch encoded every image and record. That dropped native NapCat cache names, downloaded HTTP URLs AstrBot may not be able to fetch, and swallowed encoding failures without a log.
Reproduction
/session watch <telegram_umo>.Unit: a local
Image.fromFileSystemor delivery-styleImage(file=uri, path=uri)through_build_outbound_messagepreviously emittedfile:///.../data/temp/bridge-*/0.jpg.Implementation notes
Local and
file://copies that AstrBot can read are encoded asbase64://. HTTP, existingbase64://, and bare NapCat cache names pass through, including originalurl/pathon the segment. Unreadable filesystem refs and encoding failures omit the media, log a redacted warning, and insert a generic[Image]/[Record]text placeholder instead of forwarding a path. Video and File stay pass-through, same as aiocqhttp. Telegram download failure still degrades to the existing unavailable placeholder.Validation
The ruff, pytest (106 passed), and Prettier commands passed in this session. markdownlint reported no issues on the two docs pages.
make checkandmake test-blockingwere not run.Compatibility and risk
Public API unchanged. Large local images still inflate OneBot WebSocket frames. HTTP images are no longer downloaded by AstrBot. Video/File are unchanged and can still fail across hosts.
Checklist
docs/zh/anddocs/en/when needed.docs/public/openapi.json, and tests change together when routes or schemas change.pyproject.toml,requirements.txt, anduv.locktogether.!and aBREAKING CHANGE:footer.Agent note
Goal: make
/sessionTelegram photos arrive on NapCatQQ without regressing native NapCat echo. Review of PR #191 found unconditional base64 encoding and silent failure swallows. Touchednapcat_platform_adapter.py(_portable_media_file,_append_media_outbound_segment),tests/unit/platform/test_napcat_outbound.py, and the NapCat rows indocs/zh/dev/plugin-platform-adapter.mdanddocs/en/dev/plugin-platform-adapter.md. Residual risk: Video/File still use pass-through URIs; Telegramget_filedownload failure is a separate placeholder path. Tools: OpenCode / grok-4.6, ruff, pytest, Prettier.