Skip to content

Feat/openrouter#45

Merged
EggerMarc merged 5 commits into
mainfrom
feat/openrouter
Jun 2, 2026
Merged

Feat/openrouter#45
EggerMarc merged 5 commits into
mainfrom
feat/openrouter

Conversation

@EggerMarc

@EggerMarc EggerMarc commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added OpenRouter as a new provider for chat completions and streaming chat responses
    • Support for both standard completions and real-time SSE streaming
    • Configure using OPENROUTER_API_KEY environment variable
  • Documentation

    • Added OpenRouter provider documentation with configuration and usage examples
    • Updated provider feature-flag reference table with OpenRouter details

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@EggerMarc, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 48 minutes and 50 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 75e22660-d8f9-40dc-8bea-688e9f96743b

📥 Commits

Reviewing files that changed from the base of the PR and between 15d5027 and eced41e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • README.md
  • providers/openrouter/Cargo.toml
  • providers/openrouter/src/lib.rs
📝 Walkthrough

Walkthrough

This PR introduces OpenRouter provider support to chat-rs, a new crate wrapping the OpenAI-compatible OpenRouter API. The implementation includes a type-state builder, two usage examples, workspace integration via feature flags, and documentation updates describing the provider's dual-wire capability and stateless behavior.

Changes

OpenRouter Provider Integration

Layer / File(s) Summary
OpenRouter provider implementation
providers/openrouter/src/lib.rs, providers/openrouter/Cargo.toml, providers/openrouter/README.md
Type-state OpenRouterBuilder selects between Responses API (default) and Chat Completions (via .with_completions()), resolves API keys from environment or explicit config, disables previous_response_id reuse on Responses path, and supports custom transports and optional reasoning configuration.
Workspace integration and feature wiring
Cargo.toml, src/lib.rs
Registers providers/openrouter as a workspace member, adds optional chat-openrouter dependency, introduces openrouter feature flag, extends stream feature for streaming support, defines two examples with required-features, and re-exports provider in root module and prelude.
Completion and streaming examples
.env.example, examples/openrouter/completion.rs, examples/openrouter/stream.rs
Adds OPENROUTER_API_KEY to environment template; completion example sends a single prompt and prints response; streaming example implements an interactive REPL that reads user input, streams responses with reasoning chunks rendered in dim gray, and outputs usage metadata.
README and ROADMAP updates
README.md, ROADMAP.md
Adds OpenRouter to providers feature-flag table; documents Responses/Completions wire selection, stateless Responses handling, SSE-only streaming, and HTTP-only upstream in feature comparison.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A router for chats, shiny and new,
Built with states and features in queue,
Examples show how to stream and complete,
Responses or Completions, pick your feat!
hops away with OpenRouter in tow

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feat/openrouter' is vague and uses a generic pattern without clearly describing what the feature adds or changes. Use a more descriptive title like 'Add OpenRouter provider integration' or 'Implement OpenRouter chat provider with Responses and Chat Completions support' to clearly communicate the main change.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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/openrouter

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
ROADMAP.md (1)

46-48: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the stale chat-responses “planned” note.

This section now contradicts both the implemented table above and the Line 23 OpenRouter description. chat-responses is already shipped, so keeping it here as planned makes the roadmap internally inconsistent.

Suggested documentation fix
-**A planned `chat-responses` crate** will factor the OpenAI Responses API wire out of `chat-openai` the same way `chat-completions` factors Chat Completions. Providers that support both (Groq) will then be able to toggle between wire specs on the builder.
+**`chat-responses`** is the shared OpenAI Responses API wire crate, factored out of `chat-openai` the same way `chat-completions` factors Chat Completions. Providers that support both wires can build on it directly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ROADMAP.md` around lines 46 - 48, Remove the stale "planned `chat-responses`
crate" sentence and update the wording to reflect that `chat-responses` has
already shipped and was factored out of `chat-openai` (mirroring how
`chat-completions` works); ensure the paragraph mentions that providers can
toggle between wire specs (e.g., Groq) and matches the existing table and the
`OpenRouter` description so the roadmap is consistent with current
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/openrouter/stream.rs`:
- Around line 33-38: The REPL loop reads stdin into user_input with
std::io::stdin().read_line(&mut user_input) but doesn't check the returned byte
count, so EOF (0 bytes) still pushes an empty message and triggers chat.stream;
modify the loop around read_line to capture the Result<usize, _>, unwrap or ?
into a variable (e.g., bytes_read), break the loop when bytes_read == 0 (EOF),
and also skip pushing blank input by checking user_input.trim().is_empty()
before calling messages.push(content::from_user(...)); update the block
containing user_input, read_line, messages.push and chat.stream accordingly.

In `@providers/openrouter/Cargo.toml`:
- Around line 21-23: The provider crate's stream feature must wire through
chat-core and include optional dependencies; update the [features] section so
the stream feature also enables "chat-core/stream" and references the optional
deps "async-stream" and "futures" (e.g. stream =
["chat-responses/stream","chat-completions/stream","chat-core/stream","async-stream","futures"]),
and add optional dependency entries for async-stream and futures in the
dependencies table (mark them optional = true) so the provider-level stream
contract is satisfied.
- Around line 12-19: Add the standard provider dependency surface to this
crate's Cargo.toml: include dependencies on async-trait, serde (with features =
["derive"]), serde_json, tools-rs, schemars, and the transport-reqwest crate
(per provider contract); also add optional dependencies for streaming support:
futures and async-stream (marked optional with appropriate features if the crate
supports streaming). Ensure these entries are placed alongside the existing
chat-core / chat-completions / chat-responses deps so the provider
(chat-openrouter) matches the other providers' manifest contract and enable any
needed features (e.g., serde derive) consistent with the workspace convention.

In `@README.md`:
- Line 75: Add OpenRouter to the Examples section of the README by inserting
entries that reference the new example files examples/openrouter/completion.rs
and examples/openrouter/stream.rs and show the correct provider name/key/builder
(OpenRouter, `openrouter`, `OPENROUTER_API_KEY`, `OpenRouterBuilder`) — update
the examples table row (the line containing the providers like "OpenRouter |
`openrouter` | `OPENROUTER_API_KEY` | `OpenRouterBuilder`") and add short
example commands or notes pointing to the two example files so users can
discover and run examples for completion and streaming.

---

Outside diff comments:
In `@ROADMAP.md`:
- Around line 46-48: Remove the stale "planned `chat-responses` crate" sentence
and update the wording to reflect that `chat-responses` has already shipped and
was factored out of `chat-openai` (mirroring how `chat-completions` works);
ensure the paragraph mentions that providers can toggle between wire specs
(e.g., Groq) and matches the existing table and the `OpenRouter` description so
the roadmap is consistent with current implementation.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67014c37-43b6-4057-b511-3b167f53afe1

📥 Commits

Reviewing files that changed from the base of the PR and between 633b37a and 15d5027.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • .env.example
  • Cargo.toml
  • README.md
  • ROADMAP.md
  • examples/openrouter/completion.rs
  • examples/openrouter/stream.rs
  • providers/openrouter/Cargo.toml
  • providers/openrouter/README.md
  • providers/openrouter/src/lib.rs
  • src/lib.rs

Comment thread examples/openrouter/stream.rs
Comment thread providers/openrouter/Cargo.toml
Comment thread providers/openrouter/Cargo.toml Outdated
Comment thread README.md
EggerMarc and others added 2 commits June 2, 2026 16:16
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@EggerMarc EggerMarc merged commit 8c1dba6 into main Jun 2, 2026
4 checks passed
@EggerMarc EggerMarc deleted the feat/openrouter branch June 2, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant