Releases: erans/lunaroute
v0.2.0
Codex CLI WebSocket Support for /responses (#37)
Codex CLI can now talk to LunaRoute over WebSockets. When Codex is configured with supports_websockets = true, it opens a WS upgrade on GET /v1/responses (or GET /responses for base URLs without /v1), and LunaRoute terminates the WS, drives the existing HTTP Responses pipeline upstream (stream=true always), and translates SSE events back as WS text frames.
What's included
GEThandlers on/v1/responsesand/responsesthat accept WS upgrades- Full feature parity with the HTTP path: session recording, LUNAROUTE markers (same-dialect), metrics, provider registry,
codex_auth, header filtering - Sequential in-flight per connection; terminal-event detection; structured error frames for malformed/unsupported client frames
- New Prometheus metrics:
lunaroute_ws_connections_opened_total,lunaroute_ws_connections_closed_totallunaroute_ws_connection_duration_secondslunaroute_ws_frames_total{endpoint,direction,type}— labels use parsed Responses event types (response.create,response.completed, …) plusmalformed_json,unsupported_event_type,invalid_request,binary,error,message
Codex configuration
openai_base_url = "http://localhost:8081/v1"
[model_providers.openai]
name = "OpenAI"
base_url = "http://localhost:8081/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"
supports_websockets = trueSetting supports_websockets = false (or omitting it on older Codex versions) continues to use HTTP POST /v1/responses with SSE — fully supported.
Tests
- Integration tests covering: WS event streaming with session recording, sequential in-flight, error frames for unsupported event types,
/responsescompat path - Unit tests for the frame parser and metric-label precedence
- Full test suite: 937 pass, 0 fail, 43 ignored
Also in this release
fix: stabilize tool_mapper cleanup test under tarpaulin— a timing-sensitive test that flaked under tarpaulin's instrumentation now uses a 1s TTL margin.chore: ignore .worktrees directory— Git worktrees created under.worktrees/no longer show up in status.
Full Changelog: v0.1.12...v0.2.0
v0.1.12
Cross-Dialect Marker Routing: Anthropic → OpenAI Translation (#35)
Adds cross-dialect routing: Anthropic-format requests can now be routed to OpenAI-type providers via LUNAROUTE markers (e.g., Claude Code → Kimi K2.5 on Cloudflare). Supports both streaming (SSE with synthetic message_start) and non-streaming paths. Normal same-dialect passthrough is unchanged — zero additional cost.
How it works
When messages_passthrough() detects a marker targeting an OpenAI-type provider:
- Parse raw Anthropic JSON →
AnthropicMessagesRequest - Normalize via
to_normalized()→NormalizedRequest - Send through
OpenAIConnector.send()/.stream()via theProvidertrait - Convert response back via
from_normalized()/stream_event_to_anthropic_events()
Tests
- Round-trip test: Anthropic JSON → normalize → Anthropic JSON preserves content
- Tool use round-trip: tool_use/tool_result survives normalization
- Stream event conversion: NormalizedStreamEvent → Anthropic SSE events
- Error SSE event serialization
- Model override ordering verification
- Full test suite passes (132 unit + 19 integration)
Full Changelog: v0.1.11...v0.1.12
v0.1.11
LUNAROUTE Marker-Based Provider Routing (#34)
Add [LUNAROUTE:provider_name] marker detection in passthrough request bodies to dynamically route requests to named providers. This enables Claude Code users to switch providers on-the-fly via a #!provider command (e.g., #!sonnet) without restarting sessions or changing configuration.
- Marker-based routing:
[LUNAROUTE:provider_name]markers in request bodies trigger dynamic provider switching - Arbitrary named providers: Config supports extra providers via
serde(flatten)with optional model override - Both dialects: Marker detection integrated into both Anthropic and OpenAI passthrough handlers
- Clean forwarding: Markers are stripped before forwarding to upstream providers
- Session observability: Tags added for tracking (
lunaroute:<provider>,model_override:<model>) - Error handling: Unknown providers fall back to default; cross-dialect mismatch returns HTTP 400
Tests
- 19 unit tests for marker extraction and stripping
- 3 integration tests for full extract→strip→override flow
- 4 config validation tests
Update Minimum Rust Version to 1.94.0 (#33)
- Bump
rust-versionin workspaceCargo.tomlfrom 1.90 to 1.94 - Update CI check job toolchain pin from 1.90 to 1.94
Full Changelog: v0.1.10...v0.1.11
v0.1.10
🌕 LunaRoute v0.1.10 - Provider Switch Notifications & Stability
Release Date: March 11, 2026
🎉 What's New
🔔 Provider Switch Notifications (#23)
LunaRoute can now automatically notify users when their request is routed to a different provider due to rate limits, errors, or circuit breaker events.
- Automatic user notifications via injected LLM message
- Global on/off with per-provider customization
- Template variable substitution:
${original_provider},${new_provider},${reason},${model} - Cross-dialect failover (OpenAI ↔ Anthropic)
- Idempotent - prevents duplicate notifications in cascading fallbacks
- Zero overhead when disabled
Configuration Example:
routing:
provider_switch_notification:
enabled: true
default_message: |
IMPORTANT: Please inform the user that due to temporary service constraints,
their request is being handled by an alternative AI service provider.
Continue with their original request.
providers:
anthropic-backup:
type: "anthropic"
switch_notification_message: |
IMPORTANT: Using Claude (${model}) due to ${reason}.
Quality remains the same. Continue with their original request.⚡ Response-Side Gzip Compression for Passthrough Mode
Passthrough mode now supports response-side gzip compression, reducing bandwidth usage for proxied responses.
📊 Improved Analytics Chart Tooltips
Analytics charts now display detailed model statistics in tooltips for better visibility into usage patterns.
🐛 Bug Fixes
- Fix streaming passthrough hang caused by gzip-compressed SSE responses
- Fix transparent proxying for Claude Code passthrough mode
- Fix Windows SQLite path parsing in UI server and import (#25) — uses
SqliteConnectOptions::new().filename()instead of URL-based connection strings that fail with Windows backslash paths - Fix flaky test by flushing tokio file writes in session recorder
- Fix build for reqwest 0.13: rename
rustls-tlsfeature torustls
📦 Dependency Updates
📝 Changes
Pull Requests
- feat: Add provider switch notification feature (#23) by @erans
- Fix Windows SQLite path parsing in UI server and import (#25) by @njt
- Update reqwest requirement from 0.12 to 0.13 (#27) by @dependabot
- Update mockall requirement from 0.13 to 0.14 (#22) by @dependabot
Commits
d1ab5b0Fix build: rename rustls-tls feature to rustls for reqwest 0.135aae1a5Add response-side gzip compression to passthrough modefe82d41Fix flaky test by flushing tokio file writes in session recorder31b756dFix streaming passthrough hang caused by gzip-compressed SSEdeacd81Fix transparent proxying for Claude Code passthrough modefea0f97Fix Windows SQLite path parsing in UI server and importa6d1f38Improve analytics chart tooltips with detailed model statisticsd3dfb38Wire provider switch notification config to Router in serverb9f434fdocs: add provider switch notification section to README95c5b3fdocs: add example config for provider switch notifications7e8141dtest: add comprehensive provider switch notification integration testsf854f51feat: integrate notification injection into provider switching logic29e5bb6feat: implement Phase 4 router integration for provider switch notificationsfd6c1a0feat: implement idempotency guard for notifications924cfa9feat: implement notification message buildera47cda7feat: implement template variable substitution667193cfeat: add switch_notification_message to provider configsbe49c05feat: add provider_switch_notification to RoutingConfigfb5fe3cfeat: export notification modulef749eb3feat: add ProviderSwitchNotificationConfig structd1dfc38feat: add SwitchReason enum for provider switch notificationsa7246cdAdd design document for provider switch notification feature831a521Update reqwest requirement in the dependencies groupfcdd534Update mockall requirement from 0.13 to 0.14
📦 Installation
Download for your platform:
- Linux AMD64:
lunaroute-server-linux-amd64-0.1.10 - Linux ARM64:
lunaroute-server-linux-arm64-0.1.10 - macOS AMD64:
lunaroute-server-darwin-amd64-0.1.10 - macOS ARM64:
lunaroute-server-darwin-arm64-0.1.10 - Windows AMD64:
lunaroute-server-windows-amd64-0.1.10.exe - Windows ARM64:
lunaroute-server-windows-arm64-0.1.10.exe
Or build from source:
git clone https://github.com/erans/lunaroute.git
cd lunaroute
git checkout v0.1.10
cargo build --release --package lunaroute-server🐛 Bug Reports & Feedback
- Issues: https://github.com/erans/lunaroute/issues
- Discussions: https://github.com/erans/lunaroute/discussions
Full Changelog: v0.1.9...v0.1.10
🌕 Happy coding with full visibility!
LunaRoute - Your AI Coding Assistant's Best Friend
v0.1.9
Maintenance Release
Bug: Fix stats when session go over date lines.
v0.1.8
🌕 LunaRoute v0.1.8 - One-Command Setup
Release Date: October 31, 2025
🎉 What's New
⚡ One-Command Setup with env Command
Getting started with LunaRoute is now incredibly simple:
eval $(lunaroute-server env)That's it! This single command:
- ✅ Starts the server in the background (detached process)
- ✅ Configures Claude Code (
ANTHROPIC_BASE_URL) - ✅ Configures Codex CLI (
OPENAI_BASE_URL) - ✅ Enables both OpenAI and Anthropic APIs simultaneously
- ✅ Tracks every token, tool call, and conversation
Example Usage:
# Basic usage - starts on port 8081
eval $(lunaroute-server env)
# Custom port
eval $(lunaroute-server env --port 8090)
# Stop the server
pkill -f "lunaroute-server serve"🔄 Dual-Dialect Passthrough by Default
Zero configuration required! LunaRoute now defaults to both APIs:
- OpenAI format:
/v1/chat/completions - Anthropic format:
/v1/messages - Zero normalization: Direct passthrough (~0.1-0.2ms latency)
- 100% API fidelity: Preserves all response fields including extended thinking
- Intelligent routing:
gpt-*→ OpenAI,claude-*→ Anthropic
Before: Required explicit configuration or defaulted to Anthropic-only
Now: Both APIs enabled by default with intelligent routing
📊 Session Recording Enabled by Default
Full session tracking now works out of the box:
JSONL Writer (~/.lunaroute/sessions/)
- Human-readable newline-delimited JSON
- Complete request/response data per session
- Perfect for debugging and manual inspection
SQLite Writer (~/.lunaroute/sessions.db)
- Fast queries and analytics
- Session metadata, tokens, performance metrics
- Web UI integration at
http://localhost:8082
What you get automatically:
- 📊 Token tracking (input, output, thinking)
- 🔧 Tool call logging (which tools, when, how long)
- 💰 Cost estimation per session
- 📈 Performance metrics (latency, overhead)
- 🔍 Searchable conversation history
🚀 Quick Start
New Users
# Download and extract
tar -xzf lunaroute-server-*.tar.gz
chmod +x lunaroute-server
# One command to start everything
eval $(lunaroute-server env)
# Done! Both Claude Code and Codex CLI work immediately
# View sessions at http://localhost:8082Existing Users
No breaking changes! All configurations continue to work.
New defaults when running without config:
- ✅ Both API dialects enabled (was: Anthropic only)
- ✅ Session recording enabled (JSONL + SQLite)
- ✅ Access to new
envcommand
To opt out of session recording:
session_recording:
enabled: false📦 Installation
Download for your platform:
- Linux AMD64:
lunaroute-server-linux-amd64-0.1.8 - Linux ARM64:
lunaroute-server-linux-arm64-0.1.8 - macOS AMD64:
lunaroute-server-darwin-amd64-0.1.8 - macOS ARM64:
lunaroute-server-darwin-arm64-0.1.8 - Windows AMD64:
lunaroute-server-windows-amd64-0.1.8.exe - Windows ARM64:
lunaroute-server-windows-arm64-0.1.8.exe
Or build from source:
git clone https://github.com/erans/lunaroute.git
cd lunaroute
git checkout v0.1.8
cargo build --release --package lunaroute-server🔧 Technical Details
Performance
- Dual-dialect mode: 0.1-0.2ms latency (P95 < 0.5ms)
- Session recording: 0.5-1ms async (non-blocking)
- Memory: ~2MB baseline + ~1KB per request
Compatibility
- ✅ Claude Code - Full passthrough support
- ✅ OpenAI Codex CLI - Automatic auth integration
- ✅ OpenCode - Standard API compatibility
- ✅ Custom clients - Any OpenAI/Anthropic compatible tool
Testing
- 858+ tests passing (0 failures)
- 73.35% code coverage
- 0 clippy warnings
📝 Changes
Commits: f947b41, 255dd6b
New Features:
- Add
lunaroute-server envcommand for one-command setup - Dual-dialect passthrough now the default (
ApiDialect::Both) - Session recording (JSONL + SQLite) enabled by default
- Both OpenAI and Anthropic providers enabled by default in passthrough mode
Documentation:
- Complete README rewrite (44% reduction, better clarity)
- Prominent one-command setup sections
- Comprehensive
envcommand documentation
Technical:
- Server detaches from terminal on Unix systems
- Health check verification before returning
- Backward compatible with all existing configurations
🐛 Bug Reports & Feedback
- Issues: https://github.com/erans/lunaroute/issues
- Discussions: https://github.com/erans/lunaroute/discussions
🌕 Happy coding with full visibility!
LunaRoute - Your AI Coding Assistant's Best Friend
v0.1.7
What's Changed
Full Changelog: v0.1.6...v0.1.7
v0.1.6
What's Changed
Full Changelog: v0.1.5...v0.1.6
v0.1.5
What's Changed
Full Changelog: v0.1.4...v0.1.5
v0.1.4
What's Changed
- Fix #14: Filter Authorization header when using configured API key in Anthropic passthrough by @erans in #17
Full Changelog: v0.1.3...v0.1.4