Skip to content

feat(codec): add OCI Generative AI typed variants and response codec (series 1/4)#554

Open
fede-kamel wants to merge 1 commit into
NVIDIA:mainfrom
fede-kamel:feat/oci-codec-1-types-response
Open

feat(codec): add OCI Generative AI typed variants and response codec (series 1/4)#554
fede-kamel wants to merge 1 commit into
NVIDIA:mainfrom
fede-kamel:feat/oci-codec-1-types-response

Conversation

@fede-kamel

@fede-kamel fede-kamel commented Jul 24, 2026

Copy link
Copy Markdown

Overview

First PR of a four-part stacked series adding Oracle Cloud Infrastructure (OCI) Generative AI as a built-in provider in the Rust core — the rework requested in #549 review, split into foundation-ordered units of ~≤1k lines for reviewability (per the plan posted on #552 before closing it).

Series map (each stacked on the previous, opened as its predecessor merges):

  1. This PR — typed ApiSpecific variants + response codec (~560 lines)
  2. Request codec: decode + merge-not-replace encode with identity guarantees (~1.4k, the complexity heart)
  3. Provider-surface resolver registration + streaming codec + guardrails/PII-redaction/adaptive surface support (~1.1k)
  4. Python/Node bindings (~200)
  • I confirm this contribution is my own work, or I have the right to submit it under this project's license.
  • I searched existing issues and open pull requests, and this does not duplicate existing work.

Details

What: ApiSpecificRequest::OCIGenAI { compartment_id, serving_mode, api_format } and ApiSpecificResponse::OCIGenAI { api_format, model_version } (serde tag "oci_genai") in crates/types, plus crates/core/src/codec/oci_genai.rs introducing OCIGenAIChatCodec with its LlmResponseCodec implementation: decodes OCI ChatResult payloads — both GENERIC (choices-based; Meta Llama, Google, xAI, OpenAI, and imported open-weights models such as NVIDIA Nemotron on dedicated AI clusters) and COHERE (text-based) — normalizing model, message text, tool calls, finish reasons, and usage counters. Key lookup tolerates the three conventions OCI emits (SDK camelCase, CLI kebab-case, snake_case).

Why: OCI GenAI responses are currently opaque to Relay observability. This layer alone enables normalized LLMEnd annotations (model, finish reason, token usage) for OCI-backed calls when the codec is supplied explicitly; subsequent PRs add request editing, automatic detection, and binding exposure.

How: Follows the built-in provider pattern (anthropic.rs as template): unit-struct codec, in-module tests, FinishReason mapping for both formats' vocabularies (stop/length/tool_calls, COMPLETE/MAX_TOKENS). Response decoding is manual-extraction rather than serde intermediates because of the multi-convention keys.

Testing: 8 unit tests with fixtures taken from real OCI wire traffic (GENERIC and COHERE ChatResult, kebab-case CLI shape, non-dict fallback, finish-reason and usage mapping, invalid-content error paths, ProviderNative part preservation, tool-call-only empty content). Full cargo test --workspace green (3,369 tests), cargo clippy --workspace --all-targets zero warnings, cargo fmt clean, missing_docs satisfied. The complete series content has additionally been validated end-to-end: the encoded payload of the full codec was posted verbatim to the signed OCI REST endpoint and answered by a dedicated AI cluster serving an imported NVIDIA Nemotron 3 model.

Breaking changes: None — additive enum variants and a new module only.

Where should the reviewer start?

crates/types/src/codec/{request,response}.rs for the variant shapes, then decode_response and the fixtures in crates/core/tests/unit/codec/oci_genai_tests.rs.

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

Summary by CodeRabbit

  • New Features
    • Added typed decoding for OCI Generative AI chat responses, supporting both GENERIC and Cohere-style payloads.
    • Introduced OCI GenAI request/response options (including compartment ID, serving mode, API format, and model version) for consistent handling.
    • Normalizes finish reasons, message content (including non-text parts), tool calls, and token usage; when decoding can’t be structured, the original payload is retained.
  • Tests
    • Added unit tests for GENERIC and Cohere fixtures, kebab-case inputs, tool-call argument parsing, usage/finish-reason mapping, and invalid/non-object responses.

@copy-pr-bot

copy-pr-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added size:L PR is large Feature a new feature lang:rust PR changes/introduces Rust code labels Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds OCI GenAI request and response variants, exports a codec supporting GENERIC and COHERE response formats, normalizes content, tool calls, finish reasons, and usage, and adds unit tests for supported response shapes and edge cases.

Changes

OCI GenAI codec support

Layer / File(s) Summary
OCI GenAI API contracts
crates/types/src/codec/request.rs, crates/types/src/codec/response.rs
Adds serde-tagged OCI GenAI request and response variants with optional provider-specific fields.
OCI GenAI response decoding
crates/core/src/codec/mod.rs, crates/core/src/codec/oci_genai.rs
Exports OCIGenAIChatCodec and decodes GENERIC and COHERE responses, including alternate key spellings, message content, tool calls, finish reasons, usage, raw values, and OCI metadata.
Codec fixtures and validation
crates/core/src/codec/oci_genai.rs, crates/core/tests/unit/codec/oci_genai_tests.rs
Wires unit tests and validates standard, CLI-shaped, non-object, tool-call, mixed-content, invalid-content, usage, and finish-reason inputs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OCI as OCI GenAI response
  participant Codec as OCIGenAIChatCodec
  participant Decoder as GENERIC or COHERE decoder
  participant Result as AnnotatedLlmResponse
  OCI->>Codec: submit JSON response
  Codec->>Decoder: select decoder from apiFormat
  Decoder-->>Codec: return decoded message and tool calls
  Codec->>Result: populate normalized fields and metadata
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Title check ❌ Error The title is Conventional Commits-shaped but exceeds the required 72-character limit. Shorten the title to under 72 characters while keeping the same summary, such as 'feat(codec): add OCI GenAI typed variants and response codec'.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description matches the template with overview, details, review start, and related issues, and the required confirmations are completed.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@fede-kamel
fede-kamel marked this pull request as ready for review July 24, 2026 17:33
@fede-kamel
fede-kamel requested a review from a team as a code owner July 24, 2026 17:33
@fede-kamel

Copy link
Copy Markdown
Author

How this series fits together

This PR is layer 1 of 4. Each layer adds one capability, each is independently buildable and testable, and each later branch is a pure superset of the previous — so review feedback here rebases cleanly through the rest of the stack.

Layer Capability it adds Contents
1 — this PR (+562) Relay can read OCI responses: normalized LLMEnd annotations (model, finish reason, usage) when the codec is supplied explicitly Typed ApiSpecific variants + LlmResponseCodec for GENERIC and COHERE ChatResult payloads
2 (+1,414) Relay can edit OCI requests safely: intercepts (redaction, policy) with encode(decode(x), x) == x identity and unmodeled-field preservation LlmCodec decode + merge-not-replace encode, request-side test suite
3 (+1,060) Relay auto-detects OCI: provider-surface registration, streaming, and awareness in guardrails, PII-redaction overlay, and adaptive components ProviderSurface::OCIGenAI, detection (strongest-signal envelope keys, placed first), OCIGenAIStreamingCodec, parity cases
4 (+202) Every language gets it pyo3 + napi classes, .pyi/codecs.py exposure, binding tests — closes #548

Branch links and the full plan of record are on #548. Lineage: #549 (Python approach, closed per review) → #552 (this same content as a single Rust PR, closed in favor of this reviewable split).

Verification provenance

Every branch in the stack passes the full local gate on its own: cargo build --workspace, complete workspace test suite (3,369 tests at this layer, growing to 3,403 by layer 4), cargo clippy --workspace --all-targets with zero warnings, cargo fmt --check, and missing_docs. The four layers recombine byte-identically to the #552 content, which was validated end-to-end: the codec-encoded request was posted verbatim to the signed OCI REST chat endpoint and answered correctly by a dedicated AI cluster serving an imported NVIDIA Nemotron 3 model, with the response codec normalizing the reply including token usage.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/core/src/codec/oci_genai.rs`:
- Around line 124-162: Update flatten_all_text_parts to return None for an empty
parts slice, while preserving Text concatenation for non-empty arrays containing
only valid TEXT parts. This ensures decode_generic_content returns None for
content: [] and does not mark tool-call-only messages as containing text.

In `@crates/core/tests/unit/codec/oci_genai_tests.rs`:
- Around line 131-167: Add error-path coverage alongside the existing OCI GenAI
codec tests for GENERIC responses: create a test such as
test_invalid_generic_content_shape_errors that passes a numeric or object
message.content to OCIGenAIChatCodec.decode_response and asserts it returns an
error. Also cover an array containing a non-object part if practical, ensuring
decode_generic_content rejects each invalid shape with
FlowError::InvalidArgument.
🪄 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: Enterprise

Run ID: a9645a77-4c88-4c9e-8a1c-90f1492e291a

📥 Commits

Reviewing files that changed from the base of the PR and between 6e13cfd and ccb3281.

📒 Files selected for processing (5)
  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/types/src/codec/request.rs
  • crates/types/src/codec/response.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (17)
**/*.rs

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.rs: If any Rust code changed, always run just test-rust.
If any Rust code changed, also run cargo fmt --all.
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
{crates/core,crates/adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
crates/core/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
crates/core/src/{api/**/*.rs,api/runtime/**/*.rs,codec/**/*.rs,json.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement the new or changed public runtime behavior first in the Rust core, especially under crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, and crates/core/src/json.rs.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
{crates/**/src/**/*.rs,python/**/*.py}

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
crates/{core,adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full validation matrix across Rust, Python, Go, and Node.js.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
**/*.{rs,py,go,js,ts}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
{crates/core/src/plugin/dynamic/**,crates/plugin/**,crates/worker/**,crates/worker-proto/**,crates/types/**,python/plugin/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Keep the stable boundary explicit: native plugins cross a C ABI, and worker plugins cross grpc-v1.

Files:

  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
crates/types/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Runtime helpers must cover marks, scopes, continuations, and isolated scope stacks.

Files:

  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/codec/oci_genai_tests.rs
🔇 Additional comments (8)
crates/types/src/codec/request.rs (1)

537-549: LGTM!

crates/types/src/codec/response.rs (1)

329-339: LGTM!

crates/core/src/codec/mod.rs (1)

19-19: LGTM!

crates/core/src/codec/oci_genai.rs (3)

197-254: LGTM!


262-329: LGTM!


90-101: LGTM!

Also applies to: 332-341

crates/core/tests/unit/codec/oci_genai_tests.rs (2)

16-129: LGTM!


169-188: LGTM!

Comment thread crates/core/src/codec/oci_genai.rs
Comment thread crates/core/tests/unit/codec/oci_genai_tests.rs
@fede-kamel
fede-kamel force-pushed the feat/oci-codec-1-types-response branch from ccb3281 to 21d6e18 Compare July 24, 2026 17:59
@fede-kamel

Copy link
Copy Markdown
Author

Both review findings addressed in the updated commit:

  1. Empty content: []None: decode_generic_content now returns Ok(None) for an empty part list, so tool-call-only messages no longer decode to Some(Text("")). The tool-call fixture test now asserts annotated.message == None explicitly.
  2. Error-path coverage: added test_invalid_generic_content_shape_errors exercising InvalidArgument for non-string/array/null content and non-object parts.

Full workspace build and test suite re-run green after the change; the fix is propagated through the staged follow-up branches of the series.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/core/src/codec/oci_genai.rs`:
- Around line 313-333: The decode_response_tool_call path silently discards
malformed tool calls when the name is missing or non-string. Add an appropriate
debug or warning log before returning None for this validation failure,
including enough context to identify the malformed OCI payload while preserving
the existing successful decoding behavior.

In `@crates/core/tests/unit/codec/oci_genai_tests.rs`:
- Around line 1-210: Add a test near test_invalid_generic_content_shape_errors
that decodes a GENERIC response with mixed TEXT and non-TEXT content through
OCIGenAIChatCodec::decode_response. Assert the message is MessageContent::Parts,
contains both parts, and specifically verify the non-TEXT part is represented as
ContentPart::ProviderNative with its original payload preserved.
🪄 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: Enterprise

Run ID: 09237b3d-efcb-4116-9173-2272097f9a8c

📥 Commits

Reviewing files that changed from the base of the PR and between ccb3281 and 21d6e18.

📒 Files selected for processing (5)
  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/types/src/codec/request.rs
  • crates/types/src/codec/response.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (17)
**/*.rs

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.rs: If any Rust code changed, always run just test-rust.
If any Rust code changed, also run cargo fmt --all.
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
{crates/core,crates/adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/core/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/core/src/{api/**/*.rs,api/runtime/**/*.rs,codec/**/*.rs,json.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement the new or changed public runtime behavior first in the Rust core, especially under crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, and crates/core/src/json.rs.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
{crates/**/src/**/*.rs,python/**/*.py}

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/src/codec/oci_genai.rs
**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/{core,adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full validation matrix across Rust, Python, Go, and Node.js.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,go,js,ts}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
{crates/core/src/plugin/dynamic/**,crates/plugin/**,crates/worker/**,crates/worker-proto/**,crates/types/**,python/plugin/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Keep the stable boundary explicit: native plugins cross a C ABI, and worker plugins cross grpc-v1.

Files:

  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
crates/types/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Runtime helpers must cover marks, scopes, continuations, and isolated scope stacks.

Files:

  • crates/types/src/codec/response.rs
  • crates/types/src/codec/request.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/codec/oci_genai_tests.rs
🔇 Additional comments (4)
crates/types/src/codec/request.rs (1)

537-549: LGTM!

crates/types/src/codec/response.rs (1)

329-339: LGTM!

crates/core/src/codec/oci_genai.rs (1)

1-113: LGTM!

Also applies to: 201-258, 266-345

crates/core/src/codec/mod.rs (1)

19-19: LGTM!

Comment thread crates/core/tests/unit/codec/oci_genai_tests.rs
@fede-kamel

Copy link
Copy Markdown
Author

End-to-end validation re-run on the updated series content (including the empty-content fix above), via the Python binding built from the stack tip:

  1. decode normalized a live OCI ChatDetails request (dedicated serving mode)
  2. encode(decode(request), request) verified byte-identical to the original payload
  3. the codec-encoded request was posted verbatim to the signed OCI Generative AI REST endpoint (us-chicago-1) and answered correctly by a dedicated AI cluster serving an imported NVIDIA Nemotron 3 model
  4. decode_response normalized the live reply, including finish reason and token usage (prompt_tokens: 28, completion_tokens: 109, total_tokens: 137)

Unit suite on the same tip: 33 OCI codec tests green, full workspace build and tests passing, clippy zero warnings.

Introduce the first layer of the OCI Generative AI provider codec:
typed ApiSpecificRequest::OCIGenAI and ApiSpecificResponse::OCIGenAI
variants, plus an OCIGenAIChatCodec implementing LlmResponseCodec.
Response decode covers ChatResult ({modelId, chatResponse}) and bare
chat responses in both apiFormat variants (GENERIC choices-based and
COHERE text-based), tolerates camelCase, kebab-case, and snake_case
key conventions (SDK vs CLI shapes), parses GENERIC string-encoded
tool-call arguments, maps promptTokens/completionTokens/totalTokens
into Usage, and maps finish reasons (stop/COMPLETE -> complete,
length/MAX_TOKENS -> length, tool_calls -> tool_use, else unknown).

Request encode/decode, streaming, and provider-surface registration
follow in subsequent changes.

Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
@fede-kamel
fede-kamel force-pushed the feat/oci-codec-1-types-response branch from 21d6e18 to 1b8a31f Compare July 24, 2026 20:26
@fede-kamel

Copy link
Copy Markdown
Author

Second CodeRabbit pass triaged:

  • Empty content: []None and error-path coverage — already fixed in the previous push; the re-posted comments anchor to the superseded diff. Current code returns Ok(None) for empty part lists (asserted in the tool-call test) and test_invalid_generic_content_shape_errors covers the InvalidArgument paths.
  • Missing ProviderNative fallback coverage — valid gap; added test_non_text_parts_preserved_as_provider_native (TEXT + IMAGE part list decodes to typed parts with the image preserved losslessly as a ProviderNative component).
  • Malformed tool calls silently dropped — declining intentionally: this mirrors the established built-in pattern (the Anthropic codec's tool-call decode uses the same filter_map drop semantics), and diverging here would make OCI behave inconsistently with the other providers. Happy to revisit codec-wide in a follow-up if maintainers prefer logging.

Suite on the updated tip: 34 OCI codec tests green, clippy zero warnings, full stack rebased.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/core/src/codec/oci_genai.rs`:
- Around line 313-333: The decode_response_tool_call function currently assigns
an empty string when the OCI response omits id, causing parallel Cohere tool
calls to collide. Replace the unwrap_or_default fallback with a stable, unique
per-call identifier derived from the available tool-call data, while preserving
the provided id unchanged when present.
🪄 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: Enterprise

Run ID: bb97e075-db42-4f75-be55-471c3f8be155

📥 Commits

Reviewing files that changed from the base of the PR and between 21d6e18 and 1b8a31f.

📒 Files selected for processing (5)
  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/types/src/codec/request.rs
  • crates/types/src/codec/response.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (17)
**/*.rs

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.rs: If any Rust code changed, always run just test-rust.
If any Rust code changed, also run cargo fmt --all.
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
{crates/core/src/plugin/dynamic/**,crates/plugin/**,crates/worker/**,crates/worker-proto/**,crates/types/**,python/plugin/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Keep the stable boundary explicit: native plugins cross a C ABI, and worker plugins cross grpc-v1.

Files:

  • crates/types/src/codec/request.rs
  • crates/types/src/codec/response.rs
{crates/**/src/**/*.rs,python/**/*.py}

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/src/codec/oci_genai.rs
crates/types/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)

Runtime helpers must cover marks, scopes, continuations, and isolated scope stacks.

Files:

  • crates/types/src/codec/request.rs
  • crates/types/src/codec/response.rs
**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,go,js,ts}

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/types/src/codec/request.rs
  • crates/core/src/codec/mod.rs
  • crates/types/src/codec/response.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
{crates/core,crates/adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/core/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/core/src/{api/**/*.rs,api/runtime/**/*.rs,codec/**/*.rs,json.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement the new or changed public runtime behavior first in the Rust core, especially under crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, and crates/core/src/json.rs.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/src/codec/oci_genai.rs
crates/{core,adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full validation matrix across Rust, Python, Go, and Node.js.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/src/codec/mod.rs
  • crates/core/tests/unit/codec/oci_genai_tests.rs
  • crates/core/src/codec/oci_genai.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/codec/oci_genai_tests.rs
🔇 Additional comments (5)
crates/types/src/codec/request.rs (1)

537-549: LGTM!

crates/types/src/codec/response.rs (1)

329-339: LGTM!

crates/core/src/codec/oci_genai.rs (1)

1-354: Rest of the file (key-convention helpers, GENERIC content decoding, envelope/chat_response split, usage mapping, finish-reason mapping) is correct and the previously-flagged empty-content and error-path issues are now addressed.

crates/core/src/codec/mod.rs (1)

19-19: LGTM!

crates/core/tests/unit/codec/oci_genai_tests.rs (1)

1-247: LGTM! Both previously-flagged gaps (invalid-content error path, mixed-parts ProviderNative coverage) are now covered.

Comment on lines +313 to +333
fn decode_response_tool_call(value: &Json) -> Option<ResponseToolCall> {
let obj = value.as_object()?;
let name = get_first(obj, "name")?.as_str()?.to_string();
let arguments = match get_first(obj, "arguments") {
Some(Json::String(text)) => {
// CRITICAL: GENERIC arguments arrive JSON-encoded; parse for the
// normalized shape, preserving the raw string when unparseable.
serde_json::from_str::<Json>(text).unwrap_or_else(|_| Json::String(text.clone()))
}
Some(other) => other.clone(),
None => get_first(obj, "parameters").cloned().unwrap_or(Json::Null),
};
Some(ResponseToolCall {
id: get_first(obj, "id")
.and_then(Json::as_str)
.unwrap_or_default()
.to_string(),
name,
arguments,
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Cohere tool calls need a unique fallback id
When OCI omits id, every Cohere tool call gets "", so parallel calls become indistinguishable. Synthesize a stable per-call fallback instead of defaulting to an empty string.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/core/src/codec/oci_genai.rs` around lines 313 - 333, The
decode_response_tool_call function currently assigns an empty string when the
OCI response omits id, causing parallel Cohere tool calls to collide. Replace
the unwrap_or_default fallback with a stable, unique per-call identifier derived
from the available tool-call data, while preserving the provided id unchanged
when present.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature a new feature lang:rust PR changes/introduces Rust code size:L PR is large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant