Skip to content

feat(rook): add OpenAI-compatible gateway endpoints#627

Merged
yacosta738 merged 3 commits into
mainfrom
feat/rook-589-gateway-api
Apr 21, 2026
Merged

feat(rook): add OpenAI-compatible gateway endpoints#627
yacosta738 merged 3 commits into
mainfrom
feat/rook-589-gateway-api

Conversation

@yacosta738
Copy link
Copy Markdown
Contributor

Related Issues

closes #589


Summary

  • add OpenAI-compatible gateway endpoints for POST /v1/chat/completions and GET /v1/models
  • route OpenAI-style requests through Rook's account-aware routing engine and upstream proxy layer
  • persist provider api_key values locally and archive the completed gateway OpenSpec artifacts

Tested Information

  • cargo test --manifest-path "clients/rook/Cargo.toml" gateway::
  • cargo test --manifest-path "clients/rook/Cargo.toml" server::tests::
  • cargo test --manifest-path "clients/rook/Cargo.toml" open_in_memory_applies_account_api_key_migration
  • cargo test --manifest-path "clients/rook/Cargo.toml" insert_and_get_account_round_trips_api_key
  • cargo test --manifest-path "clients/rook/Cargo.toml" chat_completion_request_deserializes_typed_optional_fields
  • cargo test --manifest-path "clients/rook/Cargo.toml" proxy_chat_completion_without_api_key_still_forwards_request
  • verify result recorded as PASS WITH WARNINGS in archived OpenSpec verification report

Reviewer focus:

  • upstream proxy behavior for vendor auth/header handling
  • handler error mapping and stream rejection behavior
  • server composition at /v1 alongside /api/health and dashboard assets

Documentation Impact

  • Docs updated in:
    • openspec/specs/gateway/spec.md
    • openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md
    • openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md
    • openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md
    • openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md
    • openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md
  • No docs update required because:
  • I verified the documentation matches the current behavior.

Breaking Changes

None.


Checklist

  • I have checked that there isn’t already a PR solving the same problem.
  • I have read the Contributing Guidelines.
  • I ensured my code follows the project's style guidelines.
  • I have added or updated tests that prove my fix is effective or that my feature works.
  • I have updated the documentation, or I explained above why no documentation update is needed.
  • I verified the documentation matches the current behavior.
  • I have documented any breaking changes in the Breaking Changes section.
  • I have linked the related issue (if any).

Expose /v1/chat/completions and /v1/models so OpenAI-style clients can route through Rook with account-aware upstream proxying. Persist provider API keys locally and archive the completed gateway spec for future iteration.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 21, 2026

Deploying corvus with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5ddeb41
Status: ✅  Deploy successful!
Preview URL: https://bd3c7b46.corvus-42x.pages.dev
Branch Preview URL: https://feat-rook-589-gateway-api.corvus-42x.pages.dev

View logs

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

Warning

Rate limit exceeded

@yacosta738 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 24 minutes and 47 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 24 minutes and 47 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2483a5e0-6030-4c9f-9207-a2c2644a860d

📥 Commits

Reviewing files that changed from the base of the PR and between 41d7539 and 5ddeb41.

📒 Files selected for processing (14)
  • clients/rook/migrations/0003_account_api_key.sql
  • clients/rook/src/db/mod.rs
  • clients/rook/src/domain/mod.rs
  • clients/rook/src/gateway/handlers.rs
  • clients/rook/src/gateway/mod.rs
  • clients/rook/src/gateway/upstream.rs
  • clients/rook/src/gateway/vendor.rs
  • clients/rook/src/main.rs
  • clients/rook/src/server/mod.rs
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md
  • openspec/specs/gateway/spec.md
📝 Walkthrough

Walkthrough

This PR implements an OpenAI-compatible gateway for Rook, adding database support for per-account API keys, upstream HTTP proxying with vendor-specific auth, and two new endpoints (/v1/chat/completions and /v1/models) with comprehensive request/response types and error handling.

Changes

Cohort / File(s) Summary
Database Schema & Storage
clients/rook/migrations/0003_account_api_key.sql, clients/rook/src/db/account.rs, clients/rook/src/db/mod.rs, clients/rook/src/db/pool.rs, clients/rook/src/db/route.rs
Added api_key: Option<String> column to provider_accounts via new migration; updated all account insert/select/row-mapping queries to persist and retrieve api_key; added embedded migration runner checks and integration tests for the new schema version.
Domain Model
clients/rook/src/domain/mod.rs, clients/rook/src/server/mod.rs
Extended ProviderAccount struct with new api_key: Option<String> field; added db_path to ServerConfig for database initialization control.
Gateway Request/Response Types
clients/rook/src/gateway/types.rs
Defined OpenAI-compatible request/response serde structs: ChatCompletionRequest, ChatCompletionMessage, ChatCompletionResponse, ChatCompletionChoice, Usage, ModelObject, ModelListResponse, GatewayErrorResponse with extensive field preservation via flattened extras and polymorphic Stop enum.
Vendor Configuration & Auth
clients/rook/src/gateway/vendor.rs
Implemented vendor-specific base URL mapping (default_base_url), precedence resolution with override support (effective_base_url), and auth header construction (auth_header) with Anthropic x-api-key vs. standard Bearer token variants.
Upstream Proxying
clients/rook/src/gateway/upstream.rs
Created proxy_chat_completion function to forward raw JSON bodies to upstream providers, with vendor-aware URL/auth header construction, comprehensive error mapping (timeout, transport, non-2xx status), and response body/status capture via reqwest::Client.
Gateway Handlers & Routing
clients/rook/src/gateway/handlers.rs, clients/rook/src/gateway/mod.rs
Implemented handle_chat_completions with request parsing, stream rejection (400), routing resolution, upstream proxying, health tracking, and error response mapping; handle_list_models for model enumeration; introduced GatewayState struct and build_router function to compose endpoints.
Server Integration
clients/rook/src/server/mod.rs, clients/rook/src/main.rs
Updated run and new build_app to instantiate registry, routing engine, and shared reqwest::Client (30s timeout, rustls-tls); mounted gateway router at /v1 alongside existing routes; added integration tests verifying composed router and /v1/models availability.
Test Fixtures
clients/rook/src/routing/mod.rs, clients/rook/src/services/account.rs, clients/rook/Cargo.toml
Updated test helpers across routing and account services to initialize api_key: None; added reqwest (json, rustls-tls) and bytes dependencies; added tower dev dependency.
Specification & Documentation
openspec/specs/gateway/spec.md, openspec/changes/archive/2026-04-21-rook-589-gateway-api/*
Added comprehensive OpenAI gateway spec with M1 requirements, design doc, proposal, task breakdown, and verification report; created archive state yaml documenting completion of propose→spec→design→tasks→apply→verify phases.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Handler as Handler<br/>(chat_completions)
    participant Engine as RoutingEngine
    participant Upstream as Upstream<br/>Provider
    participant Health as Health<br/>Tracker

    Client->>Handler: POST /v1/chat/completions<br/>(model, messages, stream=false)
    
    Handler->>Handler: Parse request<br/>Reject if stream=true
    
    Handler->>Engine: resolve(model)
    Engine-->>Handler: ProviderAccount<br/>(with api_key)
    
    Handler->>Upstream: POST {vendor_url}/v1/chat<br/>(auth header, raw JSON body)
    
    alt Upstream Success (2xx)
        Upstream-->>Handler: 200 + response body
        Handler->>Health: mark_success(account)
        Handler-->>Client: 200 + response
    else Upstream Error
        Upstream-->>Handler: 4xx/5xx or timeout
        Handler->>Health: mark_failure(account,<br/>cooldown=60s)
        Handler->>Handler: Map to GatewayErrorResponse<br/>(502/504 with code)
        Handler-->>Client: Error response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

The PR spans multiple systems (database, HTTP proxying, vendor-specific logic, error mapping) with substantial new code, complex error handling paths, and security-sensitive auth header construction requiring careful verification across all control flows.

Possibly related PRs

  • PR #601: Extends domain models (adds api_key to ProviderAccount) that are foundational to gateway functionality.
  • PR #605: Modifies the persistence layer (db/account.rs) that this PR builds upon with api_key column integration.

Suggested labels

area:rust, area:web, area:docs, risk:high, risk:security

Suggested reviewers

  • yuniel-acosta
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title follows Conventional Commit format (feat prefix) and clearly summarizes the main change: adding OpenAI-compatible gateway endpoints.
Description check ✅ Passed PR description includes all required sections: Related Issues, Summary, Tested Information, Documentation Impact, Breaking Changes, and completed Checklist.
Linked Issues check ✅ Passed All coding objectives from #589 are met: endpoints implemented end-to-end, targeted tests provided (gateway::, server::tests::, specific account/proxy tests), and contracts documented in openspec/specs/gateway/spec.md.
Out of Scope Changes check ✅ Passed All changes directly support gateway implementation (database schema/migrations, domain models, upstream proxy, handlers, types, vendor mapping, server wiring) and OpenSpec documentation. No unrelated modifications detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rook-589-gateway-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added the size/xl Denotes an extra large change size label Apr 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

✅ Contributor Report

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

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

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
clients/rook/src/main.rs (1)

61-67: ⚠️ Potential issue | 🟡 Minor

db_path is unreachable from the CLI.

ServerConfig.db_path exists and branches in-memory vs on-disk in build_app, but Serve hard-codes None, so operators cannot override ./rook.db or select :memory: without code changes. Consider threading a --db-path arg through, or removing the field until it's exposed.

Proposed CLI wiring
     Serve {
         /// Host address to bind to
         #[arg(long, default_value = "127.0.0.1")]
         host: String,

         /// TCP port to listen on
         #[arg(long, default_value_t = 4141)]
         port: u16,

         /// Enable the operator TUI alongside the HTTP server
         #[arg(long, default_value_t = false)]
         tui: bool,
+
+        /// Path to the SQLite database file (use ":memory:" for ephemeral)
+        #[arg(long)]
+        db_path: Option<String>,
     },
@@
-        Commands::Serve { host, port, tui } => {
+        Commands::Serve { host, port, tui, db_path } => {
             let config = ServerConfig {
                 host,
                 port,
                 enable_tui: tui,
-                db_path: None,
+                db_path,
             };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/rook/src/main.rs` around lines 61 - 67, ServerConfig.db_path is
hard-coded to None in the Commands::Serve arm so the CLI cannot choose an
on-disk or :memory: DB; update the CLI wiring to surface a --db-path option on
the Serve command and thread that value into ServerConfig (i.e., add a db_path
field to the Serve variant and populate ServerConfig.db_path from it in the
Serve match arm), or if you prefer to defer DB selection remove the
ServerConfig.db_path field and its branches in build_app to avoid dead config.
clients/rook/src/domain/mod.rs (1)

236-259: ⚠️ Potential issue | 🟠 Major

Secret leak via Debug: api_key will be printed by any {:?} of ProviderAccount.

ProviderAccount derives Debug and now contains api_key: Option<String>. Anywhere this struct (or anything wrapping it — pools, routing decisions, error contexts, tracing spans/fields) is formatted with {:?}, the raw key lands in logs. Given the PR explicitly adds tracing/structured logging as a follow-up NFR, this will almost certainly end up in log aggregation. "Plaintext at rest until #591" is fine; "plaintext in stdout" is not.

As per coding guidelines: "Security first... secret management" and "Prioritize... secret handling."

🛡️ Suggested fix — redact in Debug

Either drop the auto-derive and implement Debug manually, or wrap the secret:

-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
 pub struct ProviderAccount {
     ...
     pub api_key: Option<String>,
     ...
 }
+
+impl fmt::Debug for ProviderAccount {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ProviderAccount")
+            .field("id", &self.id)
+            .field("vendor", &self.vendor)
+            .field("display_name", &self.display_name)
+            .field("api_base_override", &self.api_base_override)
+            .field("api_key", &self.api_key.as_ref().map(|_| "***redacted***"))
+            .field("enabled", &self.enabled)
+            .field("weight", &self.weight)
+            .field("priority", &self.priority)
+            .field("tags", &self.tags)
+            .field("capabilities", &self.capabilities)
+            .finish()
+    }
+}

Also worth auditing Serialize usage — if ProviderAccount is ever returned over an admin API, you'll want a separate DTO without api_key (or with it write-only).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/rook/src/domain/mod.rs` around lines 236 - 259, ProviderAccount
currently derives Debug and contains api_key, which causes secrets to appear in
logs; replace the auto-derived Debug for ProviderAccount with a manual impl that
redacts api_key (e.g., print "<redacted>" or omit the field) or wrap api_key in
a secret type that implements Debug safely, and likewise ensure Serialize does
not expose the secret by either removing api_key from the public DTO/impl or
implementing custom Serialize/Deserialize to prevent dumping the key; update
references to ProviderAccount (pools, routing, error contexts, tracing spans) to
use the redacted/debug-safe representation.
clients/rook/src/server/mod.rs (1)

137-161: 🧹 Nitpick | 🔵 Trivial

Add a test asserting db_path default resolves to ./rook.db.

server_config_default_values doesn't assert db_path is None, and no test covers the unwrap_or("./rook.db") fallback path in build_app. A regression that flips the default would slip through.

     fn server_config_default_values() {
         let cfg = ServerConfig::default();
         assert_eq!(cfg.host, "127.0.0.1");
         assert_eq!(cfg.port, 4141);
         assert!(!cfg.enable_tui);
+        assert!(cfg.db_path.is_none());
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/rook/src/server/mod.rs` around lines 137 - 161, Add an assertion in
the server_config_default_values test to verify ServerConfig::default() sets
db_path to None and add a new test (or extend server_config_default_values) that
simulates build_app's fallback behavior by asserting that when db_path is None
the effective DB path used by build_app (or the unwrap_or("./rook.db") logic)
resolves to "./rook.db"; reference the ServerConfig struct, the
server_config_default_values test, the db_path field, and the build_app
unwrap_or("./rook.db") fallback so CI will catch regressions flipping the
default db path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@clients/rook/migrations/0003_account_api_key.sql`:
- Around line 1-3: The ProviderAccount struct currently derives Debug and will
leak api_key; replace the derived Debug on ProviderAccount with a custom impl
that redacts the api_key field (e.g., print "<redacted>" for api_key) similar to
the ProviderAccountConfig example in clients/agent-runtime/src/config/schema.rs;
ensure you keep Clone/Serialize/Deserialize intact. Also, when creating the
rook.db file, ensure its permissions are set to 0o600 on creation and add a
comment on the ProviderAccount struct and the migration noting that api_key is
stored plaintext for M1 with a link to issue `#591`. Finally, audit logging sites
to never pass the full ProviderAccount to logging macros—log only safe fields
(e.g., account_id and vendor) or formatted summaries that omit api_key.

In `@clients/rook/src/db/mod.rs`:
- Around line 167-196: The migration logic for version_0003 (and analogous
0001/0002 blocks) performs DDL (MIGRATION_SQL_0003 via sqlx::raw_sql) and then
separately inserts into schema_migrations
(sqlx::query(...).bind(version_0003).bind(&now).execute(pool)), which can desync
if the process crashes between statements; wrap the DDL and the bookkeeping
INSERT in a single database transaction so they commit or roll back together:
begin a transaction from the same pool, execute MIGRATION_SQL_0003 and then the
INSERT into schema_migrations using that transaction handle instead of pool, and
finally commit the transaction (or rollback on error); consider extracting this
pattern into a helper function used by version_0001/version_0002/version_0003 to
avoid duplication.

In `@clients/rook/src/gateway/handlers.rs`:
- Around line 56-80: The health updates are being awaited before returning the
upstream response; instead, spawn them to run concurrently so the gateway
returns immediately. In both branches (success path using
state.registry.health().mark_success and error path using
state.registry.health().mark_failure), wrap the async health call in a
background task (e.g., tokio::spawn) and move/clone any needed handles
(state.registry.clone() or health handle, and decision.account.id plus
FAILURE_COOLDOWN_SECS) into that task, then return the Response or
map_upstream_error result without awaiting the spawned task.
- Around line 255-283: The test helper mock_upstream currently sets the
process-wide ROOK_TEST_UPSTREAM_URL which causes races; modify mock_upstream to
stop calling std::env::set_var and instead return the server URL (e.g., change
its return from tokio::task::JoinHandle<()> to something like (JoinHandle<()>,
String) or a struct containing the handle and url), and update callers such as
chat_completions_happy_path_returns_upstream_body to capture that returned URL
and pass it into test_app or whatever configuration expects the upstream instead
of reading ROOK_TEST_UPSTREAM_URL from the environment; ensure the
TcpListener::local_addr-derived url is the returned value and that no global env
var writes remain in mock_upstream.

In `@clients/rook/src/gateway/mod.rs`:
- Around line 12-37: The router lacks auth and a request-body size limit: update
build_router to include authentication middleware for /v1/* (or document that
binding to loopback in ServerConfig::default is required before exposing the
port) and add a request-size limiting layer for POST /chat/completions
(affecting handlers::handle_chat_completions) such as axum's DefaultBodyLimit or
a RequestBodyLimitLayer to guard against raw-body proxy memory exhaustion;
reference GatewayState when wiring middleware so the auth layer can access
registry/engine/client as needed.

In `@clients/rook/src/gateway/upstream.rs`:
- Around line 44-50: Add a structured warning when an account lacks API
credentials instead of silently sending unauthenticated requests: in
upstream.rs, inside the block handling account.api_key (the if let Some(api_key)
= account.api_key.as_deref() { ... } construct), add an else branch that emits a
warning (e.g., tracing::warn! or process_logger.warn) including only non-secret
metadata such as account identifier and vendor (reference account.vendor and
account.id or equivalent), ensuring you do NOT log api_key or any secret value;
keep the existing vendor::auth_header(...) and request.header(...) logic
unchanged.

In `@clients/rook/src/gateway/vendor.rs`:
- Around line 5-8: The current mapping in vendor.rs returns native base URLs
(ProviderVendor::OpenAi, ::Anthropic, ::Google, ::OpenRouter) but upstream.rs
always appends "/v1/chat/completions", so incompatible vendors will fail; update
the function that returns base URLs to either return None for vendors that are
not OpenAI-compatible by default (e.g., ProviderVendor::Anthropic,
ProviderVendor::Google) or implement vendor-specific path handling by returning
fully compatible base+path strings (or a tuple of base and path) for each
ProviderVendor, and ensure upstream.rs uses those vendor-specific values instead
of always appending "/v1/chat/completions".

In `@clients/rook/src/server/mod.rs`:
- Around line 59-82: The startup code in build_app currently treats the literal
db_path value ":memory:" as a sentinel to open an in-memory DB
(RookRegistry::open_in_memory), which leaks a test-only concern into production
and risks accidental volatile DBs; change the design so ServerConfig does not
use a string sentinel: either introduce an explicit enum (e.g.,
DatabaseSource::OnDisk(String) | DatabaseSource::InMemory) on ServerConfig and
switch on that to call RookRegistry::open or RookRegistry::open_in_memory, or
keep ServerConfig.db_path as Option<String> for CLI parsing but add a test-only
constructor like build_app_with_registry(registry, config) (or a dedicated
RookRegistry::from_test helper) and have build_app always call
RookRegistry::open(db_path) for production paths; update build_app to remove the
db_path == ":memory:" comparison and ensure tests use the new constructor to
avoid repeated migrations and accidental production usage.

In `@openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md`:
- Around line 539-553: Update the design doc to match the implemented behavior:
when decision.account.api_key (variable api_key in the flow) is missing or
empty, the gateway should proceed by omitting auth and proxying the request
rather than returning a 502 via error_response with "missing_api_key"; change
the described flow and the test matrix entries that assert 502/missing_api_key
to instead expect the no-auth/proxy behavior, and scan all markdown docs (glob
**/*.{md,mdx}) to ensure the wording and examples reference the updated behavior
and not the old 502 response.
- Around line 332-386: default_base_url currently returns an OpenAI URL for
ProviderVendor::Other but the shipped contract requires unknown vendors to yield
no default; change default_base_url to return Option<&'static str> and make
ProviderVendor::Other return None, then update effective_base_url(account:
&ProviderAccount) to first check account.api_base_override (as_deref), trim
trailing slashes and return that if present, otherwise call
default_base_url(&account.vendor).map(|s| s.trim_end_matches('/').to_string())
and handle the None case (decide and document whether to return an empty string
or propagate an error) so behavior matches the spec that Other has no implicit
OpenAI endpoint unless api_base_override is set.

In `@openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md`:
- Around line 24-26: The proposal incorrectly claims the new
ProviderAccount.api_key column is "encrypted at rest" while the risk table and
implementation indicate M1 stores keys in plaintext; update the text so the
"api_key" field explicitly states that M1 stores keys in plaintext (encryption
deferred to later migrations), and make the risk table entry for M1 and the
summary paragraph for "api_key on ProviderAccount" consistent; search for
"ProviderAccount.api_key", "M1", and the risk table section (also referenced
around the existing 169-176 notes) and revise all occurrences in the .md/.mdx
docs to state plaintext storage for M1 and clearly note that encryption-at-rest
will be introduced in a future migration.

In `@openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md`:
- Around line 579-624: The spec currently implies build_router(state) mounts
absolute /v1/... routes; change R12 to state that gateway::build_router(state)
MUST expose only relative routes (e.g., POST /chat/completions and GET /models)
and accept GatewayState (Clone) as before, and change R13 to require server::run
to own the /v1 prefix: create RookRegistry, RoutingEngine, reqwest::Client (30s
timeout), construct GatewayState, call gateway::build_router(state) and then
mount it under Router::nest("/v1", ...) or Router::route_layer to ensure the
server owns the /v1 path segment so there is no ambiguity between router and
server routing.

In `@openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md`:
- Around line 122-133: The health feedback currently awaits
mark_success(account_id) / mark_failure(account_id, 60) inline which can add
latency; change the implementation in the gateway handler that calls
mark_success and mark_failure to offload the write into a background task (e.g.
use tokio::spawn) capturing account_id so the HTTP response is returned without
awaiting the health-write; ensure errors from the spawned task are logged but do
not affect the client response and keep the existing happy-path test semantics
by adjusting tests to allow eventual consistency if needed.

In `@openspec/specs/gateway/spec.md`:
- Around line 579-624: Update the spec to match the implemented router contract:
change R12 so gateway::build_router(state) returns a Router that serves POST
/chat/completions and GET /models (i.e., routes are relative, without the /v1
prefix) and keep GatewayState requirements (registry: RookRegistry, engine:
RoutingEngine, client: reqwest::Client, Clone); then amend R13 to state that
server::run MUST call gateway::build_router(state) and mount it via
Router::nest("/v1", gateway::build_router(state)) (creating RookRegistry,
RoutingEngine, and a reqwest::Client with 30s timeout beforehand) so the
top-level server retains /v1 as the namespace.

---

Outside diff comments:
In `@clients/rook/src/domain/mod.rs`:
- Around line 236-259: ProviderAccount currently derives Debug and contains
api_key, which causes secrets to appear in logs; replace the auto-derived Debug
for ProviderAccount with a manual impl that redacts api_key (e.g., print
"<redacted>" or omit the field) or wrap api_key in a secret type that implements
Debug safely, and likewise ensure Serialize does not expose the secret by either
removing api_key from the public DTO/impl or implementing custom
Serialize/Deserialize to prevent dumping the key; update references to
ProviderAccount (pools, routing, error contexts, tracing spans) to use the
redacted/debug-safe representation.

In `@clients/rook/src/main.rs`:
- Around line 61-67: ServerConfig.db_path is hard-coded to None in the
Commands::Serve arm so the CLI cannot choose an on-disk or :memory: DB; update
the CLI wiring to surface a --db-path option on the Serve command and thread
that value into ServerConfig (i.e., add a db_path field to the Serve variant and
populate ServerConfig.db_path from it in the Serve match arm), or if you prefer
to defer DB selection remove the ServerConfig.db_path field and its branches in
build_app to avoid dead config.

In `@clients/rook/src/server/mod.rs`:
- Around line 137-161: Add an assertion in the server_config_default_values test
to verify ServerConfig::default() sets db_path to None and add a new test (or
extend server_config_default_values) that simulates build_app's fallback
behavior by asserting that when db_path is None the effective DB path used by
build_app (or the unwrap_or("./rook.db") logic) resolves to "./rook.db";
reference the ServerConfig struct, the server_config_default_values test, the
db_path field, and the build_app unwrap_or("./rook.db") fallback so CI will
catch regressions flipping the default db path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 35f0fd45-8204-4baf-8615-4ba6da817d01

📥 Commits

Reviewing files that changed from the base of the PR and between b2bb089 and 41d7539.

⛔ Files ignored due to path filters (1)
  • clients/rook/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (23)
  • clients/rook/Cargo.toml
  • clients/rook/migrations/0003_account_api_key.sql
  • clients/rook/src/db/account.rs
  • clients/rook/src/db/mod.rs
  • clients/rook/src/db/pool.rs
  • clients/rook/src/db/route.rs
  • clients/rook/src/domain/mod.rs
  • clients/rook/src/gateway/handlers.rs
  • clients/rook/src/gateway/mod.rs
  • clients/rook/src/gateway/types.rs
  • clients/rook/src/gateway/upstream.rs
  • clients/rook/src/gateway/vendor.rs
  • clients/rook/src/main.rs
  • clients/rook/src/routing/mod.rs
  • clients/rook/src/server/mod.rs
  • clients/rook/src/services/account.rs
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/state.yaml
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md
  • openspec/specs/gateway/spec.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: report / Contributor Quality Report
  • GitHub Check: pr-checks
  • GitHub Check: sonar
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

⚙️ CodeRabbit configuration file

**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.

Files:

  • clients/rook/src/routing/mod.rs
  • clients/rook/src/db/route.rs
  • clients/rook/src/services/account.rs
  • clients/rook/src/db/pool.rs
  • clients/rook/src/main.rs
  • clients/rook/src/domain/mod.rs
  • clients/rook/src/db/account.rs
  • clients/rook/src/gateway/mod.rs
  • clients/rook/src/server/mod.rs
  • clients/rook/src/gateway/vendor.rs
  • clients/rook/src/gateway/handlers.rs
  • clients/rook/src/db/mod.rs
  • clients/rook/src/gateway/upstream.rs
  • clients/rook/src/gateway/types.rs
**/*

⚙️ CodeRabbit configuration file

**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.

Files:

  • clients/rook/src/routing/mod.rs
  • clients/rook/src/db/route.rs
  • clients/rook/src/services/account.rs
  • clients/rook/src/db/pool.rs
  • clients/rook/src/main.rs
  • clients/rook/migrations/0003_account_api_key.sql
  • clients/rook/src/domain/mod.rs
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/state.yaml
  • clients/rook/src/db/account.rs
  • clients/rook/src/gateway/mod.rs
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md
  • clients/rook/src/server/mod.rs
  • clients/rook/Cargo.toml
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md
  • clients/rook/src/gateway/vendor.rs
  • openspec/specs/gateway/spec.md
  • clients/rook/src/gateway/handlers.rs
  • clients/rook/src/db/mod.rs
  • clients/rook/src/gateway/upstream.rs
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md
  • clients/rook/src/gateway/types.rs
**/*.{md,mdx}

⚙️ CodeRabbit configuration file

**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.

Files:

  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md
  • openspec/specs/gateway/spec.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md
🧠 Learnings (11)
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/providers/**/*.rs : Implement `Provider` trait in `src/providers/` and register in `src/providers/mod.rs` factory when adding a new provider

Applied to files:

  • clients/rook/src/routing/mod.rs
  • clients/rook/src/db/route.rs
  • clients/rook/src/db/pool.rs
  • clients/rook/src/domain/mod.rs
  • clients/rook/src/db/account.rs
  • clients/rook/src/gateway/vendor.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Keep startup path lean and avoid heavy initialization in command parsing flow

Applied to files:

  • clients/rook/src/main.rs
  • clients/rook/Cargo.toml
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Include threat/risk notes and rollback strategy for security, runtime, and gateway changes; add or update tests for boundary checks and failure modes

Applied to files:

  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/Cargo.toml : Do not add heavy dependencies for minor convenience; justify new crate additions

Applied to files:

  • clients/rook/Cargo.toml
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/Cargo.toml : Preserve release-size profile assumptions in `Cargo.toml` and avoid adding heavy dependencies unless clearly justified

Applied to files:

  • clients/rook/Cargo.toml
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why

Applied to files:

  • clients/rook/Cargo.toml
  • clients/rook/src/gateway/types.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/main.rs : Preserve CLI contract unless change is intentional and documented; prefer explicit errors over silent fallback for unsupported critical paths

Applied to files:

  • clients/rook/Cargo.toml
  • clients/rook/src/gateway/types.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/channels/**/*.rs : Implement `Channel` trait in `src/channels/` with consistent `send`, `listen`, and `health_check` semantics and cover auth/allowlist/health behavior with tests

Applied to files:

  • clients/rook/Cargo.toml
  • openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md
  • openspec/specs/gateway/spec.md
  • clients/rook/src/gateway/handlers.rs
  • clients/rook/src/gateway/upstream.rs
  • clients/rook/src/gateway/types.rs
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/tools/**/*.rs : Implement `Tool` trait in `src/tools/` with strict parameter schema, validate and sanitize all inputs, and return structured `ToolResult` without panics in runtime path

Applied to files:

  • clients/rook/Cargo.toml
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/**/*.rs : Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency

Applied to files:

  • clients/rook/Cargo.toml
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/src/{security,gateway,tools}/**/*.rs : Treat `src/security/`, `src/gateway/`, `src/tools/` as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks

Applied to files:

  • clients/rook/src/gateway/types.rs
🪛 LanguageTool
openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md

[grammar] ~175-~175: Ensure spelling is correct
Context: ...reasonable default timeout (30s) on the reqwest client. Gateway returns 504 on timeout....

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~214-~214: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...returns 503. - /v1/chat/completions handler (upstream error): mock returns 500, v...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md

[style] ~514-~514: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..._failure(account_id, cooldown_secs). - On upstream HTTP 5xx response: call healt...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~515-~515: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..._failure(account_id, cooldown_secs). - On connection error: call health.mark_fai...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~622-~622: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...utingEnginebacked by the registry. 3. Create areqwest::Client` with a default time...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

openspec/specs/gateway/spec.md

[style] ~514-~514: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..._failure(account_id, cooldown_secs). - On upstream HTTP 5xx response: call healt...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~515-~515: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ..._failure(account_id, cooldown_secs). - On connection error: call health.mark_fai...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~622-~622: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...utingEnginebacked by the registry. 3. Create areqwest::Client` with a default time...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md

[style] ~1077-~1077: To form a complete sentence, be sure to include a subject.
Context: ... for M1 — hardcoded 30s is reasonable. Can be made configurable as a fast follow-u...

(MISSING_IT_THERE)

🪛 markdownlint-cli2 (0.22.0)
openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md

[warning] 113-113: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 113-113: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md

[warning] 33-33: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 56-56: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 82-82: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 108-108: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 115-115: Ordered list item prefix
Expected: 1; Actual: 2; Style: 1/1/1

(MD029, ol-prefix)


[warning] 186-186: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 227-227: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 276-276: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 314-314: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 351-351: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 387-387: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 421-421: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 454-454: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 483-483: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 552-552: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 595-595: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 629-629: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 698-698: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 744-744: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 775-775: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 869-869: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 898-898: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 954-954: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 995-995: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md

[warning] 68-68: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 120-120: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 143-143: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 689-689: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 930-930: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (8)
clients/rook/src/gateway/types.rs (1)

12-28: LGTM — flatten + raw-body pass-through is consistent.

Since handle_chat_completions forwards body: Bytes upstream verbatim, the #[serde(flatten)] extra map is effectively only used for deserialization tolerance and optional inspection. No data is lost on the wire. Tests cover the shape well.

clients/rook/src/routing/mod.rs (1)

416-431: LGTM.

Test fixtures correctly track the new api_key: Option<String> field.

clients/rook/src/services/account.rs (1)

163-163: LGTM.

Fixture aligned with new domain shape.

clients/rook/src/db/route.rs (1)

223-223: LGTM.

clients/rook/src/db/pool.rs (1)

312-324: LGTM.

clients/rook/Cargo.toml (1)

27-28: Dependencies justified for the upstream proxy.

reqwest with rustls-tls + json and bytes are consistent with gateway/upstream.rs usage. default-features = false keeps the surface lean.

clients/rook/src/db/account.rs (1)

53-95: LGTM. api_key column plumbed correctly through row_to_account, insert_account, get_account, and list_accounts; round-trip tests cover both Some and None. Just note the Debug leak raised on domain/mod.rs affects any {:?} formatting of rows fetched here.

openspec/changes/archive/2026-04-21-rook-589-gateway-api/tasks.md (1)

1-1082: Docs LGTM. Task breakdown matches the implemented code; markdownlint warnings (MD031/MD029/MD040) are cosmetic in an archived artifact and can be ignored.

Comment thread clients/rook/migrations/0003_account_api_key.sql
Comment thread clients/rook/src/db/mod.rs
Comment thread clients/rook/src/gateway/handlers.rs
Comment thread clients/rook/src/gateway/handlers.rs Outdated
Comment thread clients/rook/src/gateway/mod.rs
Comment thread openspec/changes/archive/2026-04-21-rook-589-gateway-api/design.md Outdated
Comment thread openspec/changes/archive/2026-04-21-rook-589-gateway-api/proposal.md Outdated
Comment thread openspec/changes/archive/2026-04-21-rook-589-gateway-api/spec.md Outdated
Comment thread openspec/changes/archive/2026-04-21-rook-589-gateway-api/verify-report.md Outdated
Comment thread openspec/specs/gateway/spec.md Outdated
Redact ProviderAccount secrets, make migrations transactional, remove test-only DB sentinel behavior, limit gateway request bodies, and align tests/docs with the current gateway contract and review findings.
@yacosta738 yacosta738 merged commit 81aec86 into main Apr 21, 2026
13 checks passed
@yacosta738 yacosta738 deleted the feat/rook-589-gateway-api branch April 21, 2026 18:34
@sonarqubecloud
Copy link
Copy Markdown

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.

Implement /v1/chat/completions and /v1/models for OpenAI-style compatibility

1 participant