Skip to content

feat(llm): add an OCI Generative AI chat provider - #122

Open
fede-kamel wants to merge 4 commits into
tinyhumansai:mainfrom
fede-kamel:feat/oci-genai-provider
Open

fede-kamel wants to merge 4 commits into
tinyhumansai:mainfrom
fede-kamel:feat/oci-genai-provider

Conversation

@fede-kamel

@fede-kamel fede-kamel commented Oct 21, 2026 •

Copy link
Copy Markdown

Summary

Adds an OCI Generative AI chat provider to tinyinference-llm (providers::oci), plus an oci preset in the tinyinference-providers builtin catalog.

  • Auth:
    • Generative AI API key (bearer).
    • IAM request signing: an API-signing-key profile from ~/.oci/config, a session token, or a resource principal.
    • Behind the off-by-default oci-principals feature: instance principal and OKE workload identity. That feature pulls in OpenSSL.
  • Transports:
    • OpenAI-compatible /openai/v1 and /20231130/actions/v1, through the existing OpenAI adapter.
    • The native chat API (/20231130/actions/chat, GENERIC and COHERE formats), with its own request, response and SSE stream mapping.
  • Serving: on-demand by model id, or a dedicated endpoint OCID.
  • Entry point: build_oci_model(OciConfig) -> Result<Arc<dyn ChatModel<()>>>. load_profile reads an OCI config profile.

Related issue

None.

API or behavior changes

  • New public module tinyinference_llm::providers::oci.
  • New feature oci-principals, off by default.
  • OpenAiModel gains a RequestSigner hook. It signs the fully built request before it is sent, and it is unused unless set.
  • BuiltinAuthStyle::Oci and an oci entry in BUILTIN_CLOUD_PROVIDERS. Adding the variant breaks hosts that match BuiltinAuthStyle exhaustively; the OpenHuman host is updated in its own PR.
  • is_reasoning_model now also matches gpt-6* and OCI's openai.-prefixed ids. Requests to those models get max_completion_tokens instead of max_tokens.

Behavior found against the live service and fixed here:

  • Token limit: OpenAI models on the native API need maxCompletionTokens.
  • Sampling: OpenAI reasoning models reject a non-default temperature or top_p, on both the native and /openai/v1 paths, so the provider leaves them out for those models.
  • Provider options: OpenAI-wire provider_options such as prompt_cache_key are rejected by the native API, so the native path drops them.
  • Compartment: IAM-signed /openai/v1 calls need opc-compartment-id. It is now sent on both OpenAI-compatible bases whenever a compartment is configured.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo build --all-targets --all-features
  • cargo test --all-features: all pass
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features

Live check, tested with OCI GenAI: examples/live_oci.rs ran a completion, a streamed completion and a streamed tool round trip on 10 model/transport cases. All 30 checks passed with IAM signing and all 30 passed with a GenAI API key. The cases covered OpenAI, xAI, Meta, Google and Cohere models over all four transports.

Tests

  • Unit tests sit beside each module in *_tests.rs files. They cover:
    • request signing, checked against OpenSSL signatures, and principal token exchange against mocked endpoints. The RSA key and the leaf certificate are generated by OpenSSL (a dev-dependency) when the tests run; no key material is committed, and the branch history was rewritten so no earlier commit carries any
    • request and response mapping, SSE stream reconstruction (text, tool-call deltas, usage, finish reasons) and error classification
    • config-file profile parsing
    • the OpenAI-compatible wiring: headers, auth style, compartment and project, and dropping reasoning-model parameters
  • examples/live_oci.rs is the credential-gated live smoke test. It exits 0 with "skipped" when OCI_LIVE_PROFILE / OCI_LIVE_API_KEY are unset, so CI never calls the service.
  • Not covered live: instance principal and OKE workload identity need an OCI VM or an OKE pod, so they are tested against mocked metadata and token endpoints only. Session-token profiles and dedicated endpoints are also mock-tested only.

Documentation

Rustdoc on every public item. The live example's header documents its environment variables.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

cc @senamakel @M3gA-Mind for review and merge.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9f86a4ad-275d-4b4d-b8d0-c68ee1c9f184
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@tinysweeper

tinysweeper Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Findings

No active actionable findings.

Advisory notes

  • medium: Canonicalize the OCI finish reason before returning it (crates/tinyinference-llm/src/providers/oci/response.rs:131)
    Problem: `crates/tinyinference-llm/src/model/finish_reason.rs` states the crate-wide contract: "every adapter routes the value through [`canonical_finish_reason`] before it reaches [`ModelR
    Suggested fix:
            choice["finishReason"]
                .as_str()
                .map(|raw| crate::model::canonical_finish_reason(raw.to_string())),
    

Resolved this pass

  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator
  • Remove the committed private key (an RSA private key)
  • Remove the committed private key (a private key)
  • Guard the tool-call slot before indexing an empty accumulator

Verdict: Incomplete · Priority: none
Coverage: Reviewed 20 of 38 files; not reviewed: Cargo.lock; not reviewed (large PR): Cargo.toml, crates/tinyinfer…, and 15 additional unreviewed files.

Diagnostics and supporting details

Full summary

Pull request purpose (title): feat(llm): add an OCI Generative AI chat provider. Pull-request purpose (title): feat(llm): add an OCI Generative AI chat provider. The change adds a new `crates/tinyinference-llm/src/providers/oci/` module, registered from `crates/tinyinference-llm/src/providers/mod.rs`, supporting OCI Generative AI API keys, user-principal, session-token and session-token-file signing, resource principals, host-supplied token sources, and feature-gated instance-principal and OKE workload identity, over both an OpenAI-compatible transport and a native `actions/chat` transport. It also adds a host-supplied request-signer hook to the shared OpenAI adapter, broadens reasoning-model detection to `gpt-6` and OCI's `openai.`-prefixed ids, and adds an `oci` preset and `BuiltinAuthStyle::Oci` to the builtin provider catalog. The tests and description lanes are Answered and report no blocking issue, having withdrawn earlier committed-key findings.

Unreviewed paths

  • Cargo.lock
  • Cargo.toml
  • crates/tinyinference-llm/Cargo.toml
  • crates/tinyinference-llm/examples/live_oci.rs
  • crates/tinyinference-llm/src/providers/mod.rs
  • crates/tinyinference-llm/src/providers/oci/auth_tests.rs
  • crates/tinyinference-llm/src/providers/oci/config_file.rs
  • crates/tinyinference-llm/src/providers/oci/config_file_tests.rs
  • crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs
  • crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs
  • crates/tinyinference-llm/src/providers/oci/principals/mod.rs
  • crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs
  • crates/tinyinference-llm/src/providers/oci/response_tests.rs
  • crates/tinyinference-llm/src/providers/oci/stream_tests.rs
  • crates/tinyinference-llm/src/providers/openai/mod.rs
  • crates/tinyinference-llm/src/providers/openai/mod_tests.rs
  • crates/tinyinference-providers/src/builtin.rs
  • crates/tinyinference-providers/src/builtin_tests.rs

Partial review reasons

  • critique: Cargo.toml — not selected by the large-review budget
  • security: Cargo.toml — not selected by the large-review budget
  • critique: crates/tinyinference-llm/Cargo.toml — not selected by the large-review budget
  • security: crates/tinyinference-llm/Cargo.toml — not selected by the large-review budget
  • critique: crates/tinyinference-llm/examples/live_oci.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/examples/live_oci.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/mod.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/mod.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/auth_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/auth_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/config_file.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/config_file.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/config_file_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/config_file_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/principals/mod.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/principals/mod.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/response_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/response_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/oci/stream_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/oci/stream_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/openai/mod.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/openai/mod.rs — not selected by the large-review budget
  • critique: crates/tinyinference-llm/src/providers/openai/mod_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-llm/src/providers/openai/mod_tests.rs — not selected by the large-review budget
  • critique: crates/tinyinference-providers/src/builtin.rs — not selected by the large-review budget
  • security: crates/tinyinference-providers/src/builtin.rs — not selected by the large-review budget
  • critique: crates/tinyinference-providers/src/builtin_tests.rs — not selected by the large-review budget
  • security: crates/tinyinference-providers/src/builtin_tests.rs — not selected by the large-review budget

Review snapshot

Change surface Files Review signal Count
Production 20 Active findings 0
Tests 15 Noted findings 1
Documentation 0 Resolved findings 31
Configuration 2 Pending checks/questions 51

Completeness: Incomplete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

What changed

Latest-push-delta unavailable: review state holds prior reviewed head `7920d4bab7e536ded93f1945b93742d5f5bcd945` and new head `5506ff3208bdbb21d1852d86ed9f632035311dee`, but there is no trusted base-to-head diff comparison, so no push-level change description is given. The whole-pull-request behavior is described in the features and executive summary.

Features

  • Added — OCI Generative AI provider with multiple auth styles: Hosts can build a chat model against OCI using API keys, user principals, session tokens, session-token files, resource principals, and host-supplied token sources, with feature-gated instance and OKE principals; static keys are parsed at build time while dynamic material (file re-reads, resource-principal env material, token sources) is fetched per request with the parsed key cached until the PEM changes. (crates/tinyinference-llm/src/providers/oci/auth.rs, crates/tinyinference-llm/src/providers/oci/config.rs, crates/tinyinference-llm/src/providers/oci/mod.rs)
  • Added — OCI service endpoint resolution and validation: Endpoints derive from a region or an explicit override; non-HTTPS endpoints are rejected except loopback hosts, region characters are validated, and a missing region/endpoint fails at build time. (crates/tinyinference-llm/src/providers/oci/config.rs)
  • Added — OCI CLI config-file profile loading: Profiles in `/.oci/config` resolve to user-principal or session-token-file auth with DEFAULT-section inheritance, `` expansion, `OCI_CLI_CONFIG_FILE` override, and explicit rejection of passphrase-protected keys. (crates/tinyinference-llm/src/providers/oci/config_file.rs, crates/tinyinference-llm/src/providers/oci/config_file_tests.rs)
  • Added — OCI OpenAI-compatible and native chat transports: One configuration can call `/openai/v1`, `/20231130/actions/v1`, or the native `/20231130/actions/chat` with GENERIC or COHERE payloads, including dedicated AI cluster endpoint addressing; the native transport requires a compartment id, and OpenAI-family models get `maxCompletionTokens` while reasoning models drop temperature/top_p. (crates/tinyinference-llm/src/providers/oci/request.rs, crates/tinyinference-llm/src/providers/oci/response.rs, crates/tinyinference-llm/src/providers/oci/stream.rs)
  • Added — OCI HTTP signature signing: Requests using signed auth produce `Signature version="1"` authorization headers with `x-content-sha256` digests instead of a bearer credential, with a host-omitting variant used for the X.509 federation exchange. (crates/tinyinference-llm/src/providers/oci/signer.rs)
  • Added — Instance-principal and OKE workload-identity exchanges: Behind the off-by-default `oci-principals` feature, IMDS-derived instance identity is exchanged at the X.509 federation endpoint and a Kubernetes service-account token at the cluster proxymux for session tokens bound to a freshly generated RSA keypair, with expiry-aware caching; without the feature both flows return an unsupported error naming it. (crates/tinyinference-llm/src/providers/oci/principals/instance.rs, crates/tinyinference-llm/src/providers/oci/principals/oke.rs, crates/tinyinference-llm/src/providers/oci/principals/token.rs, crates/tinyinference-llm/src/providers/oci/principals/mod.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs)
  • Modified — Host-supplied request signer hook on OpenAiModel: `OpenAiModel` can be built with `AuthStyle::None` plus a host-provided signer so signature-authenticated providers such as OCI work through the shared OpenAI adapter; `/openai/v1` gains `OpenAI-Project` and both bases gain `opc-compartment-id` when a compartment is configured. (crates/tinyinference-llm/src/providers/openai/transport.rs pub struct OpenAiModel {, crates/tinyinference-llm/src/providers/openai/transport.rs impl OpenAiModel {, crates/tinyinference-llm/src/providers/types.rs impl std::fmt::Debug for ProviderRequestOptions {, crates/tinyinference-llm/src/providers/oci/config.rs)
  • Modified — Reasoning-model detection broadened for OCI vendor prefixes: Reasoning detection now strips an `openai.` prefix and matches `gpt-6` ids, so those models receive `max_completion_tokens` and omit sampling parameters. (crates/tinyinference-llm/src/providers/openai/transport.rs pub(super) fn is_anthropic_model(model: &str) -> bool {, crates/tinyinference-llm/src/providers/openai/mod.rs pub mod server;, crates/tinyinference-llm/src/providers/openai/mod_tests.rs fn routes_max_tokens_to_max_completion_tokens_for_o_series() {)
  • 1 additional supported feature(s) omitted by the configured limit.

Tests

  • unit — `crates/tinyinference-llm/src/providers/oci/auth_tests.rs` asserts that API keys resolve to bearer, user-principal and session-token key ids are formed correctly, dynamic token sources are consulted and trimmed, session-token files are re-read on each use, disabled flows error without the feature, bad static keys fail at resolve time, and Debug output redacts secrets.: Covers auth resolution success and error paths; not claimed executed. (crates/tinyinference-llm/src/providers/oci/auth_tests.rs, crates/tinyinference-llm/src/providers/oci/auth.rs)
  • unit — `crates/tinyinference-llm/src/providers/oci/config_file_tests.rs` asserts DEFAULT inheritance and overrides, session-token-file resolution, missing-profile and passphrase errors, missing required keys, and tilde expansion only with a home directory.: Covers config parser success and error paths; not claimed executed. (crates/tinyinference-llm/src/providers/oci/config_file_tests.rs, crates/tinyinference-llm/src/providers/oci/config_file.rs)
  • unit — `crates/tinyinference-llm/src/providers/oci/config_tests.rs` asserts endpoint derivation and rejection, bearer vs. signer wiring and extra headers, reasoning-model token/sampling handling on both paths, native compartment requirement, dedicated serving addressing, and key non-leakage in Debug.: Covers construction-policy branches; not claimed executed. (crates/tinyinference-llm/src/providers/oci/config_tests.rs, crates/tinyinference-llm/src/providers/oci/config.rs)
  • unit — `crates/tinyinference-llm/src/providers/oci/signer_tests.rs` verifies produced signatures against OpenSSL-computed signatures, rejects encrypted and malformed PEM, checks signing-string shapes for GET and POST, empty-body digests, port preservation, and host-omitting federation signing.: Signature bytes checked against an independent implementation; not claimed executed. (crates/tinyinference-llm/src/providers/oci/signer_tests.rs, crates/tinyinference-llm/src/providers/oci/signer.rs, crates/tinyinference-llm/src/providers/oci/fixtures.rs)
  • unit — `crates/tinyinference-llm/src/providers/oci/request_tests.rs` and `crates/tinyinference-llm/src/providers/oci/response_tests.rs` assert GENERIC and COHERE request mapping, `max_completion_tokens` selection, reasoning sampling omission, dropping of non-native provider options, unary response parsing including malformed tool arguments, and usage fallbacks.: Asserts on produced JSON and parsed output; not claimed executed. (crates/tinyinference-llm/src/providers/oci/request_tests.rs, crates/tinyinference-llm/src/providers/oci/response_tests.rs)
  • unit — `crates/tinyinference-llm/src/providers/oci/stream_tests.rs` feeds raw SSE bytes through the production state machine, asserting text reconstruction, split-chunk and `[DONE]` handling, tool-call fragment accumulation including a fragment arriving before any id, COHERE final-chunk de-duplication, partial-message provider failure on EOF without a finish reason, and error-event and bad-JSON failures.: Drives the real stream state machine with byte fixtures; not claimed executed. (crates/tinyinference-llm/src/providers/oci/stream_tests.rs, crates/tinyinference-llm/src/providers/oci/stream.rs)
  • unit — `crates/tinyinference-llm/src/providers/oci/principals/instance_tests.rs`, `oke_tests.rs`, `token_tests.rs`, `keys_tests.rs` and `disabled_tests.rs` drive the principal exchanges against a loopback mock, asserting request shapes, caching, 4xx non-retry, expiry and half-life renewal, key and certificate parsing, and feature-disabled errors.: Exercised against mocked endpoints only per the description; not claimed executed. (crates/tinyinference-llm/src/providers/oci/principals/instance_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/oke_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs)
  • unit — `crates/tinyinference-providers/src/builtin_tests.rs` asserts the builtin preset table includes the `oci` entry with its label, endpoint and `BuiltinAuthStyle::Oci`.: Covers preset metadata only; not claimed executed. (crates/tinyinference-providers/src/builtin_tests.rs fn builtin_cloud_provider_defaults_cover_phase_one_presets() {, crates/tinyinference-providers/src/builtin.rs pub enum BuiltinAuthStyle {)

Before merge

  • Complete the critique review for crates/tinyinference-llm/src/providers/oci/auth_tests.rs, crates/tinyinference-llm/src/providers/oci/response_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs, crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs, crates/tinyinference-llm/Cargo.toml, Cargo.toml, crates/tinyinference-llm/src/providers/oci/config_file.rs, crates/tinyinference-llm/src/providers/oci/config_file_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mod.rs, crates/tinyinference-llm/src/providers/mod.rs, crates/tinyinference-llm/src/providers/openai/mod.rs, crates/tinyinference-llm/src/providers/openai/mod_tests.rs, crates/tinyinference-llm/examples/live_oci.rs, crates/tinyinference-llm/src/providers/oci/stream_tests.rs, crates/tinyinference-providers/src/builtin.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs, crates/tinyinference-providers/src/builtin_tests.rs.
  • Complete the security review for crates/tinyinference-llm/src/providers/oci/auth_tests.rs, crates/tinyinference-llm/src/providers/oci/response_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs, crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs, crates/tinyinference-llm/Cargo.toml, Cargo.toml, crates/tinyinference-llm/src/providers/oci/config_file.rs, crates/tinyinference-llm/src/providers/oci/config_file_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mod.rs, crates/tinyinference-llm/src/providers/mod.rs, crates/tinyinference-llm/src/providers/openai/mod.rs, crates/tinyinference-llm/src/providers/openai/mod_tests.rs, crates/tinyinference-llm/examples/live_oci.rs, crates/tinyinference-llm/src/providers/oci/stream_tests.rs, crates/tinyinference-providers/src/builtin.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs, crates/tinyinference-providers/src/builtin_tests.rs.
  • Review uncovered paths: Cargo.toml, crates/tinyinference-llm/Cargo.toml, crates/tinyinference-llm/examples/live_oci.rs, crates/tinyinference-llm/src/providers/mod.rs, crates/tinyinference-llm/src/providers/oci/auth_tests.rs, crates/tinyinference-llm/src/providers/oci/config_file.rs, crates/tinyinference-llm/src/providers/oci/config_file_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs, crates/tinyinference-llm/src/providers/oci/principals/mod.rs, crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs, crates/tinyinference-llm/src/providers/oci/response_tests.rs, crates/tinyinference-llm/src/providers/oci/stream_tests.rs, crates/tinyinference-llm/src/providers/openai/mod.rs, crates/tinyinference-llm/src/providers/openai/mod_tests.rs, crates/tinyinference-providers/src/builtin.rs, crates/tinyinference-providers/src/builtin_tests.rs.

How this fits together

flowchart LR
  n0["OpenAiModel<br/>changed"]:::changed
  n1["ProviderRequestOptions<br/>changed"]:::changed
  n2["BuiltinAuthStyle<br/>changed"]:::changed
  n3["BuiltinCloudProvider<br/>changed"]:::changed
  n4["build_with"]:::impacted
  n5["builtin_cloud_provider"]:::impacted
  n6["builtin_cloud_supports_responses_api"]:::impacted
  n7["endpoint_host_is_chat_completions_only"]:::impacted
  n8["...es_with_slug_capability_for_every_builtin"]:::impacted
  n9["Client"]:::impacted
  n0 -->|uses| n1
  n0 -->|uses| n9
  n1 -->|uses| n9
  n3 -->|uses| n2
  n4 -->|uses| n0
  n5 -->|uses| n3
  n6 -->|calls| n5
  n7 -->|calls| n6
  n8 -->|calls| n6
  n8 -->|tests| n6
  n8 -->|calls| n7
  n8 -->|tests| n7
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered files: crates/tinyinference-llm/src/providers/oci/auth_tests.rs, crates/tinyinference-llm/src/providers/oci/response_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs, crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs, crates/tinyinference-llm/Cargo.toml, Cargo.toml, crates/tinyinference-llm/src/providers/oci/config_file.rs, crates/tinyinference-llm/src/providers/oci/config_file_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mod.rs, crates/tinyinference-llm/src/providers/mod.rs, crates/tinyinference-llm/src/providers/openai/mod.rs, crates/tinyinference-llm/src/providers/openai/mod_tests.rs, crates/tinyinference-llm/examples/live_oci.rs, crates/tinyinference-llm/src/providers/oci/stream_tests.rs, crates/tinyinference-providers/src/builtin.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs, crates/tinyinference-providers/src/builtin_tests.rs
  • Lane summary: Reviewed 6 of 23 files — 17 not reviewed. Reviewed 6 files; 2 findings. 17 files were omitted: not selected by the large-review budget.

security

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered files: crates/tinyinference-llm/src/providers/oci/auth_tests.rs, crates/tinyinference-llm/src/providers/oci/response_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mock_http.rs, crates/tinyinference-llm/src/providers/oci/principals/token_tests.rs, crates/tinyinference-llm/Cargo.toml, Cargo.toml, crates/tinyinference-llm/src/providers/oci/config_file.rs, crates/tinyinference-llm/src/providers/oci/config_file_tests.rs, crates/tinyinference-llm/src/providers/oci/principals/mod.rs, crates/tinyinference-llm/src/providers/mod.rs, crates/tinyinference-llm/src/providers/openai/mod.rs, crates/tinyinference-llm/src/providers/openai/mod_tests.rs, crates/tinyinference-llm/examples/live_oci.rs, crates/tinyinference-llm/src/providers/oci/stream_tests.rs, crates/tinyinference-providers/src/builtin.rs, crates/tinyinference-llm/src/providers/oci/principals/disabled_tests.rs, crates/tinyinference-providers/src/builtin_tests.rs
  • Lane summary: Reviewed 6 of 23 files — 17 not reviewed. Reviewed 6 files; 0 findings. 17 files were omitted: not selected by the large-review budget.

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The tests lane is Answered and reports the new OCI request/response mapping, SSE reconstruction, signer verification against a known OpenSSL signature, token caching, and both principal exchanges carry real assertions including error paths; it also reports the earlier committed-key and empty-accumulator panic findings are resolved.
  • Lane summary: The earlier committed-key findings are resolved: fixtures.rs now generates the RSA key and certificate at test time and no key material is committed. The empty-accumulator panic in the tool-call slot logic is also fixed and pinned by `tool_call_fragment_before_any_id_does_not_panic`. The new OCI provider, signer, request/response mapping, stream state machine, token cache, and config-file parser all carry tests that assert on concrete wire shapes and would fail on regression; I found no remaining defect worth blocking on.

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The commits lane is Answered and reports no sensitive content in committed files, while noting 4 earlier findings still open.
  • Lane summary: No sensitive content in committed files. (4 earlier finding(s) still open)

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The description lane is Answered and reports the PR body matches the diff: auth, signer, principals, native request/response/stream mapping, the live example, and the OpenAI `RequestSigner` hook and reasoning-model widening. It withdraws earlier committed-private-key findings because the key material in `crates/tinyinference-llm/src/providers/oci/fixtures.rs` is generated at runtime by OpenSSL rather than committed.
  • Lane summary: The earlier committed-key findings are resolved: the fixtures now generate the RSA key and leaf certificate at test time with OpenSSL, and the tool-call accumulator guards the empty case before indexing. The new commits (ring/httpdate deps, the `oci-principals` feature, the live example, the principals/token/stream modules and the `oci` builtin preset) look sound; I found no new defect that meets the reporting bar.
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash
  • Spend: $0.015334
  • Tokens: 1184123 input · 12450 output · 362496 cached · 816 embedding
  • Updated: 2026-11-11T15:59:41Z
  • Continuity: summary cache chain restarted at the storage ceiling.
Head State Pass summary
5afbf4478790 incomplete 3 active finding(s), 0 resolved finding(s) (at 2026-10-21T19:28:54Z)
3a923b836e96 incomplete 0 active finding(s), 27 resolved finding(s) (at 2026-10-21T19:36:01Z)
257befa91bff incomplete 0 active finding(s), 30 resolved finding(s) (at 2026-10-22T14:52:53Z)
7920d4bab7e5 incomplete 1 active finding(s), 26 resolved finding(s) (at 2026-11-06T18:34:07Z)
5506ff3208bd incomplete 0 active finding(s), 31 resolved finding(s) (at 2026-11-11T15:59:41Z)

tinysweeper 0.1.2

@tinysweeper tinysweeper 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.

Requesting changes: 1 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

Diagnostics

Total spend: $0.0105


/// PKCS#1 (`RSA PRIVATE KEY`) form of the same key.
pub(super) const TEST_PKCS1_PEM: &str = "\
-----BEGIN RSA PRIVATE KEY-----\n\

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority critical commits confident

Remove the committed private key (an RSA private key)

Rotate the key, remove it from the working tree, and purge it from history — a force-push alone does not remove it from forks or from anyone who already fetched.

[RULE] private-key ·

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in c21d902. The tests now generate the RSA key and the leaf certificate with OpenSSL (dev-dependency) at test time, and the branch was rewritten so no commit contains key material. The key was a throwaway test fixture and was never an OCI credential.

assert!(pair.public_pem.starts_with("-----BEGIN PUBLIC KEY-----"));
assert!(
pair.private_pem
.starts_with("-----BEGIN RSA PRIVATE KEY-----")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority critical commits confident

Remove the committed private key (an RSA private key)

Rotate the key, remove it from the working tree, and purge it from history — a force-push alone does not remove it from forks or from anyone who already fetched.

[RULE] private-key ·

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in c21d902. The tests now generate the RSA key and the leaf certificate with OpenSSL (dev-dependency) at test time, and the branch was rewritten so no commit contains key material. The key was a throwaway test fixture and was never an OCI credential.

fn malformed_pem_is_a_validation_error() {
assert!(SigningKey::from_pem("not pem").is_err());
assert!(
SigningKey::from_pem("-----BEGIN PRIVATE KEY-----\n!!!\n-----END PRIVATE KEY-----")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority critical commits confident

Remove the committed private key (a private key)

Rotate the key, remove it from the working tree, and purge it from history — a force-push alone does not remove it from forks or from anyone who already fetched.

[RULE] private-key ·

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in c21d902. The tests now generate the RSA key and the leaf certificate with OpenSSL (dev-dependency) at test time, and the branch was rewritten so no commit contains key material. The key was a throwaway test fixture and was never an OCI credential.

@fede-kamel
fede-kamel force-pushed the feat/oci-genai-provider branch 2 times, most recently from 3a923b8 to c21d902 Compare October 22, 2026 14:33
fede-kamel added a commit to fede-kamel/tinyagents that referenced this pull request Oct 22, 2026
Moves vendor/tinyinference to tinyinference main plus the OCI Generative
AI provider (tinyhumansai/tinyinference#122). The path dependencies are
already at 0.5.0, so only the gitlink and Cargo.lock change; the lock
follows tinyinference main's switch of its secret store to
tinystoragedrivers-api.
fede-kamel added a commit to fede-kamel/tinyagents that referenced this pull request Oct 22, 2026
Moves vendor/tinyinference to tinyinference main plus the OCI Generative
AI provider (tinyhumansai/tinyinference#122). The path dependencies are
already at 0.5.0, so only the gitlink and Cargo.lock change; the lock
follows tinyinference main's switch of its secret store to
tinystoragedrivers-api.

@tinysweeper tinysweeper 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.

tinysweeper could not complete coverage (27 unanswered item(s)), so this is not an approval.

Diagnostics

Total spend: $0.0135

fede-kamel added a commit to fede-kamel/openhuman that referenced this pull request Oct 22, 2026
Review fixes for the OCI Generative AI provider:

- Endpoint: the built-in preset's URL is a display default. Settings no
  longer saves it as the entry endpoint, and the factory ignores it, so
  a non-Chicago region is no longer sent to us-chicago-1. An explicit
  override (another realm, a private endpoint) is kept on save.
- Project: the `openai` transport (`/openai/v1`) requires
  `oci.project_id`, in the factory and in the settings form, with a
  translated message in every locale.
- Billing: keyless OCI modes (profiles, session tokens, principals) count
  as usable BYOK credentials, so the managed-budget gate no longer blocks
  them.
- Temperature: a route's `@<temperature>` suffix now reaches OCI models
  through the new `OciConfig::temperature_override`.
- Settings: custom OCI slugs (e.g. `oci-cohere`) open the OCI dialog and
  keep their label and `oci` block instead of the generic editor, and a
  failed key deletion aborts a switch to a keyless mode and restores the
  previous providers.

Moves vendor/tinyagents to tinyhumansai/tinyagents#517, which pins
tinyinference with the OCI provider (tinyhumansai/tinyinference#122).
@fede-kamel

Copy link
Copy Markdown
Author

@senamakel these are all rebased on current main with the bot findings addressed. Merge order, since three of them stack:

  1. feat(llm): add an OCI Generative AI chat provider #122: OCI Generative AI chat provider. Green. The test keys are now generated at test time, so none are in history.
  2. chore(deps): bump tinyinference for the OCI Generative AI provider tinyagents#517: bumps tinyinference to feat(llm): add an OCI Generative AI chat provider #122. Green once feat(llm): add an OCI Generative AI chat provider #122 lands.
  3. feat(inference): add OCI Generative AI as a cloud provider openhuman#8183: OCI as a BYOK cloud provider, on top of #517.

Independent:

The openhuman lanes that are still red fail in files these PRs don't touch: the observability.rs unused doc comment, the stale docs/storage-schema.md, and the tinyeventqueues pin. Other outside PRs (#8205, #8168, #8169) fail them the same way.

Thanks!

Add `providers::oci` to tinyinference-llm and an `oci` preset to the
tinyinference-providers builtin catalog.

- Auth: Generative AI API key (bearer); IAM request signing from an
  `~/.oci/config` API-signing-key profile, a session token or a resource
  principal; and, behind the off-by-default `oci-principals` feature
  (OpenSSL), instance principal and OKE workload identity.
- Transports: OpenAI-compatible `/openai/v1` and `/20231130/actions/v1`
  through the OpenAI adapter, which gains a `RequestSigner` hook, and the
  native `/20231130/actions/chat` API (GENERIC and COHERE formats) with
  its own request, response and SSE stream mapping.
- Serving: on-demand by model id or a dedicated endpoint OCID.
- Live-service fixes: `maxCompletionTokens` for OpenAI models on the
  native API, no sampling parameters for OpenAI reasoning models, no
  OpenAI-wire provider options on the native API, and
  `opc-compartment-id` on both OpenAI-compatible bases.
- `examples/live_oci.rs` runs a credential-gated live matrix and skips
  when no credentials are set.

Tests sign with an RSA key and a self-signed leaf certificate generated
by OpenSSL (a dev-dependency) at test time, so no key material is
committed.
Like OpenAiConfig::temperature_override: the value replaces the request's
temperature on both the OpenAI-compatible and native transports, and
OpenAI reasoning models still receive none. Hosts that encode a
per-route temperature can now apply it to OCI models.
@fede-kamel
fede-kamel force-pushed the feat/oci-genai-provider branch from 257befa to 7920d4b Compare November 6, 2026 18:31

@tinysweeper tinysweeper 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.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

Diagnostics

Total spend: $0.0131


impl Acc {
fn delta_tool(&mut self, id: &str, name: &str, args: &str, slot_hint: usize) -> usize {
let existing = if id.is_empty() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority high critique likely

Guard the tool-call slot before indexing an empty accumulator

When `id` is empty (a continuation fragment) and no call has been seen yet, `self.calls` is empty, so `slot_hint.min(0)` is `0`. The `is_empty()` fallback below only runs when `existing != 0`, which a zero never satisfies, so `self.calls[existing]` indexes an empty `Vec` and panics. Reachable input: a GENERIC stream whose first tool-call fragment carries no id, e.g. `data: {"message":{"toolCalls":[{"name":"get_weather","arguments":"{"}}]}}\n`. The provider may split the arguments across chunks and let the id arrive on a later fragment; nothing in the adapter requires the id to come first. A panic here aborts the stream instead of producing a `ProviderFailed` terminal item, violating the rule that stream adapters must emit terminal `Completed` or `ProviderFailed` items.

[RULE] unchecked-index ·

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 5506ff3. The fallback did push a slot before indexing, so it could not panic, but it was easy to misread. An id-less fragment now opens its slot up front, and a later fragment carrying the id adopts that slot instead of starting a second call. New test: tool_call_fragment_before_any_id_does_not_panic.

@tinysweeper tinysweeper 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.

tinysweeper could not complete coverage (17 unanswered item(s)), so this is not an approval.

Diagnostics

Total spend: $0.0153

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant