Skip to content

feat: fall back to OpenCode when Anthropic is unavailable#107

Merged
samueltuyizere merged 3 commits into
routatic:mainfrom
vinicius91carvalho:106-anthropic-first-fallback
Jun 30, 2026
Merged

feat: fall back to OpenCode when Anthropic is unavailable#107
samueltuyizere merged 3 commits into
routatic:mainfrom
vinicius91carvalho:106-anthropic-first-fallback

Conversation

@vinicius91carvalho

Copy link
Copy Markdown
Contributor

Closes #106

Summary

  • add opt-in Anthropic-first passthrough with OAuth/capability header preservation
  • fall back on 408, 429, 5xx, and transport failures before response streaming starts
  • honor Retry-After with adaptive single-request recovery probes and no synthetic health calls
  • skip usage-limited OpenCode Go models and continue through working Zen-free fallbacks
  • refresh generated defaults and document Claude subscription configuration

Validation

  • gofmt check
  • go vet ./...
  • go test ./... -race
  • go build ./cmd/routatic-proxy
  • golangci-lint (0 issues)
  • live Claude Code -> Anthropic passthrough
  • forced Anthropic 429 -> real OpenCode fallback
  • resumed Claude Code session retained context across Anthropic -> OpenCode failover
  • live one-token checks for configured Zen-free models

Notes

The free Zen catalog still lists MiniMax M3 Free and Qwen3.6 Plus Free, but both report that their promotions ended. Defaults therefore use the currently working Nemotron 3 Ultra Free, MiMo V2.5 Free, and DeepSeek V4 Flash Free endpoints.

@kilo-code-bot

kilo-code-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Code Review Roast 🔥

Verdict: No Issues Found | Recommendation: Merge

Oh wait, this PR is actually clean. I need to sit down. I had my flamethrower warmed up and everything.

📊 Overall: Like finding a unicorn in production — I didn't think clean PRs existed anymore, but here we are.

Files Reviewed (2 files)
  • internal/handlers/anthropic_first.go
  • internal/handlers/anthropic_first_test.go
Previous Review Summaries (2 snapshots, latest commit ef6bfef)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit ef6bfef)

Verdict: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
⚠️ warning 1
Issue Details (click to expand)
File Line Roast
internal/handlers/anthropic_first.go 120 Retry-After: 0 gets floor'd to 1 second instead of immediate retry

🔥 The incremental fix added a 1-second minimum floor to parseRetryAfter, but "0" per HTTP spec means "retry immediately" — not "wait one second." Past-dated HTTP dates also incorrectly return 1 second instead of 0. This could delay recovery when Anthropic signals readiness.

🏆 Best part: The context-aware streaming with sync.Pool buffer reuse is actually clever. Memory allocation optimization while maintaining cancel propagation? I need to sit down.

💀 Worst part: Retry-After: 0 treated as 1 second. Nothing says "production ready" like reinterpreting spec-compliant retry directives.

📊 Overall: Like a second pancake — better than the first but still slightly misshapen.

Files Reviewed (2 files)
  • internal/handlers/anthropic_first.go - 1 issue
  • internal/handlers/anthropic_first_test.go - no issues (fix correct)

Fix these issues in Kilo Cloud

Previous review (commit e1b12f8)

Verdict: No Issues Found | Recommendation: Merge

Oh wait, this PR is actually clean. I need to sit down. I had my flamethrower warmed up and everything.

📊 Overall: Like finding a unicorn in production — I didn't think clean PRs existed anymore, but here we are.

The Anthropic-first passthrough implementation is solid:

  • Proper circuit breaker pattern with exponential backoff up to 15 minutes
  • Retry-After header support for HTTP-date format parsing (though now is passed as parameter, not captured internally)
  • Zero-byte stream handling with 32KB buffer
  • Provider-wide usage limit skipping works correctly in both streaming and non-streaming paths
  • Tests cover concurrent probe scenarios, transport failures, and redirect handling without credential leaks

The only thing that made me raise an eyebrow was copyStreamingResponse silently swallowing write errors — but that's expected for streaming where client disconnects are normal.

Files Reviewed (11 files)
  • internal/handlers/anthropic_first.go - 287 lines (new)
  • internal/handlers/anthropic_first_test.go - 228 lines (new)
  • internal/handlers/messages.go - 6 changed lines
  • internal/handlers/messages_test.go - 87 new lines
  • internal/server/server.go - 2 changed lines
  • internal/config/config.go - 5 new lines
  • internal/config/loader.go - 4 new lines
  • internal/config/loader_test.go - 22 new lines
  • internal/router/fallback.go - 9 changed lines
  • internal/router/fallback_test.go - 48 new lines
  • internal/provider/opencode_zen.go - 2 new lines
  • cmd/routatic-proxy/main.go - 20 changed lines

Reviewed by step-3.7-flash-20260528 · Input: 341.5K · Output: 4.3K · Cached: 5.9K

Comment thread internal/handlers/anthropic_first.go

@samueltuyizere samueltuyizere left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM!

@samueltuyizere samueltuyizere merged commit 9e294f9 into routatic:main Jun 30, 2026
3 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.

Feature: use OpenCode only when Anthropic is unavailable

2 participants