Skip to content

feat: provider vision gating and Anthropic image adapter (#268)#335

Merged
yacosta738 merged 4 commits into
mainfrom
feat/provider-vision-gating
Mar 27, 2026
Merged

feat: provider vision gating and Anthropic image adapter (#268)#335
yacosta738 merged 4 commits into
mainfrom
feat/provider-vision-gating

Conversation

@yacosta738
Copy link
Copy Markdown
Contributor

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

  • 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
  • 7 new tests (capabilities, format, regression, integration)
  • 2896 total tests passing

SDD Artifacts

  • Spec: 6 requirements (REQ-1 through REQ-6), 20 scenarios
  • Design: 5 ADRs (trait capability, three-layer gating, Anthropic adapter, format translation, Ollama deferral)
  • Verify: PASS WITH WARNINGS (doc-only, no code issues)

Provider Vision Matrix (v1)

Provider Image Support Transport Format
OpenAI-compatible Yes InlineBytes image_url data URI
Anthropic Yes (NEW) InlineBytes source.type=base64 content block
Gemini Yes InlineBytes inline_data in parts
Ollama Deferred (Wave 2)

Known limitations

- 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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 27, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds multimodal image support for the Anthropic provider: introduces NativeContentOut::Image and ImageSource, base64-encodes staged image bytes and injects image blocks into the last user message in chat(), overrides capabilities() to advertise image input, and supplies spec/design/docs for provider vision gating.

Changes

Cohort / File(s) Summary
Anthropic Provider Implementation
clients/agent-runtime/src/providers/anthropic.rs
Adds NativeContentOut::Image + ImageSource, base64_encode() helper, overrides capabilities() to advertise image_input with InlineBytes, extends chat() to read StagedImage.temp_path, base64-encode bytes and append image blocks to the last user message, and updates cache-control handling. Adds tests for serialization, cache behavior, and image injection.
Vision Capability Spec
openspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.md
New spec defining provider vision capability matrix, fail-closed gating across trait/router/reliable-wrapper, per-provider image format contracts (Anthropic base64 source), and routing/error semantics for non-vision providers.
Design & Proposal Docs
openspec/changes/2026-03-26-provider-vision-gating/design.md, .../exploration.md, .../proposal.md
Design, exploration, and proposal content describing gating architecture, runtime flow, Anthropic adapter requirements (image block format, injection timing), rollout/rollback, and test plans.
Planning & Verification
openspec/changes/2026-03-26-provider-vision-gating/tasks.md, .../verify-report.md
Tasked rollout plan and verification report documenting build/test outcomes, spec compliance mapping, and verification status (PASS WITH WARNINGS).

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

area:rust, area:docs, risk:security

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title follows Conventional Commit style with a 'feat' prefix, includes the issue number (#268), and clearly summarizes the main changes: provider vision gating and Anthropic image adapter implementation.
Description check ✅ Passed The PR description covers the main objectives (SDD cycle implementation), code changes, test results, and provider matrix. However, it lacks explicit sections matching the template structure (Related Issues, Tested Information, Documentation Impact, Breaking Changes).
Linked Issues check ✅ Passed All objectives from issue #268 are addressed: provider vision capability gating is formalized with a three-layer fail-closed model; initial provider matrix (OpenAI, Anthropic, Gemini, Ollama deferred) is defined; Anthropic adapter is implemented with image support; and follow-up issues can be created cleanly.
Out of Scope Changes check ✅ Passed All changes are within scope. The PR includes code implementation (Anthropic adapter), comprehensive spec/design documentation, verification reports, and task tracking—all directly serving issue #268 objectives. No unrelated refactoring or style changes are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/provider-vision-gating

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 27, 2026

✅ Contributor Report

User: @yacosta738
Status: Passed (12/13 metrics passed)

Metric Description Value Threshold Status
PR Merge Rate PRs merged vs closed 89% >= 30%
Repo Quality Repos with ≥100 stars 0 >= 0
Positive Reactions Positive reactions received 9 >= 1
Negative Reactions Negative reactions received 0 <= 5
Account Age GitHub account age 3072 days >= 30 days
Activity Consistency Regular activity over time 108% >= 0%
Issue Engagement Issues with community engagement 0 >= 0
Code Reviews Code reviews given to others 456 >= 0
Merger Diversity Unique maintainers who merged PRs 2 >= 0
Repo History Merge Rate Merge rate in this repo 91% >= 0%
Repo History Min PRs Previous PRs in this repo 180 >= 0
Profile Completeness Profile richness (bio, followers) 90 >= 0
Suspicious Patterns Spam-like activity detection 1 N/A

Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-03-27 to 2026-03-27

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between fc2e18c and b54e583.

📒 Files selected for processing (7)
  • clients/agent-runtime/src/providers/anthropic.rs
  • openspec/changes/2026-03-26-provider-vision-gating/design.md
  • openspec/changes/2026-03-26-provider-vision-gating/exploration.md
  • openspec/changes/2026-03-26-provider-vision-gating/proposal.md
  • openspec/changes/2026-03-26-provider-vision-gating/specs/provider-vision-gating/spec.md
  • openspec/changes/2026-03-26-provider-vision-gating/tasks.md
  • openspec/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.md
  • openspec/changes/2026-03-26-provider-vision-gating/tasks.md
  • openspec/changes/2026-03-26-provider-vision-gating/proposal.md
  • openspec/changes/2026-03-26-provider-vision-gating/design.md
  • openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
  • openspec/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.md
  • openspec/changes/2026-03-26-provider-vision-gating/tasks.md
  • openspec/changes/2026-03-26-provider-vision-gating/proposal.md
  • openspec/changes/2026-03-26-provider-vision-gating/design.md
  • 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/specs/provider-vision-gating/spec.md
clients/agent-runtime/src/providers/**/*.rs

📄 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
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, and cargo test for 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 ImageHistoryMeta replay 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_encode helper is clean and appropriate.

Uses base64::engine::general_purpose::STANDARD.encode which produces raw base64 without padding issues. This matches the Anthropic API requirement for source.data without a data: URL prefix.


94-104: NativeContentOut::Image and ImageSource serialize 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 handles Image as no-op.

Image blocks don't carry cache_control in 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: true with ImageTransportForm::InlineBytes, satisfying the supports_image_input() gate in traits.rs which requires both conditions. native_tool_calling: true is correctly preserved.


1175-1358: Test coverage is comprehensive for the new image functionality.

Tests cover:

  • capabilities_declares_image_support — verifies declaration
  • supports_image_input_returns_true — verifies gate method
  • image_content_block_serializes_to_anthropic_format — verifies JSON shape
  • image_content_block_no_data_url_prefix — verifies no data: prefix
  • empty_images_produces_no_image_blocks — regression test
  • apply_cache_to_last_message_handles_image_variant — no-panic test
  • image_blocks_attached_to_last_user_message — integration test with tempfile

The 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_input AND non-empty image_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_hint

The Anthropic format scenario (lines 192-200) correctly specifies source.data without data: URL prefix, matching the implementation.

Comment thread clients/agent-runtime/src/providers/anthropic.rs Outdated
Comment thread openspec/changes/2026-03-26-provider-vision-gating/proposal.md Outdated
Comment thread openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Mar 27, 2026

Deploying corvus with  Cloudflare Pages  Cloudflare Pages

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

View logs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
openspec/changes/2026-03-26-provider-vision-gating/verify-report.md (2)

24-37: ⚠️ Potential issue | 🟡 Minor

Add 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 issues

Tests: ✅ 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.md around
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 opening shell fences are preceded by an empty line; specifically, add a newline before the shell 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 messages by
    attaching images to the last role == "user" message, but rfind(|m| m.role == "user") can match tool outputs (also encoded as user) and misattach images;
    before reading files and pushing NativeContentOut::Image, check
    request.messages for a final real user turn (e.g., find the last element in
    request.messages with role == "user" and verify it's the final turn), and if
    none exists return an explicit error rather than proceeding; update the logic
    around request.images, messages, and the rfind that sets last_user (in
    anthropic.rs) to validate against request.messages and 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 opening shell fences are preceded by an empty line; specifically, add a newline before the shell 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 -->

Comment thread clients/agent-runtime/src/providers/anthropic.rs Outdated
Comment thread clients/agent-runtime/src/providers/anthropic.rs Outdated
Comment thread openspec/changes/2026-03-26-provider-vision-gating/verify-report.md Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 386bd39 and b0da1b2.

📒 Files selected for processing (2)
  • clients/agent-runtime/src/providers/anthropic.rs
  • openspec/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.md
  • clients/agent-runtime/src/providers/anthropic.rs
clients/agent-runtime/src/providers/**/*.rs

📄 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
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, and cargo test for 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.md
  • 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/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::Image variant with source.type = "base64" follows Anthropic's content block schema exactly. The #[serde(rename = "type")] on source_type produces 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: true with InlineBytes transport form enables the router's fail-closed check at router.rs:149-163 to 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. The supports_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_message helper 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 methods ChatMessage::user(), ChatMessage::assistant(), and ChatMessage::tool() are defined in clients/agent-runtime/src/providers/traits.rs and 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.

Comment thread clients/agent-runtime/src/providers/anthropic.rs
Comment thread openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
Comment thread openspec/changes/2026-03-26-provider-vision-gating/verify-report.md
@sonarqubecloud
Copy link
Copy Markdown

@yacosta738 yacosta738 merged commit d169a5a into main Mar 27, 2026
11 of 12 checks passed
@yacosta738 yacosta738 deleted the feat/provider-vision-gating branch March 27, 2026 10:34
@yacosta738 yacosta738 mentioned this pull request Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Define provider vision capability gating and multimodal adapter strategy

1 participant