Commit Graph
29 Commits
Author SHA1 Message Date
whit3rabbitandClaude Opus 4.6 a4e655c8bb feat: LiteLLM gap fill - chat completions input, Azure backend, virtual keys, client SDK
Phase 1-8 implementation of the LiteLLM gap fill feature set:

- POST /v1/chat/completions: Accept OpenAI-format input, translate through
  Anthropic pipeline, return OpenAI-format responses (streaming + non-streaming)
- Reverse translation layer: openai_to_anthropic_request, anthropic_to_openai_response,
  ReverseStreamingTranslator (Anthropic SSE -> OpenAI ChatCompletionChunk)
- Azure OpenAI backend: BACKEND=azure with deployment-scoped URLs, api-key header,
  api-version query param (default 2024-10-21)
- Virtual key management: SQLite-backed CRUD via admin API (POST/GET/DELETE
  /admin/api/keys), DashMap in-memory cache, immediate revocation
- Per-key rate limiting: RPM sliding window enforcement in auth middleware,
  429 with retry-after header on limit exceeded
- Client library v0.2.0: ClientBuilder, ToolBuilder, ToolChoiceBuilder,
  typed streaming, rustdoc examples
- New dependencies: dashmap, aws-sigv4, aws-credential-types (prod);
  opentelemetry stack (feature-gated, optional)

534 tests passing, 0 failures, clippy clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 20:09:40 -05:00
whit3rabbitandClaude Sonnet 4.6 f1df50ff37 refactor: extract shared client crate and rename to anyllm_*
Introduce `anyllm_client` crate containing HTTP client construction,
SSRF-safe DNS resolver, retry/backoff logic, rate limit header parsing,
and SSE frame parsing. These were previously inlined in the proxy crate.

Rename crates from `anthropic_openai_proxy`/`anthropic_openai_translate`
to `anyllm_proxy`/`anyllm_translate` throughout.

proxy/backend: now re-exports retry, rate limit, and SSE symbols from
the client crate; `send_with_retry` and `build_http_client` are thin
adapters bridging BackendAuth/TlsConfig to the client crate's types.

streaming: remove duplicate `find_double_newline` and
`MAX_SSE_BUFFER_SIZE` definitions; import from `crate::backend` instead.

Fix missing `pub mod` declarations in translator and proxy that were
accidentally replaced by doc comments (streaming, usage_map, server,
redact).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 06:11:01 -05:00
whit3rabbitandClaude Opus 4.6 ded040090b docs: add missing doc comments and remove stale PLAN.md references
Add doc comments to ~30 undocumented public functions, structs, enum
variants, and fields across both crates. Strengthen weak comments to
explain "why" not just "what". Remove 16 stale PLAN.md line references
(PLAN.md was removed previously). Add Anthropic API doc links where
relevant for rate limit headers and ID format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:23:39 -05:00
whit3rabbitandClaude Opus 4.6 c607620c19 fix: local LLM compat, protocol headers, and doc cleanup
- Strip markdown code fences from tool call arguments (DeepSeek/Qwen)
- Add OMIT_STREAM_OPTIONS for backends that reject unknown fields
- Strip n/temperature/top_p for o-series models
- Add anthropic-version header to all responses
- Add x-token-count-warning header to count_tokens endpoint
- Rewrite README for clarity; remove stale PLAN.md, TASKS.md, CHANGELOG.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:24:57 -05:00
whit3rabbitandClaude Opus 4.6 c033ef0705 fix: o-series model compat, restore read_timeout, deduplicate date math
- Handle o-series reasoning models (o1, o3, o4-mini): drop max_tokens
  (keep only max_completion_tokens) and convert system -> developer role
- Restore read_timeout(900s) alongside tcp_keepalive(60s) to bound hung
  connections that keepalive alone cannot detect
- Reuse epoch_to_iso8601 from admin/db.rs instead of duplicating the
  Hinnant civil date algorithm in backend/mod.rs
- Make ISO 8601 conversion testable via anchor time parameter
- Fix f64 truncation in duration parsing (use .round() before cast)
- Extract convert_reset_duration helper to deduplicate header injection
- Use eq_ignore_ascii_case in is_o_series_model to avoid allocation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:42:59 -05:00
whit3rabbitandClaude Opus 4.6 30611bff48 fix: security hardening, streaming correctness, and admin robustness
Security: hash API keys with SHA-256 for constant-time comparison (eliminates
length timing leak), require explicit PROXY_OPEN_RELAY for unauthenticated
access, gate /metrics behind auth, sanitize admin error responses, enforce
log_level allowlist on DB restore, validate GCP identifiers against URL
injection, add referrer-policy header to admin SPA.

Correctness: hold concurrency semaphore permit through entire stream lifetime
(not just until headers are sent), fix SSE parser to resume scanning near
chunk boundaries instead of re-scanning from start, mark padding tool call
slots as closed to prevent spurious ContentBlockStop events, mark responses
streaming translator as finished on error to prevent double closure events,
serialize concurrent config writes with a Mutex.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:14:37 -05:00
whit3rabbitandClaude Opus 4.6 bf33d8d2f4 fix: return proper HTTP status for pre-stream backend errors
Previously, backend errors (401, 429, 500) that occurred before any SSE
data was sent were wrapped in a 200 OK response with an error event
buried in the stream. Now messages_stream returns Result so the caller
can respond with the correct HTTP status code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 06:55:07 -05:00
whit3rabbitandClaude Opus 4.6 a0527551cb feat: add DeepSeek/Qwen compatibility (reasoning_content, forward-compat FinishReason)
Prevents hard deserialization failures from unknown finish reasons
(e.g. DeepSeek's "insufficient_system_resource") and adds bidirectional
mapping of reasoning_content to/from Anthropic thinking blocks for
DeepSeek/Qwen thinking models.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 06:54:22 -05:00
whit3rabbitandClaude Opus 4.6 8b111e3005 refactor: split large modules, fix IPv6 host parsing, add Anthropic error shapes
Split config.rs into config/{mod,tls,url_validation}.rs and extract
server/{passthrough,streaming,token_counting}.rs and admin/ws.rs from
their parent modules for clarity.

Functional changes:
- Add DNS rebinding protection on admin API (Host header validation)
- Fix IPv6 host parsing in admin origin check (bare ::1 was mishandled)
- Return Anthropic-shaped errors for JSON parse failures (400 not 422)
  and unmatched routes (404 not_found_error)
- Forward extra fields from Anthropic request to OpenAI request
- Count "Error: " prefix tokens for error tool results
- Reduce TOKENIZER visibility to module-private

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 06:30:18 -05:00
whit3rabbitandClaude Opus 4.6 f6c5aae22d fix: address security audit findings (timing, log escalation, TOCTOU, gitignore)
- Use constant-time comparison (subtle::ConstantTimeEq) for proxy API key
  validation, matching the pattern already used in admin auth
- Restrict admin config log_level to allowlist (error/warn/info/debug) to
  prevent trace-level logging that leaks secrets in HTTP headers
- Create admin token file with atomic 0o600 permissions via OpenOptionsExt
  to eliminate TOCTOU race where file is briefly world-readable
- Add .admin_token, *.db, and TLS key material to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:19:00 -05:00
whit3rabbitandClaude Opus 4.6 379052b79a fix: security hardening, correctness fixes, and extended thinking support
- Constant-time token comparison in admin auth (timing side-channel)
- Origin header parsing via URL to prevent bypass (e.g., 127.0.0.1.attacker.com)
- CSP headers and X-Frame-Options on admin SPA
- WebSocket origin check for cross-site WS hijacking prevention
- Switch admin DB mutex from tokio::Mutex to std::Mutex, use spawn_blocking
- Poison-recovery on std::sync locks (unwrap_or_else + into_inner)
- JSON builder for SSE error fallback to prevent injection
- UTF-8-safe secret redaction (char-aware slicing)
- Add RedactedThinking content block and SignatureDelta streaming types
- Map OpenAI refusal field to Anthropic text block (non-streaming + streaming)
- Map OpenAI cached_tokens to Anthropic cache_read_input_tokens
- Map HTTP 408 to Anthropic OverloadedError
- Warn on trace log level and log_bodies enable via admin API
- Update CLAUDE.md docs to match current state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:11:25 -05:00
whit3rabbitandClaude Opus 4.6 486661e0a0 refactor: remove native Gemini API translation, use OpenAI-compatible endpoint
Gemini's OpenAI-compatible endpoint (/openai) supports the same Chat
Completions format as the OpenAI backend, making the native Gemini
translation path redundant. This removes ~3400 lines of Gemini-specific
types, mapping, streaming, and client code, routing Gemini through the
existing OpenAI translation pipeline instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 06:34:03 -05:00
whit3rabbitandClaude Opus 4.6 9b00345746 fix: harden proxy with security, correctness, and reliability improvements
Security: strip admin token from browser URL, add cross-origin rejection
middleware for admin API, skip tool calls with empty names instead of
substituting "unknown".

Correctness: use BytesMut for SSE buffering to prevent UTF-8 corruption
at TCP chunk boundaries, use saturating_sub for epoch arithmetic, handle
CRLF SSE frame delimiters.

Runtime: switch runtime_config to std::sync::RwLock (guard is !Send),
use block_in_place for SQLite IO, spawn_blocking for tokenization,
add tracing reload layer so admin log_level changes apply immediately.

Reliability: retry failed log buffer flushes with capped retry queue,
add MAX_SSE_BUFFER_SIZE guard in middleware handler, cap tool call and
part indices to prevent unbounded vec growth.

Observability: defer streaming request logging until stream completes
so entries capture actual status, latency, and token counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 21:22:42 -05:00
whit3rabbitandClaude Opus 4.6 a4e2458ecb docs: update README and CLAUDE.md for multi-backend and admin features
README: rewrite with use cases, Claude Code / local LLM / OpenRouter
examples, multi-backend TOML config, admin dashboard documentation,
and updated endpoint table.

CLAUDE.md: update test counts, add Anthropic backend, PROXY_API_KEYS,
admin module, and correct architecture references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:34:56 -05:00
whit3rabbitandClaude Opus 4.6 6148b44e46 feat: add admin dashboard with request logging and observability
Localhost-only admin server (default port 3001) with:
- Web UI dashboard with live request feed via WebSocket
- SQLite-backed request log with pagination and filtering
- Hot-reload config (model mappings, log level, log bodies) persisted
  to SQLite across restarts
- Per-backend metrics with error rate tracking
- Token-based auth (random UUID printed to stderr, or set ADMIN_TOKEN)
- Automatic log retention purge (ADMIN_LOG_RETENTION_DAYS, default 7)

Supporting changes:
- Backend error types gain status_code() for request log entries
- Metrics gains Clone, Default, error_rate() for admin aggregation
- Routes track per-request context (RequestCtx) and log to admin
- Error responses sanitized: internal details logged server-side only,
  clients receive generic messages (prevents infrastructure leaks)
- SSE buffer guard (10 MB max) prevents unbounded memory from
  misbehaving backends
- New deps: rusqlite (bundled), toml, indexmap, bytes, axum ws feature

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:34:48 -05:00
whit3rabbitandClaude Opus 4.6 53ab9c4314 feat: add PROXY_API_KEYS allowlist and DNS resolution SSRF validation
- PROXY_API_KEYS env var: comma-separated allowlist of valid API keys.
  When set, only listed keys are accepted. When unset, any non-empty key
  is accepted (backward-compatible behavior).
- DNS resolution validation: base URL validation now resolves domain
  names at startup and rejects any that resolve to private/loopback IPs,
  hardening against DNS rebinding attacks.
- Made is_private_ip public for reuse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:34:31 -05:00
whit3rabbitandClaude Opus 4.6 5661f63534 fix: add missing Anthropic passthrough backend client
The previous commit added `pub mod anthropic_client` to backend/mod.rs
and wired up BackendKind::Anthropic in config and routes, but did not
include the actual client implementation file -- breaking compilation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:34:23 -05:00
whit3rabbitandClaude Opus 4.6 e7f03b345c feat: add OpenAI Responses API backend and live API integration tests
Wire up Responses API as alternative to Chat Completions via
OPENAI_API_FORMAT=responses env var. Adds request/response mapping,
streaming state machine, client methods, and route dispatch. Includes
live API integration tests (ignored by default, require OPENAI_API_KEY).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:54:49 -05:00
whit3rabbitandClaude Opus 4.6 0a9ca1ae31 fix: simplify retry loop, sanitize request IDs, and apply rustfmt (Phase 22)
Collapse retry + final-attempt into single inclusive loop, drain response
body before retry to return connections to pool, and replace panic on
invalid x-request-id with UUID fallback. Update CLAUDE.md/TASKS.md for
Phase 22 status. Apply cargo fmt across touched files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:41:06 -05:00
whit3rabbitandClaude Opus 4.6 8790c68684 feat: add LOG_BODIES toggle for opt-in request/response debug logging (Phase 22)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:07:35 -05:00
whit3rabbitandClaude Opus 4.6 9ed5be65c5 test: add error/edge case fixtures for OpenAI, Gemini, Anthropic (Phase 22)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:04:35 -05:00
whit3rabbitandClaude Opus 4.6 04b2e92f82 feat: passthrough backend rate limit headers as Anthropic equivalents (Phase 22)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:01:43 -05:00
whit3rabbitandClaude Opus 4.6 3343aac893 feat: add graceful shutdown with SIGINT/SIGTERM and in-flight draining (Phase 22)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:58:14 -05:00
whit3rabbitandClaude Opus 4.6 76e9392656 Add native Gemini backend, library mode, and middleware (Phases 20d-20g, 21a-21c)
Gemini native backend:
- Schema sanitizer strips unsupported JSON Schema keys for Gemini (20d)
- Anthropic-to-Gemini message mapping with role coercion and turn merging (20e)
- Streaming state machine for Gemini SSE and Vertex AI responses (20f)
- GeminiClient with retry/backoff, BackendClient enum dispatch (20g)
- Unified BackendError with per-backend error helpers
- Shared retry logic extracted to backend/mod.rs

Library mode (21a-21c):
- TranslationConfig with builder pattern, model mapping, lossy behavior control
- translate_request/translate_response convenience functions
- Public TranslateError enum, crate-level doc examples
- Axum middleware layer (AnthropicTranslationLayer) for embedding in existing services
- Feature-gated middleware deps (axum, reqwest, tokio)
- library_usage and middleware_integration test suites

Also: new Claude Code tool call fixtures, updated CLAUDE.md and TASKS.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:20:22 -05:00
whit3rabbitandClaude Opus 4.6 3b70d1c64e Add native Gemini API types (Phase 20c)
Pure type definitions for Gemini generateContent API: request/response
structs, Content/Part union, tool declarations, error shapes, safety
settings, and citation metadata. 19 serde round-trip tests with golden
fixtures. No mapping logic or proxy changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 21:07:29 -05:00
whit3rabbitandClaude Opus 4.6 8c149f6261 Add token counting endpoint and backend abstraction (Phases 19, 20b)
Phase 19: Replace count_tokens stub with tiktoken-rs implementation using
o200k_base encoder. Extracts text from system prompt, messages, tool
definitions, and thinking blocks for approximate token counting.

Phase 20b: Extract BackendClient enum in backend/mod.rs with OpenAI/Vertex
variants and dispatch methods, preparing for future native Gemini backend.
Pure refactor with no behavior change.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 20:42:02 -05:00
whit3rabbitandClaude Opus 4.6 ef7ffb0d4f Add Vertex AI OpenAI-compatible backend support (Phase 20a)
Parameterize OpenAIClient with BackendAuth enum to support both OpenAI
and Vertex AI backends. BACKEND=vertex enables Vertex AI with
VERTEX_PROJECT, VERTEX_REGION, and VERTEX_API_KEY/GOOGLE_ACCESS_TOKEN
env vars. Model defaults change to gemini-2.5-pro/gemini-2.5-flash
for Vertex. No new client type; reuses OpenAIClient with different
URL construction and auth header dispatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 20:20:48 -05:00
whit3rabbitandClaude Opus 4.6 d37d1e25f1 Add phases 12-20: release infra, transparent proxy, model mapping, mTLS, extended thinking, Gemini research
Phases 12-18: release infrastructure (LICENSE, README, Dockerfile, CI,
CHANGELOG), transparent proxy with anthropic-version/anthropic-beta header
passthrough and lossy translation warnings, BIG_MODEL/SMALL_MODEL env-based
model mapping, mTLS client cert support (P12/PEM), max_completion_tokens
and reasoning_effort passthrough via serde flatten, extended thinking type
support (thinking blocks stripped in translation), top_k typed field.

Phase 20: Gemini backend research with docs/gemini-api-diffs.md covering
native API format, tool calling, streaming, auth, schema restrictions,
and Vertex AI OpenAI-compatible endpoint. Task roadmap through Phase 22.

Test count: 169 -> expanded with new fixture and unit tests for all phases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 20:06:50 -05:00
whit3rabbitandClaude Opus 4.6 f2e3ed15f4 Initial commit: Anthropic-to-OpenAI API translation proxy
Rust workspace with two crates:
- translator: pure, IO-free mapping between Anthropic Messages API and OpenAI Chat Completions
- proxy: axum HTTP server with auth, streaming SSE, retry/backoff, concurrency limits

169 tests passing (unit, golden fixture, integration).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:25:43 -05:00