* fix(qqbot): allow scoped sandbox media sends
* fix(qqbot): thread scoped media access through all outbound paths
Cover the seven QQBot outbound media paths that dropped core scoped
sandbox media access: gateway block/tool/streaming deliver, direct
text qqmedia tags, structured QQBOT_PAYLOAD, and the scoped workspace
relative/missing-voice path resolution. The low-level sendPhoto /
sendVideoMsg / sendDocument now consume core mediaAccess.readFile via
the shared outbound loader with explicit localRoots guard, so
host-mediated workspace media can be sent without widening QQBot FS
access. Voice stays on the existing SILK transcode path to avoid
bypassing QQ-required format conversion.
* fix(qqbot): thread workspaceDir into gateway reply media context
Gateway dispatchOutbound previously built gatewayMediaContext with only
mediaLocalRoots, so a sandboxed block reply that carried a relative
media tag (e.g. <qqmedia>report.docx</qqmedia>) reached the downstream
sender without mediaAccess.workspaceDir and was rejected by containment
checks before the file could be resolved against the agent workspace.
Resolve the agent workspace dir via the public plugin-sdk agent-runtime
helper and pass it through mediaAccess.workspaceDir alongside the
existing mediaLocalRoots so the gateway block reply, tool forwarding,
QQBOT_PAYLOAD, and official C2C streaming paths all share the same
scoped workspace resolution as direct outbound sends. No public plugin
SDK boundary is widened; the helper is an existing export.
Add a regression test that exercises a relative <qqmedia> tag in a
gateway block reply and confirms it resolves against the configured
agent workspace.
* fix(qqbot): wrap host-read media sends with structured error handling
* fix(qqbot): preserve host-read media quota errors
* fix(qqbot): preserve host-read quota fallback path
* fix(qqbot): resolve host-read quota fallback path
* test(qqbot): satisfy host-read media lint
* fix(qqbot): cover host-read voice media
* fix(qqbot): satisfy host-read voice lint
* Drop incidental formatting from PR merge
Keep the conflict-resolution update scoped to the QQBot media send files.
* fix(qqbot): map sandbox workspace media paths
* fix(qqbot): preserve host-read media roots
* fix(qqbot): scope sandbox media delivery roots
* fix(qqbot): map virtual media roots before host read
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(qqbot): scope structured payload media roots
* fix(qqbot): keep auto media helper internal
* docs(changelog): note QQBot scoped sandbox media fix (#92872) (thanks @zhangguiping-xydt)
---------
Co-authored-by: sliverp <870080352@qq.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Addressed source-reply turns now carry the message-tool-only delivery hint in runtime prompt context, matching the room-event per-turn contract without persisting the hint into transcript rows.
Surface: auto-reply prompt envelopes and agent messaging guidance. Fixes#99371.
Release-note: fixes Telegram group replies under message_tool_only delivery being composed privately instead of being prompted to use message(action=send).
Ambient transcript watermarks now carry the transcript session id, resolve only for the current session entry, and skip stale room-event hooks that no longer match the prepared transcript session.
This protects Telegram group prompt windows after reset by backfilling rows that are no longer present in the new session transcript, while preserving steady-state watermark filtering within one session.
Fixes#99373
Release-note: fixes Telegram group context loss after session reset when ambient transcript watermarks outlived the transcript they referenced.