feat(agent): multimodal prompt — native image/audio content blocks gated by promptCapabilities - #774
Merged
Merged
Conversation
added 7 commits
August 4, 2026 19:29
…dia partition - SendMessageData stays unchanged; partition happens at the dispatch layer (the only layer that knows the target agent's capabilities), mirroring the aionrs strip-and-rebuild precedent in manager/aionrs/content.rs. - IAgentTask::prompt_media_caps() (default none) implemented by AcpAgentManager (initialize promptCapabilities) and SessionAgentTask (backend prompt_blocks). - media::partition_media splits attachments into native-block media vs path files, rewriting the [[AION_FILES]] block to the exact resolve_chat_message format; SVG, oversized (>5MB), unreadable, and capability-less attachments degrade to paths byte-identically.
build_prompt_blocks partitions attachments by the agent's declared promptCapabilities: capable media rides as base64 ImageContent/AudioContent blocks (uri: file://path) after the text block; everything else stays in the [[AION_FILES]] path list byte-identical to the previous wire form. Any read failure degrades the whole prompt back to the plain text form. Transport is LinesCodec::new() (unbounded) on both sides, so multi-MB frames pass unchanged.
…blocks SessionAgentTask::send_message now partitions attachments through the same media partition: backend-capable media rides as ContentBlock::Image/Audio (raw bytes + mime), the rest keeps the path-text + ResourceLink form. A read failure degrades that attachment back to a ResourceLink. The claude and codex adapters' existing base64 encoders consume the blocks unchanged (claude image pinned at protocols/samples/claude-cli/2.1.177).
ACP agents already carry prompt_capabilities inside the handshake-persisted agent_metadata.agent_capabilities (003 seeds + live initialize refresh), which reaches the frontend verbatim. Migration 037 json_patches the same key onto the direct-CLI rows (claude/codex: image only), mirroring 036's session_capabilities.fork pattern. Antigravity stays text-only (absent key reads as unsupported).
PromptCapabilityView {image, audio} joins fork_capability in the same
detail-only post-fill: one agent_metadata.agent_capabilities load now
feeds both projections (agent_capabilities_for_agent + two pure view
fns). List responses stay N+1-free.
Both dispatch paths (ACP prompt / session Command::Send) now emit one info line with image/audio counts when a prompt carries native media blocks, so production logs can distinguish native-block delivery from the path-text fallback (the degradation warns already existed).
Contributor
Author
Local e2e — real UI wire shapes, full upload chainRan a local instance (
Result:
The last commit adds that info line on both dispatch paths (ACP + session) so native-block delivery is diagnosable in production logs. |
kaizhou-lab
pushed a commit
that referenced
this pull request
Aug 5, 2026
🤖 I have created a release *beep* *boop* --- ## [0.1.59](v0.1.58...v0.1.59) (2026-08-05) ### Features * **agent:** multimodal prompt — native image/audio content blocks gated by promptCapabilities ([#774](#774)) ([5a78a0b](5a78a0b)) * **team:** add read-only mailbox/task activity API and real-time events ([#740](#740)) ([f86c053](f86c053)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Attachments that the target agent can natively consume (per its declared
promptCapabilities) are now delivered as protocol image/audio content blocks instead of file-path text. Agents without the capability keep the exact pre-existing path-based wire form, byte for byte. Frontend half: iOfficeAI/AionUi#3849.How it works
aionui-ai-agent/src/media.rs): the only layer that knows the agent's capabilities splitsSendMessageData.filesinto native-block media vs path files, stripping/rebuilding the[[AION_FILES]]block with the same validate-then-rebuild approach as the aionrs precedent (manager/aionrs/content.rs). Persisted/broadcast message content is untouched — UI chips and history render exactly as before. Degradation to path form: capability absent, non-media mime, SVG, unreadable, or >5MB (warn-logged).IAgentTask::prompt_media_caps()(default none) — AcpAgentManager reads the initialize response'spromptCapabilities; SessionAgentTask reads the backend'sprompt_blocks.agent_session_flow):session/promptbecomes a text block plus one base64ImageContent/AudioContentper capable attachment (uri: file://…). Any read failure degrades the whole prompt back to the plain text form. Transport isLinesCodec::new()(unbounded) on both sides.session_agent): capable media rides as seamContentBlock::Image/Audio; the claude/codex adapters' existing base64 encoders consume them unchanged.prompt_capabilitiesinsideagent_metadata.agent_capabilities(003 seeds + live handshake refresh). Migration 037 json_patches the same key onto the direct-CLI rows (claude/codex: image only), mirroring 036's fork pattern. The conversation detail response gains aprompt_capability {image, audio}projection next tofork_capability(one metadata load feeds both; lists stay N+1-free).Live verification
--input-format stream-json): a generated 24px red-square-on-blue PNG sent as the adapter'ssource-wrapped base64 image block → "图中是蓝色背景上的一个红色正方形。"--acp:session/promptwith{type:"image", data, mimeType, uri}→ "A red square centered on a blue background." (stopReason: end_turn, no error with theurifield present)Testing (targeted; CI runs the full workspace suite)
aionui-ai-agent: media partition (6), ACP prompt blocks (3), session send partition (1) — all passaionui-conversation: lib 376 +conversation_extended38 (incl. newget_projects_prompt_capability_on_detail_path) — all passaionui-db: 330 pass with migration 037cargo fmt --checkclean; targeted clippy (-pai-agent/conversation/api-types) clean