feat: provider vision gating and Anthropic image adapter (#268)#335
Conversation
- Add NativeContentOut::Image variant with Anthropic base64 source format - Override capabilities() to declare image_input: true with InlineBytes transport - Inject image content blocks into last user message in chat() - Update apply_cache_to_last_message for exhaustive match coverage - Add 7 new tests (capabilities, format, regression, integration) - Full SDD cycle: explore → propose → spec (6 REQs, 20 scenarios) → design (5 ADRs) → implement → verify Closes #268
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds multimodal image support for the Anthropic provider: introduces Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Router
participant AnthropicProvider
participant FileSystem
participant AnthropicAPI
Client->>Router: Submit chat request with images
Router->>AnthropicProvider: Dispatch chat() (image-capable)
AnthropicProvider->>FileSystem: Read staged image bytes (temp_path)
FileSystem-->>AnthropicProvider: Return bytes
AnthropicProvider->>AnthropicProvider: base64-encode bytes, build NativeContentOut::Image block
AnthropicProvider->>AnthropicAPI: Send chat request (last user message + image block)
AnthropicAPI-->>AnthropicProvider: Response
AnthropicProvider-->>Router: Return response
Router-->>Client: Deliver response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Contributor ReportUser: @yacosta738
Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-03-27 to 2026-03-27 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/agent-runtime/src/providers/anthropic.rs`:
- Around line 504-505: The code uses blocking std::fs::read to load
image.temp_path; replace it with the asynchronous tokio::fs::read and await it
(e.g., tokio::fs::read(&image.temp_path).await) and preserve the error mapping
to anyhow (map_err(|e| anyhow::anyhow!("Failed to read staged image: {e}"))?).
Locate the read call in clients/agent-runtime/src/providers/anthropic.rs (the
bytes = std::fs::read(&image.temp_path) line) and update it to use
tokio::fs::read with .await so it performs non-blocking file I/O in the async
context. Ensure the surrounding function is async or already in an async context
and adjust imports to include tokio::fs if needed.
In `@openspec/changes/2026-03-26-provider-vision-gating/proposal.md`:
- Line 68: The affected-areas table is incorrect: the `NativeContentOut::Image`
variant is declared locally in `anthropic.rs` (the enum `NativeContentOut` is
defined there) not in `clients/agent-runtime/src/providers/traits.rs`; update
the table entry to mark `anthropic.rs` as Modified (and remove or correct the
`traits.rs` entry) so the proposal references the actual file where
`NativeContentOut::Image` is implemented.
In `@openspec/changes/2026-03-26-provider-vision-gating/verify-report.md`:
- Around line 24-37: The fenced code blocks showing build and test outputs in
verify-report.md lack language specifiers; edit the two triple-backtick blocks
around the "cargo clippy / cargo fmt" and "cargo test" output and add an
appropriate language tag (e.g., shell or text) right after the opening ``` so
they become ```shell (or ```text) to satisfy markdownlint MD040 and ensure
consistent rendering.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 48b21a58-39de-4c75-9f5f-5736d4429fa1
📒 Files selected for processing (7)
clients/agent-runtime/src/providers/anthropic.rsopenspec/changes/2026-03-26-provider-vision-gating/design.mdopenspec/changes/2026-03-26-provider-vision-gating/exploration.mdopenspec/changes/2026-03-26-provider-vision-gating/proposal.mdopenspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.mdopenspec/changes/2026-03-26-provider-vision-gating/tasks.mdopenspec/changes/2026-03-26-provider-vision-gating/verify-report.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: pr-checks
- GitHub Check: sonar
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{md,mdx}
⚙️ CodeRabbit configuration file
**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.
Files:
openspec/changes/2026-03-26-provider-vision-gating/exploration.mdopenspec/changes/2026-03-26-provider-vision-gating/tasks.mdopenspec/changes/2026-03-26-provider-vision-gating/proposal.mdopenspec/changes/2026-03-26-provider-vision-gating/design.mdopenspec/changes/2026-03-26-provider-vision-gating/verify-report.mdopenspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.md
**/*
⚙️ CodeRabbit configuration file
**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.
Files:
openspec/changes/2026-03-26-provider-vision-gating/exploration.mdopenspec/changes/2026-03-26-provider-vision-gating/tasks.mdopenspec/changes/2026-03-26-provider-vision-gating/proposal.mdopenspec/changes/2026-03-26-provider-vision-gating/design.mdopenspec/changes/2026-03-26-provider-vision-gating/verify-report.mdclients/agent-runtime/src/providers/anthropic.rsopenspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.md
clients/agent-runtime/src/providers/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Implement
Providertrait insrc/providers/and register insrc/providers/mod.rsfactory when adding a new provider
Files:
clients/agent-runtime/src/providers/anthropic.rs
clients/agent-runtime/src/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Files:
clients/agent-runtime/src/providers/anthropic.rs
clients/agent-runtime/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Run
cargo fmt --all -- --check,cargo clippy --all-targets -- -D warnings, andcargo testfor code validation, or document which checks were skipped and why
Files:
clients/agent-runtime/src/providers/anthropic.rs
**/*.rs
⚙️ CodeRabbit configuration file
**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.
Files:
clients/agent-runtime/src/providers/anthropic.rs
🧠 Learnings (1)
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider
Applied to files:
clients/agent-runtime/src/providers/anthropic.rs
🪛 LanguageTool
openspec/changes/2026-03-26-provider-vision-gating/exploration.md
[uncategorized] ~156-~156: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...the three major cloud providers for v1, low risk - Cons: Ollama users with vision mod...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
openspec/changes/2026-03-26-provider-vision-gating/design.md
[grammar] ~110-~110: Ensure spelling is correct
Context: ... ImageSource, }, With a supporting struct: rust #[derive(Debug, Serialize)] struct ImageSource { #[serde(rename = "type")] source_type: String, // always "base64" media_type: String, // from StagedImage.mime_type data: String, // base64-encoded bytes } ``` chat() modification (`anthropic.rs:469-511`)...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
[style] ~201-~201: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...iant with specs. All 12 tasks complete. All design decisions followed. Code compile...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
openspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.md
[grammar] ~127-~127: Use a hyphen to join words.
Context: ...enario: Trait default rejects image turn on unoverridden provider - GIVEN a prov...
(QB_NEW_EN_HYPHEN)
🪛 markdownlint-cli2 (0.22.0)
openspec/changes/2026-03-26-provider-vision-gating/exploration.md
[warning] 20-20: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
[warning] 25-25: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 33-33: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 33-33: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (12)
openspec/changes/2026-03-26-provider-vision-gating/exploration.md (1)
1-199: Exploration document is well-structured and technically accurate.The document correctly identifies the existing three-layer fail-closed infrastructure and the Anthropic adapter gap. Line references to the codebase (e.g.,
traits.rs:222-243,compatible.rs:494-609) align with the implementation context.Minor: Line 156 uses "low risk" — hyphenate to "low-risk" when modifying the noun.
openspec/changes/2026-03-26-provider-vision-gating/tasks.md (1)
1-104: Task breakdown is complete and well-mapped.The phased rollout plan correctly tracks all implementation tasks with specific file locations, verification commands (
cargo check,cargo test,cargo fmt,cargo clippy), and traceability to design ADRs and spec requirements. The acceptance criteria mapping table provides clear coverage.openspec/changes/2026-03-26-provider-vision-gating/verify-report.md (1)
1-201: Verification report is thorough and correctly identifies gaps.The 14 PARTIAL scenarios appropriately reflect existing behavior formalized into spec without code changes. The two warnings (coverage not measured, proposal table inaccuracy) are valid observations and correctly classified as non-blocking.
openspec/changes/2026-03-26-provider-vision-gating/design.md (1)
1-342: Design document is well-architected with complete ADRs.The five ADRs provide clear rationale for each decision:
- ADR-1/ADR-2 correctly formalize existing infrastructure.
- ADR-3 specifies the Anthropic adapter with matching code snippets.
- ADR-4 justifies per-provider format ownership over forced abstraction.
- ADR-5 correctly defers Ollama due to capability detection gaps.
The sequence diagram and testing strategy table are comprehensive. Open question about
ImageHistoryMetareplay is appropriately tracked for future work.openspec/changes/2026-03-26-provider-vision-gating/proposal.md (1)
1-111: Proposal is well-scoped with clear success criteria.The intent, scope, approach, and rollback plan are well-defined. Success criteria are measurable and map directly to implementation tasks. Dependencies on prior issues (
#266,#267) are correctly stated.clients/agent-runtime/src/providers/anthropic.rs (6)
12-15:base64_encodehelper is clean and appropriate.Uses
base64::engine::general_purpose::STANDARD.encodewhich produces raw base64 without padding issues. This matches the Anthropic API requirement forsource.datawithout adata:URL prefix.
94-104:NativeContentOut::ImageandImageSourceserialize correctly to Anthropic format.The serde attributes (
#[serde(rename = "image")],#[serde(rename = "type")]) produce the exact JSON shape required:{type:"image", source:{type:"base64", media_type, data}}.
226-226: Cache control match arm correctly handlesImageas no-op.Image blocks don't carry
cache_controlin Anthropic's API, so the empty match arm is appropriate. This maintains exhaustive matching without runtime issues.
548-554:capabilities()override correctly declares image support.Returns
image_input: truewithImageTransportForm::InlineBytes, satisfying thesupports_image_input()gate intraits.rswhich requires both conditions.native_tool_calling: trueis correctly preserved.
1175-1358: Test coverage is comprehensive for the new image functionality.Tests cover:
capabilities_declares_image_support— verifies declarationsupports_image_input_returns_true— verifies gate methodimage_content_block_serializes_to_anthropic_format— verifies JSON shapeimage_content_block_no_data_url_prefix— verifies nodata:prefixempty_images_produces_no_image_blocks— regression testapply_cache_to_last_message_handles_image_variant— no-panic testimage_blocks_attached_to_last_user_message— integration test with tempfileThe integration test at lines 1268-1358 exercises the full flow with a real temp file, validating both structure and content.
500-516: rfind() logic correctly identifies the last user message for image injection.The implementation properly appends image blocks after text content, matching the specification. The edge case concern (images without user messages) is not applicable: conversation history always includes the current message as a final user message, and image turns without valid content are rejected fail-closed before reaching the provider.
openspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.md (1)
1-282: Spec is well-structured with testable Given/When/Then scenarios.The 6 requirements correctly formalize:
- REQ-1: Provider capability matrix with explicit v1 status
- REQ-2: Dual-condition gate (
image_inputAND non-emptyimage_transport_forms)- REQ-3: Three-layer fail-closed enforcement
- REQ-4: Provider-specific format contracts with exact field expectations
- REQ-5: Explicit rejection behavior (no silent stripping)
- REQ-6: Config integration via
vision_model_hintThe Anthropic format scenario (lines 192-200) correctly specifies
source.datawithoutdata:URL prefix, matching the implementation.
Deploying corvus with
|
| Latest commit: |
e78c4b5
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://4e320c8d.corvus-42x.pages.dev |
| Branch Preview URL: | https://feat-provider-vision-gating.corvus-42x.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md (2)
24-37:⚠️ Potential issue | 🟡 MinorAdd the missing blank lines around the fenced output blocks.
markdownlint still flags Lines 25 and 33 because the fences are immediately preceded by paragraph text. Insert a blank line before each opening fence.
🧹 Suggested fix
**Build**: ✅ Passed + ```shell cargo clippy --manifest-path clients/agent-runtime/Cargo.toml --all-targets -- -D warnings → 0 errors, 0 warnings cargo fmt --manifest-path clients/agent-runtime/Cargo.toml --check → no formatting issuesTests: ✅ 64 passed / ❌ 0 failed /
⚠️ 0 skipped
+cargo test --manifest-path clients/agent-runtime/Cargo.toml -- anthropic test result: ok. 64 passed; 0 failed; 0 ignored; 0 measured; finished in 0.03s (run across lib + main binary targets)</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@openspec/changes/2026-03-26-provider-vision-gating/verify-report.mdaround
lines 24 - 37, Insert a blank line immediately before each fenced code block
that follows the "Build: ✅ Passed" and "Tests: ✅ 64 passed / ❌ 0 failed
/⚠️ 0 skipped" paragraphs so the openingshell fences are preceded by an empty line; specifically, add a newline before theshell block under the
"Build" section and another newline before the ```shell block under the
"Tests" section to satisfy markdownlint.</details> --- `134-145`: _⚠️ Potential issue_ | _🟡 Minor_ **Drop the stale `traits.rs` mismatch from this report.** The current `proposal.md` affected-areas table already points the `NativeContentOut::Image` work at `clients/agent-runtime/src/providers/anthropic.rs`, so Lines 134-145 and the verdict on Lines 199-201 now describe a mismatch that no longer exists. Remove that warning/deviation and update the verdict summary to reflect the remaining warning count. As per coding guidelines, "`**/*.{md,mdx}`: Verify technical accuracy and that docs stay aligned with code changes." Also applies to: 199-201 <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` around lines 134 - 145, Remove the stale mismatch warning in verify-report.md that claims NativeContentOut::Image was added to traits.rs; delete the paragraph(s) referencing the traits.rs deviation (including the duplicate_comment note) and update the verdict/summary counts so the warning tally reflects only the coverage warning; ensure the report still documents that NativeContentOut::Image exists in anthropic.rs (reference the NativeContentOut::Image symbol and anthropic.rs) so the affected-areas table remains correct. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Inline comments:
In@clients/agent-runtime/src/providers/anthropic.rs:
- Around line 1310-1323: The test currently duplicates chat()'s image injection
loop (manipulating native_messages, pushing NativeContentOut::Image with
ImageSource), which can diverge from production; instead refactor by extracting
the image-attachment logic used by chat() into a small helper (e.g.,
attach_image_to_message(&mut Message, &StagedImage) or attach_images(&mut
Vec, &[StagedImage])) and call that helper from both chat() and this
test, or invoke chat() through a mocked transport so the production path is
exercised; update the test to call the new helper (or mocked chat) rather than
hand-copying the loop that reads files, base64-encodes bytes, and pushes
NativeContentOut::Image.- Around line 500-516: The code mutates the converted Anthropic
messagesby
attaching images to the lastrole == "user"message, butrfind(|m| m.role == "user")can match tool outputs (also encoded as user) and misattach images;
before reading files and pushingNativeContentOut::Image, check
request.messagesfor a final real user turn (e.g., find the last element in
request.messageswith role == "user" and verify it's the final turn), and if
none exists return an explicit error rather than proceeding; update the logic
aroundrequest.images,messages, and therfindthat setslast_user(in
anthropic.rs) to validate againstrequest.messagesand early-return on
failure.In
@openspec/changes/2026-03-26-provider-vision-gating/verify-report.md:
- Around line 153-163: The table's "Existing tests pass (no regressions) |
Verified: 64 tests passed" and the "Fail-closed gating formalized" verification
entries are overstated because the test run was targeted with the-- anthropic
flag; either run the full adapter test suite (including OpenAI and Gemini
adapters) and update the verification to reflect full-suite results, or change
those table cells to indicate "Partial (Anthropic-only) — 64 tests passed" (and
similarly mark any REQ-3/REQ-5 rows that relied on the same run as scoped to
Anthropic) so the docs accurately reflect the verified scope.
Duplicate comments:
In@openspec/changes/2026-03-26-provider-vision-gating/verify-report.md:
- Around line 24-37: Insert a blank line immediately before each fenced code
block that follows the "Build: ✅ Passed" and "Tests: ✅ 64 passed / ❌ 0
failed /⚠️ 0 skipped" paragraphs so the openingshell fences are preceded by an empty line; specifically, add a newline before theshell block under the
"Build" section and another newline before the ```shell block under the
"Tests" section to satisfy markdownlint.- Around line 134-145: Remove the stale mismatch warning in verify-report.md
that claims NativeContentOut::Image was added to traits.rs; delete the
paragraph(s) referencing the traits.rs deviation (including the
duplicate_comment note) and update the verdict/summary counts so the warning
tally reflects only the coverage warning; ensure the report still documents that
NativeContentOut::Image exists in anthropic.rs (reference the
NativeContentOut::Image symbol and anthropic.rs) so the affected-areas table
remains correct.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Path: .coderabbit.yaml **Review profile**: ASSERTIVE **Plan**: Pro **Run ID**: `a500f44a-a526-4334-85ba-0f34d4165bf2` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between b54e583ed649cd539ebd73e7dda5af52014dee97 and 386bd39f17823095ad6c3a125420898930db4609. </details> <details> <summary>📒 Files selected for processing (3)</summary> * `clients/agent-runtime/src/providers/anthropic.rs` * `openspec/changes/2026-03-26-provider-vision-gating/proposal.md` * `openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` </details> </details> <details> <summary>📜 Review details</summary> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)</summary> * GitHub Check: pr-checks * GitHub Check: sonar * GitHub Check: Cloudflare Pages </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>📓 Path-based instructions (6)</summary> <details> <summary>**/*.{md,mdx}</summary> **⚙️ CodeRabbit configuration file** > `**/*.{md,mdx}`: Verify technical accuracy and that docs stay aligned with code changes. > For user-facing docs, check EN/ES parity or explicitly note pending translation gaps. > Files: - `openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` - `openspec/changes/2026-03-26-provider-vision-gating/proposal.md` </details> <details> <summary>**/*</summary> **⚙️ CodeRabbit configuration file** > `**/*`: Security first, performance second. > Validate input boundaries, auth/authz implications, and secret management. > Look for behavioral regressions, missing tests, and contract breaks across modules. > Files: - `openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` - `clients/agent-runtime/src/providers/anthropic.rs` - `openspec/changes/2026-03-26-provider-vision-gating/proposal.md` </details> <details> <summary>clients/agent-runtime/src/providers/**/*.rs</summary> **📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)** > Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider Files: - `clients/agent-runtime/src/providers/anthropic.rs` </details> <details> <summary>clients/agent-runtime/src/**/*.rs</summary> **📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)** > `clients/agent-runtime/src/**/*.rs`: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements > Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency Files: - `clients/agent-runtime/src/providers/anthropic.rs` </details> <details> <summary>clients/agent-runtime/**/*.rs</summary> **📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)** > Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why Files: - `clients/agent-runtime/src/providers/anthropic.rs` </details> <details> <summary>**/*.rs</summary> **⚙️ CodeRabbit configuration file** > `**/*.rs`: Focus on Rust idioms, memory safety, and ownership/borrowing correctness. > Flag unnecessary clones, unchecked panics in production paths, and weak error context. > Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling. > Files: - `clients/agent-runtime/src/providers/anthropic.rs` </details> </details><details> <summary>🧠 Learnings (5)</summary> <details> <summary>📚 Learning: 2026-02-17T12:31:17.076Z</summary> ``` Learnt from: CR Repo: dallay/corvus PR: 0 File: clients/agent-runtime/AGENTS.md:0-0 Timestamp: 2026-02-17T12:31:17.076Z Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why ``` **Applied to files:** - `openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` </details> <details> <summary>📚 Learning: 2026-02-17T12:31:17.076Z</summary> ``` Learnt from: CR Repo: dallay/corvus PR: 0 File: clients/agent-runtime/AGENTS.md:0-0 Timestamp: 2026-02-17T12:31:17.076Z Learning: Applies to clients/agent-runtime/src/main.rs : Preserve CLI contract unless change is intentional and documented; prefer explicit errors over silent fallback for unsupported critical paths ``` **Applied to files:** - `openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` </details> <details> <summary>📚 Learning: 2026-02-17T12:31:17.076Z</summary> ``` Learnt from: CR Repo: dallay/corvus PR: 0 File: clients/agent-runtime/AGENTS.md:0-0 Timestamp: 2026-02-17T12:31:17.076Z Learning: Applies to clients/agent-runtime/src/tools/**/*.rs : Implement `Tool` trait in `src/tools/` with strict parameter schema, validate and sanitize all inputs, and return structured `ToolResult` without panics in runtime path ``` **Applied to files:** - `openspec/changes/2026-03-26-provider-vision-gating/verify-report.md` </details> <details> <summary>📚 Learning: 2026-02-17T12:31:17.076Z</summary> ``` Learnt from: CR Repo: dallay/corvus PR: 0 File: clients/agent-runtime/AGENTS.md:0-0 Timestamp: 2026-02-17T12:31:17.076Z Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider ``` **Applied to files:** - `clients/agent-runtime/src/providers/anthropic.rs` - `openspec/changes/2026-03-26-provider-vision-gating/proposal.md` </details> <details> <summary>📚 Learning: 2026-02-17T12:31:17.076Z</summary> ``` Learnt from: CR Repo: dallay/corvus PR: 0 File: clients/agent-runtime/AGENTS.md:0-0 Timestamp: 2026-02-17T12:31:17.076Z Learning: Applies to clients/agent-runtime/src/**/*.rs : Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency ``` **Applied to files:** - `clients/agent-runtime/src/providers/anthropic.rs` </details> </details><details> <summary>🪛 LanguageTool</summary> <details> <summary>openspec/changes/2026-03-26-provider-vision-gating/verify-report.md</summary> [style] ~201-~201: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym. Context: ...iant with specs. All 12 tasks complete. All design decisions followed. Code compile... (ENGLISH_WORD_REPEAT_BEGINNING_RULE) </details> </details> <details> <summary>🪛 markdownlint-cli2 (0.22.0)</summary> <details> <summary>openspec/changes/2026-03-26-provider-vision-gating/verify-report.md</summary> [warning] 25-25: Fenced code blocks should be surrounded by blank lines (MD031, blanks-around-fences) --- [warning] 33-33: Fenced code blocks should be surrounded by blank lines (MD031, blanks-around-fences) </details> </details> </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/agent-runtime/src/providers/anthropic.rs`:
- Around line 399-449: In attach_images_to_last_user_message, improve the error
clarity by making the two failure branches distinct: change the ok_or_else()
message that runs when rfind on source_messages returns None to something like
"Anthropic image turns require at least one non-system message" (indicating no
non-system messages were found), and leave/update the subsequent role check's
anyhow::bail() to a different message such as "Anthropic image turns require the
last non-system message to be a user message" (indicating the last non-system
message exists but is not a user); update the error strings referenced in the
ok_or_else call on last_source_message and in the role != "user" bail to reflect
these two separate cases.
In `@openspec/changes/2026-03-26-provider-vision-gating/verify-report.md`:
- Around line 104-113: Update the report's stale line-number references to point
to the current locations by referencing the actual symbols instead of line
numbers: update the entry for capabilities() (and supports_image_input()) to its
current location, reference the NativeContentOut::Image variant and ImageSource
struct by name, and update the image-injection helper function and its call
inside chat() to their current locations; replace all hard-coded line ranges
with these symbol-based references so the traceability table remains accurate
after future edits.
- Around line 126-135: The design table in verify-report.md has stale
line-number references; update the "Actual" column for the `anthropic.rs`
entries so they point to the current locations (e.g., change the `Override
capabilities()` reference from 548-554 to 586-592, update the `Extend chat()`
entry to show helper at 399-449 and call at 552-554 or consolidate as 399-454
depending on exact range, and adjust the tests range from 1175-1358 to
1212-1426); edit the table rows for `NativeContentOut::Image`/`ImageSource`,
`capabilities()`, `chat()`, `apply_cache_to_last_message`, and the tests to
reflect the corrected line ranges and ensure the "Match?" column remains
accurate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: fc1b7222-af47-4820-a97a-6a500c112fe5
📒 Files selected for processing (2)
clients/agent-runtime/src/providers/anthropic.rsopenspec/changes/2026-03-26-provider-vision-gating/verify-report.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: pr-checks
- GitHub Check: sonar
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{md,mdx}
⚙️ CodeRabbit configuration file
**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.
Files:
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
**/*
⚙️ CodeRabbit configuration file
**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.
Files:
openspec/changes/2026-03-26-provider-vision-gating/verify-report.mdclients/agent-runtime/src/providers/anthropic.rs
clients/agent-runtime/src/providers/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Implement
Providertrait insrc/providers/and register insrc/providers/mod.rsfactory when adding a new provider
Files:
clients/agent-runtime/src/providers/anthropic.rs
clients/agent-runtime/src/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Files:
clients/agent-runtime/src/providers/anthropic.rs
clients/agent-runtime/**/*.rs
📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)
Run
cargo fmt --all -- --check,cargo clippy --all-targets -- -D warnings, andcargo testfor code validation, or document which checks were skipped and why
Files:
clients/agent-runtime/src/providers/anthropic.rs
**/*.rs
⚙️ CodeRabbit configuration file
**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.
Files:
clients/agent-runtime/src/providers/anthropic.rs
🧠 Learnings (6)
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why
Applied to files:
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Preserve CLI contract unless change is intentional and documented; prefer explicit errors over silent fallback for unsupported critical paths
Applied to files:
openspec/changes/2026-03-26-provider-vision-gating/verify-report.mdclients/agent-runtime/src/providers/anthropic.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/tools/**/*.rs : Implement `Tool` trait in `src/tools/` with strict parameter schema, validate and sanitize all inputs, and return structured `ToolResult` without panics in runtime path
Applied to files:
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider
Applied to files:
clients/agent-runtime/src/providers/anthropic.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/**/*.rs : Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency
Applied to files:
clients/agent-runtime/src/providers/anthropic.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs : Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable
Applied to files:
clients/agent-runtime/src/providers/anthropic.rs
🔇 Additional comments (9)
clients/agent-runtime/src/providers/anthropic.rs (8)
1-15: LGTM — imports and base64 helper are clean.Standard base64 encoding with no allocation waste. The new imports align with the image capability contract.
94-104: LGTM — Anthropic image format matches API spec.The
NativeContentOut::Imagevariant withsource.type = "base64"follows Anthropic's content block schema exactly. The#[serde(rename = "type")]onsource_typeproduces the correct JSON shape{"type": "image", "source": {"type": "base64", ...}}.
226-226: LGTM — exhaustive match for cache control.Image blocks correctly skip cache annotation like ToolUse — Anthropic doesn't support cache_control on image content.
552-554: LGTM — image injection wired correctly in chat().Injection happens after message conversion but before cache annotation, which is the correct order. The helper propagates errors to fail the request on validation issues.
586-592: LGTM — capability declaration matches provider contract.
image_input: truewithInlineBytestransport form enables the router's fail-closed check atrouter.rs:149-163to correctly route image turns to this provider.
1212-1232: LGTM — capability tests verify the contract.Tests confirm
image_input,native_tool_calling, and transport forms are correctly declared. Thesupports_image_input()check validates both flags are set.
1306-1389: Good integration test exercising the production path.This test uses the actual
attach_images_to_last_user_messagehelper with real temp files, verifying:
- Images attach to the correct (last) user message
- Base64 encoding produces expected output
- No
data:URL prefix in output- JSON structure matches Anthropic API schema
This addresses the earlier concern about test/production drift.
1391-1426: No action required. The helper methodsChatMessage::user(),ChatMessage::assistant(), andChatMessage::tool()are defined inclients/agent-runtime/src/providers/traits.rsand are correctly available for use in this test.> Likely an incorrect or invalid review comment.openspec/changes/2026-03-26-provider-vision-gating/verify-report.md (1)
1-200: Report structure and traceability are solid.The PARTIAL/COMPLIANT split clearly distinguishes new Anthropic functionality (fully tested) from formalized existing behavior (out of scope for this run). Spec → Design → Tasks traceability is complete. Verdict appropriately reflects the coverage warning.
|



Summary
Full SDD cycle for provider vision capability gating. Formalizes the existing three-layer fail-closed gating infrastructure and implements the Anthropic image adapter — completing v1 multimodal coverage across all three major cloud providers (OpenAI-compatible, Anthropic, Gemini).
Code changes
NativeContentOut::Imagevariant with Anthropic base64 source formatcapabilities()to declareimage_input: truewithInlineBytestransportchat()apply_cache_to_last_messagefor exhaustive match coverageSDD Artifacts
Provider Vision Matrix (v1)
image_urldata URIsource.type=base64content blockinline_datain partsKnown limitations
Closes Define provider vision capability gating and multimodal adapter strategy #268