diff --git a/docs/index.md b/docs/index.md index b477c1eeb..b8971e066 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,6 +8,7 @@ It supports OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages. | Goal | Path | Start here | |---|---|---| | Run Switchyard as a standalone proxy for API clients | Server Path | [Build and run the Rust server](getting_started.md#server-path) | +| Route Codex or Claude Code using your existing login | Server Path | [Single-provider coding agents](recipes/single_provider_coding_agents.md) | | Add Switchyard routing to a Rust application | Library Path | [`switchyard-libsy`](../crates/libsy/README.md) | | Add Switchyard routing to NeMo Relay | Native Plugin Path | [Use Switchyard with NeMo Relay](integrations/nemo_relay.md) | | Point the pi coding agent at the standalone proxy | Server Path | [Use Switchyard with pi](integrations/pi.md) | diff --git a/docs/recipes/single_provider_coding_agents.md b/docs/recipes/single_provider_coding_agents.md new file mode 100644 index 000000000..6ede23313 --- /dev/null +++ b/docs/recipes/single_provider_coding_agents.md @@ -0,0 +1,165 @@ +# Interactive coding agents with single-provider auth + +Route Codex or Claude Code between models from one provider using your saved CLI +login. Every target, including the classifier, must use that provider. + +These [composite routing](../routing_algorithms/composite_routing.md) recipes use a +classifier to choose the starting tier for each user turn. Stage adjusts routing +during tool calls. [`forward_auth`](../reference/toml_schema.md#llm_clientsname) +passes your login through to the models. + +Choose one recipe. Each uses local port `4123`. + +## Codex with OpenAI + +Sign in with `codex login`. Terra classifies, and Stage routes between Sol and Luna. + +This recipe needs Codex classifier support added after v0.3.0. Install from a +checkout of current `main`: + +```bash +cargo install --locked --path crates/switchyard-server +``` + +Save as `codex-routing.toml`: + +```toml +schema_version = 1 + +[llm_clients.chatgpt] +format = "openai_responses" +base_url = "https://chatgpt.com/backend-api/codex" +forward_auth = true + +[targets.capable] +id = "gpt-5.6-sol" +llm_client = "chatgpt" + +[targets.efficient] +id = "gpt-5.6-luna" +llm_client = "chatgpt" + +[targets.judge] +id = "gpt-5.6-terra" +llm_client = "chatgpt" +extra_body = { store = false, stream = true } +omit_body_fields = ["max_output_tokens"] + +[routes.switchyard] +id = "switchyard" +type = "composite" + +[routes.switchyard.classifier] +target = "judge" +base_threshold = 0.5 +classify_trigger = "user_turn" + +[routes.switchyard.stage] +capable_target = "capable" +efficient_target = "efficient" +confidence_threshold = 0.5 +``` + +Start the server: + +```bash +switchyard-server --config codex-routing.toml --dry-run +switchyard-server --config codex-routing.toml --host 127.0.0.1 --port 4123 +``` + +Create `~/.codex/switchyard.config.toml` (or place it beside your `config.toml` if +you use a custom Codex config directory): + +```toml +model = "switchyard" +model_provider = "switchyard" + +[model_providers.switchyard] +name = "Switchyard" +base_url = "http://127.0.0.1:4123/v1" +wire_api = "responses" +requires_openai_auth = true +``` + +In another terminal, launch Codex: + +```bash +codex --profile switchyard +``` + +## Claude Code with Anthropic + +Sign in to Claude Code with your Claude account. Haiku classifies, and Stage routes +between Opus and Sonnet. + +Install the latest release: + +```bash +cargo install --locked switchyard-server +``` + +Save as `claude-routing.toml`: + +```toml +schema_version = 1 + +[llm_clients.anthropic] +format = "anthropic_messages" +base_url = "https://api.anthropic.com" +forward_auth = true + +[targets.capable] +id = "claude-opus-5-5" +llm_client = "anthropic" + +[targets.efficient] +id = "claude-sonnet-5-5" +llm_client = "anthropic" + +[targets.judge] +id = "claude-haiku-4-5-20251001" +llm_client = "anthropic" + +[routes.switchyard] +id = "switchyard" +type = "composite" + +[routes.switchyard.classifier] +target = "judge" +base_threshold = 0.5 +classify_trigger = "user_turn" + +[routes.switchyard.stage] +capable_target = "capable" +efficient_target = "efficient" +confidence_threshold = 0.5 +``` + +Start the server: + +```bash +switchyard-server --config claude-routing.toml --dry-run +switchyard-server --config claude-routing.toml --host 127.0.0.1 --port 4123 +``` + +In another terminal, launch Claude Code: + +```bash +env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \ + ANTHROPIC_BASE_URL=http://127.0.0.1:4123 \ + ANTHROPIC_DEFAULT_OPUS_MODEL=switchyard \ + ANTHROPIC_DEFAULT_SONNET_MODEL=switchyard \ + ANTHROPIC_DEFAULT_HAIKU_MODEL=switchyard \ + claude --model switchyard +``` + +Use your saved Claude login, without an `apiKeyHelper` or gateway token. + +## Check the routing + +Send a prompt, then check which models handled the answer and classification: + +```bash +curl -s http://127.0.0.1:4123/v1/stats \ + | jq '{answers: .models, classifier: .classifier.models}' +``` diff --git a/mkdocs.yml b/mkdocs.yml index 5cd2a986c..57cf32d62 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -27,6 +27,8 @@ nav: - NeMo Relay: integrations/nemo_relay.md - pi: integrations/pi.md - Oh My Pi: integrations/oh_my_pi.md + - Recipes: + - Single-provider coding agents: recipes/single_provider_coding_agents.md - Routing: - Overview: routing_algorithms/overview.md - Task (LLM Classifier): routing_algorithms/llm_classifier_routing.md