Skip to content

feat: LUNAROUTE marker-based provider routing#34

Merged
erans merged 12 commits intomainfrom
feature/lunaroute-marker-routing
Apr 3, 2026
Merged

feat: LUNAROUTE marker-based provider routing#34
erans merged 12 commits intomainfrom
feature/lunaroute-marker-routing

Conversation

@erans
Copy link
Copy Markdown
Owner

@erans erans commented Apr 3, 2026

Summary

  • Add [LUNAROUTE:provider_name] marker detection in passthrough request bodies to dynamically route requests to named providers
  • Support arbitrary named providers in config via serde(flatten) with optional model override
  • Integrate marker detection + connector swap into both Anthropic and OpenAI passthrough handlers
  • Strip markers before forwarding to upstream providers
  • Add session tags for observability (lunaroute:<provider>, model_override:<model>)

This enables Claude Code users to switch providers on-the-fly via a #!provider command (e.g., #!sonnet) without restarting sessions or changing configuration. The client-side plugin injects the marker; the proxy handles routing.

Changes

Area Files Description
Marker parsing marker.rs (new, 433 lines) extract_marker(), strip_marker(), 19 unit tests
Provider registry provider_registry.rs (new) ProviderType, ProviderEntry, ProviderRegistry types
Config config.rs provider_type, model fields + extra providers via serde flatten
Startup main.rs Build ProviderRegistry from config at startup
Anthropic handler anthropic.rs Marker detection + connector swap in messages_passthrough
OpenAI handler openai.rs Marker detection + connector swap in chat_completions_passthrough
Multi-dialect multi_dialect.rs Thread registry parameter
Config example config.example.yaml Documented marker routing example
Version Cargo.toml Bump to 0.1.10

Error handling

  • Unknown provider name: log warning, use default connector
  • Cross-dialect mismatch (e.g., Anthropic endpoint + OpenAI provider): HTTP 400
  • Disabled provider: treated as unknown
  • Malformed marker: no detection, request proceeds normally

Test plan

  • 19 unit tests for marker extraction and stripping (all paths)
  • 3 integration-style tests for full extract→strip→override flow
  • 4 config validation tests (valid, missing type, builtin conflict, YAML deser)
  • Full workspace cargo test passes (0 failures)
  • Manual test with Claude Code + lunaroute-cc-plugin

🤖 Generated with Claude Code

erans and others added 12 commits April 3, 2026 13:53
Describes the feature for dynamically overriding which provider
handles a request via [LUNAROUTE:provider] markers in request bodies,
enabling Claude Code users to switch providers on-the-fly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix critical and major issues from spec review:
- Add provider_type field for extra providers (connector type inference)
- Document serde flatten caveats and validation requirements
- Add extra providers connector construction note
- Clarify streaming + non-streaming connector swap paths
- Use MarkerResult enum instead of Option for clear/provider/none
- Add stripping regexes for system-reminder blocks
- Document req mutability requirement
- Add /v1/responses and /v1/models to Out of Scope

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10 tasks covering: marker extraction/stripping module, config changes,
provider registry type, startup construction, handler integration
(both Anthropic and OpenAI), config example, and integration tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After reviewing the client-side Claude Code plugin, updated both
spec and plan to match actual plugin behavior:
- extract_marker scans only the last user message (not all messages),
  since old markers persist in conversation history
- strip_marker operates on last user message only
- Added tests for old-marker-ignored and last-message-wins scenarios
- Documented subagent routing (plain text marker, no system-reminder)
- Noted that [LUNAROUTE:clear] is handled client-side only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `provider_type` and `model` fields to `ProviderSettings`, an `extra`
HashMap to `ProvidersConfig` for marker-based routing of named providers,
and a `validate_extra_providers()` method with full test coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix pre-existing build failures: add missing provider_registry argument to
passthrough_router calls in integration test files, and suppress
clippy::too_many_arguments on multi_dialect::passthrough_router.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…andler

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove stale #[allow(dead_code)] from validate_extra_providers (it IS called)
- Add debug log when marker found but no provider registry available

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@erans erans merged commit 36d803e into main Apr 3, 2026
8 checks passed
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