Commit Graph

48 Commits

Author SHA1 Message Date
diegosouzapw
ba4b496306 Merge PR #666: Add Claude prompt cache logging and exclude cache reads
Includes fixes applied during review:
- Removed duplicate imports in chatCore.ts
- Fixed stray translatedBody argument (stream boolean bug)
- Fixed truncated test file
- Fixed usageExtractor cached_tokens fallback

Closes #688, Closes #640
2026-03-28 01:53:25 -03:00
diegosouzapw
c48554589c fix: repair test failures from PR #666 changes
- Fix usageExtractor cached_tokens fallback for Responses API (use cache_read_input_tokens when input_tokens_details is absent)
- Fix truncated claude-native-passthrough-tools.test.mjs that caused parse error
2026-03-28 01:50:04 -03:00
Benjamin Kitt
682fd550fa fix(core): remove extra arg in claude passthrough translateRequest call
The second translateRequest call in the claude->openai->claude passthrough
path had an extra `translatedBody` argument before `stream`, shifting all
parameters by one. This caused the `stream` field in the upstream request
to be set to an object instead of a boolean, producing:
  "stream: Input should be a valid boolean"

Co-Authored-By: Craft Agent <agents-noreply@craft.do>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 22:30:02 -05:00
cai kerui
ae8d2ac2e1 Merge branch 'main' into codex/claude-cache-log-accounting 2026-03-27 17:25:38 +09:00
cai kerui
93beb068a3 Add Claude prompt cache logging and exclude cache reads 2026-03-27 15:14:54 +09:00
cai kerui
e88d260acd Merge branch 'main' into codex/claude-native-tool-fix-push 2026-03-27 14:37:02 +09:00
cai kerui
161e377ec1 Fix Claude native tool names for Claude Code 2026-03-27 14:00:05 +09:00
diegosouzapw
926fd8abf4 fix: disable proxy_ tool prefix for all Claude-target passthrough (#618)
The openai-to-claude translator was prefixing tool names with 'proxy_'
(e.g. Bash → proxy_Bash) even when routing Claude-format requests to
native Claude/Anthropic providers. Claude rejects unknown tool names,
causing 'No such tool available: proxy_Bash' errors.

Root cause: the _disableToolPrefix condition only disabled the prefix
for non-Claude providers, but it should be disabled for ALL providers
in the Claude passthrough path since tools are already in Claude format.

Fixes #618
2026-03-26 19:44:44 -03:00
diegosouzapw
8752790352 fix: rename Hindi locale in→hi, global tool name filter, collapse \n artifacts (#642, #637, #638)
- Rename in.json → hi.json: 'in' is Indonesian (ISO 639-1), Hindi is 'hi'.
  Fixes Weblate locale conflict where id.json and in.json both claimed Indonesian.
- Move empty tool name filter before Codex passthrough: nativeCodexPassthrough
  skipped all input sanitization, causing 400 'empty tool name' from upstream.
- Collapse 3+ consecutive newlines to \n\n in response sanitizer: thinking
  models accumulate excessive line breaks between tool call blocks.
2026-03-26 09:22:10 -03:00
Diego Rodrigues de Sa e Souza
33fee5dcc5 fix: strip proxy_ prefix in non-streaming Claude responses & fix LongCat validation (#605, #592) (#607)
- fix(translator): pass toolNameMap to translateNonStreamingResponse so Claude
  OAuth proxy_ prefix is correctly stripped from tool_use block names in
  non-streaming responses (was only stripped in streaming path)
- fix(validation): add LongCat specialty validator that probes /chat/completions
  directly, bypassing the /v1/models endpoint that LongCat does not expose (#592)

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-03-25 08:16:46 -03:00
diegosouzapw
9248ab4dfd fix(ci): route validation, CodeQL alerts, Docker workflow
- Add Zod schemas + validateBody() to 5 routes missing validation:
  model-combo-mappings (POST, PUT), webhooks (POST, PUT), openapi/try (POST)
- Fix 6 polynomial-redos CodeQL alerts in provider.ts and chatCore.ts
  by replacing (?:^|/) alternation patterns with segment-based matching
- Fix insecure-randomness in acp/manager.ts (crypto.randomUUID)
- Fix shell-command-injection in prepublish.mjs (JSON.stringify)
- Upgrade docker/setup-buildx-action from v3 to v4 (Node.js 20 deprecation)

CI check:route-validation:t06 PASS (176/176 routes validated)
Tests: 926/926 pass
2026-03-24 16:08:02 -03:00
diegosouzapw
d68143e63d Merge PR #575: feat(dashboard,sse,api) — per-model upstream headers, compat PATCH, chat alignment (by @zhangqiang8vip) 2026-03-24 09:46:59 -03:00
zhang-qiang
a8ca88797a feat(dashboard,sse,api): per-model upstream headers, compat PATCH, chat alignment
- Store/sanitize upstreamHeaders; shared forbidden header names (upstreamHeaders.ts)

- chatCore: buildUpstreamHeadersForExecute; T5 recomputes; 401 retry uses translatedBody.model

- Dashboard compat popover + i18n; Zod partialRecord + header value newline guard

- Executors merge upstreamExtraHeaders; sanitize unit tests

- Dev: bootstrap env in run-next, instrumentation-node import, credentialLoader dedupe

Made-with: Cursor
2026-03-24 17:24:11 +08:00
diegosouzapw
18258b9b0d fix: merge PR #562 — MCP session management, Claude passthrough, OAuth modal, detectFormat fixes
Cherry-pick from codex/omniroute-fixes-20260324:
- Replace MCP singleton transport with per-session architecture for Streamable HTTP
- Fix Claude passthrough via OpenAI round-trip normalization
- Add detectFormatFromEndpoint() for endpoint-aware format detection
- Support raw code#state in OAuth modal for Claude Code remote auth
- Expose cloudConfigured/cloudUrl/machineId in settings API
- Switch docker-compose.prod.yml target to runner-cli
- Add 3 new tests for round-trip and detectFormat

PR: #562
2026-03-23 19:53:02 -03:00
diegosouzapw
c34b3f41bd feat: Add requested model to logs, enhance background task detection, and introduce AI SDK compatibility utilities. 2026-03-23 11:08:14 -03:00
diegosouzapw
0546d06c0a fix(types): cast extracted usage to Record<string,number> in stream.ts to resolve TS property errors
Also fix syntax error in openai-to-claude-strip-empty.test.mjs (tool/assistant messages were incorrectly nested)
2026-03-23 09:21:03 -03:00
diegosouzapw
6a2c7b467d fix(3.0.0-rc/batch3): convert tool_result blocks to text to stop Codex loop (#527)
fix(chat): convert tool_result content blocks to [Tool Result: id] text (#527)
  - Previously, tool_result blocks in user messages were silently dropped
  - This caused an infinite loop when Claude Code + superpowers routed to Codex:
    Codex never received the tool response and kept re-requesting the tool
  - Now: tool_result → text block '[Tool Result: {id}]\n{content}'
  - Handles string, array-of-text, and JSON-serialized content types

docs(issues): add Turbopack postinstall workaround on #509 and #508
docs(issues): note that #464 (API key provisioning) is on the v3.0 roadmap
2026-03-22 11:47:39 -03:00
zhang-qiang
13c45807ef feat: protocol-scoped model compat (V3)
- compatByProtocol per openai/openai-responses/claude

- getters take sourceFormat; chatCore passes it

- UI: protocol selector in compat popover, dark mode select

- shared/constants/modelCompat for client-safe import (fix node:crypto build)

- ZWS_README_V3.md

Made-with: Cursor
2026-03-20 22:06:03 +08:00
zhang-qiang
a7fe369ea0 fix: resolve role param error for Responses API + MiniMax (developer→system)
- Add preserveDeveloperRole option and model compat override

- Normalize developer→system in roleNormalizer when not preserving

- Translator runs normalizeRoles for Responses API with option

- UI: ModelCompatPopover with do not preserve developer toggle

- Add ZWS_README_V2 documenting cause and fix

Made-with: Cursor
2026-03-20 21:06:10 +08:00
diegosouzapw
2d7d7776a6 fix(routing): model aliases now affect routing, not just format detection (#472)
Previously resolveModelAlias() output was used only for getModelTargetFormat()
but the original model was sent in translatedBody.model and to the executor.
Now effectiveModel is propagated to all downstream operations.
2026-03-19 11:07:29 -03:00
diegosouzapw
601cc21a44 feat: call log response content, per-model tool call ID, key PATCH & validation (#470) 2026-03-19 08:41:01 -03:00
Sergey Morozov
8420e565d4 feat: add responses subpath passthrough for codex (#457) 2026-03-18 17:18:29 -03:00
diegosouzapw
a3bc7620b1 feat(integration): integrate ClawRouter services into active pipeline
- intentClassifier → engine.ts selectProvider()
  When taskType is 'default', classifies prompt via multilingual keyword
  detection (9 langs) and uses detected intent (code/reasoning/simple/medium)
  for 6-factor task fitness scoring.

- emergencyFallback → chatCore.ts error path (after T5 intra-family fallback)
  On HTTP 402 or budget-exhaustion keywords, attempts one redirect to
  nvidia/gpt-oss-120b ($0.00/M) before returning error to combo router.
  Skipped for streaming requests and tool-calling requests.

- AutoComboConfig.routerStrategy field added
  Allows per-combo strategy override ('rules' | 'cost' | 'latency')

Note: requestDedup was already integrated in chatCore.ts (line 387-430)
Branch: feat/clawrouter-improvements
2026-03-17 15:22:12 -03:00
diegosouzapw
095c84ac16 fix(providerRegistry): remove duplicate claude-haiku-4-5-20251001 from anthropic provider to prevent ambiguous model resolution 2026-03-17 13:10:23 -03:00
diegosouzapw
838f1d645c fix(v2.6.9): CI budget checks, #409 file attachments, atomic release workflow
Includes version bump — v2.6.9 — committed ATOMICALLY with all changes:

fixes:
- fix(ci/t11): Remove 'any' from comments in openai-responses.ts + chatCore.ts
  (\bany\b regex counted comment text as explicit any violations)
- fix(chatCore/#409): Normalize unsupported content part types before forwarding
  Cursor sends {type:'file'} for .md attachments; Copilot/OpenAI providers reject
  with 'type has to be either image_url or text'. Now: file/document→text block,
  unknown types dropped with debug log. Fixes claude-* models via github-copilot.

workflow:
- chore(generate-release): ATOMIC COMMIT RULE — npm version patch MUST run before
  feature commits so the release tag always points to a commit with full changes
2026-03-17 09:09:01 -03:00
diegosouzapw
f260483101 Merge pull request #427 from contributor branch 2026-03-17 08:14:03 -03:00
Diego Rodrigues de Sa e Souza
9644444028 Merge pull request #418 from prakersh/fix/claude-to-claude-passthrough
fix(sse): add Claude-to-Claude passthrough for anthropic-compatible providers
2026-03-17 08:09:44 -03:00
Oleg Saprykin
2908303d4b fix(sse): strip empty text content blocks before translation
Anthropic API rejects requests containing {"type":"text","text":""} with
400 "text content blocks must be non-empty". Some clients like LiteLLM
passthrough and @ai-sdk/anthropic may forward empty text blocks as-is.

Filter out empty text content blocks from messages before calling
translateRequest, similar to how empty-name tools are already stripped.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 10:46:24 +03:00
Prakersh Maheshwari
1bdabf43db fix: prevent mutation of original request body in Claude passthrough
Use shallow copy ({ ...body }) instead of direct reference assignment
so that later translatedBody.model = model does not mutate the
caller's original body object.
2026-03-17 02:45:21 +05:30
Prakersh Maheshwari
6ff7b6570c fix(sse): add Claude-to-Claude passthrough for anthropic-compatible providers
When both source and target formats are Claude, skip all request
modification and forward the body untouched. This prevents
prepareClaudeRequest from corrupting valid Claude-native requests
destined for anthropic-compatible provider nodes.
2026-03-17 02:03:45 +05:30
Regis
d79b55be5a fix(sse): strip unsupported params for reasoning models (o1/o3)
Reasoning models (o1, o1-pro, o3, o3-mini) reject standard parameters
like temperature and top_p with 400 Bad Request. OmniRoute's default
executor forwards all parameters without filtering.

This fix adds declarative parameter filtering:
- Add unsupportedParams[] field to RegistryModel interface
- Add REASONING_UNSUPPORTED frozen constant shared across entries
- Add o1-pro, o3, o3-mini to OpenAI registry (were missing)
- Add getUnsupportedParams() helper with:
  - O(1) precomputed map lookup (not O(N×M) scan)
  - Cross-provider routing support via precomputed map
  - Prefixed model ID support (e.g., "openai/o3" → "o3")
- Strip unsupported params in chatCore.ts before executor call
- Use Object.hasOwn() for safe property check (no prototype chain)
- Log stripped params at WARN level for visibility
2026-03-16 19:41:55 +01:00
Oleg Saprykin
53de27417d fix(chat): handle Anthropic-format tools in empty-name filter (#346)
The filter introduced in #346 only checked OpenAI-format tool names
(tool.function.name), silently dropping all tools when the request
arrives in Anthropic Messages API format (tool.name without .function).

This happens when LiteLLM proxies requests with anthropic/ model prefix —
it translates to Anthropic format before forwarding, so OmniRoute receives
Claude-format tools. The filter drops them all, causing Anthropic API to
return 400: 'tool_choice.any may only be specified while providing tools'.

Fix: check both formats with fn?.name ?? tool.name.
2026-03-16 11:37:40 +03:00
Kfir Amar
b1c713de60 fix(codex): avoid mutating request body 2026-03-15 18:35:43 +02:00
Kfir Amar
8642e2b721 fix(codex): preserve native responses payloads 2026-03-15 18:25:22 +02:00
diegosouzapw
4fbe45f30a fix: stream timeout, combo test auth, and empty tool name (#355 #350 #346)
- fix #355: increase STREAM_IDLE_TIMEOUT_MS from 60s to 300s to prevent
  premature stream abortion for extended-thinking models (claude-opus-4-6,
  o3, etc.) that can pause >60s during reasoning phases. Configurable via
  STREAM_IDLE_TIMEOUT_MS env var.

- fix #350: combo health check test now bypasses REQUIRE_API_KEY=true by
  sending X-Internal-Test header, recognized in chat.ts auth pipeline to
  skip API key validation for internal admin-side combo tests. Also
  extended test timeout from 15s to 20s. Uses OpenAI-compatible format
  universally (not Claude-style).

- fix #346: filter out tools with empty function.name before forwarding
  to upstream providers. Claude Code sends empty-name tool definitions
  that cause '400 Invalid input[N].name: empty string' on OpenAI-compat
  providers. Extends existing message/input empty-name filter.
2026-03-14 15:28:53 -03:00
diegosouzapw
1b354be827 feat: T07 — API Key Round-Robin per provider connection
- New: open-sse/services/apiKeyRotator.ts — round-robin rotation
  between primary API key + providerSpecificData.extraApiKeys[]
- Modified: open-sse/executors/base.ts — buildHeaders() rotates key
  using getRotatingApiKey() when extraApiKeys configured
- Modified: open-sse/handlers/chatCore.ts — injects connectionId into
  credentials to enable per-connection rotation index tracking
- Modified: providers/[id]/page.tsx — 'Extra API Keys' UI section in
  EditConnectionModal: add/remove keys, persisted in providerSpecificData

T08 (quota window rolling) and T13 (wildcard model routing) confirmed
already implemented in accountFallback.ts and wildcardRouter.ts.
2026-03-14 15:03:54 -03:00
diegosouzapw
a87d64372f feat: Phase 1 & 2 implementation plan — T1-T10, T12
T1 (openai-to-claude.ts): response_format injection for json_schema/json_object
T2 (base.ts): intra-URL retry for 429 errors (2x, 2s delay)
T3 (gemini-cli.ts): CLI fingerprint headers (User-Agent, X-Goog-Api-Client)
T5 (modelFamilyFallback.ts + chatCore.ts): intra-family model fallback on 400/404
T9 (pricing.ts): deepseek-3.1, deepseek-3.2, qwen3-coder-next pricing
T10 (scoring.ts + modePacks.ts): tierPriority as 7th scoring factor (Ultra>Pro>Free)
T12 (cliRuntime.ts): isSafePath() guard for CLI_*_BIN env var paths
2026-03-12 18:06:53 -03:00
Diego Rodrigues de Sa e Souza
d87c7c3b8c Merge pull request #311 from DavyMassoneto/fix/merge-duplicates-and-lint-warnings
feat(claude): support [1m] suffix for 1M extended context window
2026-03-12 06:58:57 -03:00
DavyMassoneto
623c63baf6 feat(claude): support [1m] suffix for 1M context window
Parse [1m] suffix from model name (e.g. claude-sonnet-4-6[1m]) and
propagate extendedContext flag through the request pipeline to append
context-1m-2025-08-07 to the Anthropic-Beta header.
2026-03-11 23:53:09 -03:00
diegosouzapw
afe2ab37e4 fix(aliases): resolve custom model aliases before routing + restore on startup (#315, #316)
#315: Import and call resolveModelAlias() in chatCore.ts before the
getModelTargetFormat() lookup so that custom aliases configured in
Settings → Model Aliases → Pattern→Target are actually applied during
routing instead of being silently ignored.

#316: Load persisted custom model aliases from settings DB at server
startup (instrumentation.ts). Previously _customAliases started as an
empty object after every restart since setCustomAliases() was only
called by the PUT /api/settings/model-aliases handler — never at init.
Now aliases are restored from settings.modelAliases JSON field on boot.
2026-03-11 12:42:18 -03:00
diegosouzapw
6a7a6022d4 fix(chat): strip empty name fields from messages/input before upstream (#291)
OpenAI-compatible providers (OpenAI, Codex) reject name:'' with 400 errors:
  - 'Unknown parameter: input[1].name'
  - 'Invalid tools[0].name: empty string'

Some clients (e.g. PocketPaw) forward assistant turns with name:'' in
the OpenAI Responses API input[] and chat completions messages[].

Fix: filter out name:'' from messages[] and input[] before translateRequest.
Non-empty non-null name values are preserved per OpenAI spec.
2026-03-10 23:31:31 -03:00
diegosouzapw
5a53c17e81 feat: configurable tool name prefix (#199) and custom rpm/tpm rate limits (#198)
- Issue #199: proxy_ prefix on tool names is now automatically disabled
  when routing to non-Claude backends (Gemini, Compatible, etc.).
  Prevents tool name mismatches in OpenCode, Cursor, and other clients.

- Issue #198: Added customRpm/customTpm support per provider connection.
  Users can configure custom rate limits via connection settings,
  overriding the default auto-learned limits from response headers.
2026-03-05 01:41:34 -03:00
diegosouzapw
0d8f28a4a4 feat: Introduce A2A lifecycle management, add type safety to ComfyUI and stream handling, and update various handlers and translators. 2026-03-04 21:02:56 -03:00
diegosouzapw
20860877b8 feat: add TypeScript types and modularize translator registry
- Add type annotations to all providerModels helper functions
- Introduce LegacyProvider interface in providerRegistry
- Refactor translator system to use self-registering module pattern
  with bootstrapTranslatorRegistry() and per-file imports
- Simplify translator/index.ts by delegating to modular translators
- Remove hardcoded Gemini OAuth client secret for security
2026-03-04 18:46:49 -03:00
diegosouzapw
5ce95dd829 fix: resolve issues #89 #90 #91 — stream default, custom models, OAuth redirect
- fix(chatCore): stream defaults to false per OpenAI spec (body.stream === true)
  closes #89
- fix(models): custom OpenAI-compatible providers now appear in /v1/models
  Added raw providerId check against activeAliases
  closes #90
- fix(OAuthModal): Google OAuth providers force localhost redirect URI
  Targeted amber warning + redirect_uri_mismatch error guidance for remote deployments
  closes #91
- docs: Add 'OAuth em Servidor Remoto' tutorial in README with 7-step Google Cloud guide
- docs: .env.example prominent warning block for Google OAuth remote setup
- chore: bump version 1.0.6 → 1.0.7
- docs: CHANGELOG entry for v1.0.7
2026-02-20 11:50:50 -03:00
diegosouzapw
3aca5fa691 feat: Implement initial database schema and centralize CORS configuration across API routes. 2026-02-18 13:44:08 -03:00
diegosouzapw
ed05599cdd feat(api-compat): response sanitization, role normalization, structured output for Gemini
- Add responseSanitizer.ts: strips non-standard fields (x_groq, usage_breakdown, service_tier),
  extracts <think> tags into reasoning_content, normalizes id/object/usage for strict OpenAI SDK v1.83+ compatibility
- Add roleNormalizer.ts: developer→system for non-OpenAI providers, system→user merging for GLM/ERNIE models
- Integrate sanitizer into chatCore.ts (non-streaming) and stream.ts (streaming passthrough)
- Integrate role normalizer into translator/index.ts pipeline
- Add response_format (json_schema/json_object) → Gemini responseMimeType/responseSchema conversion
- Update CHANGELOG.md with v1.1.0 entry
- Update README.md, ARCHITECTURE.md, TROUBLESHOOTING.md with new capabilities
2026-02-18 08:38:44 -03:00
diegosouzapw
71d14209a4 feat: OmniRoute v1.0.0 — Intelligent AI Gateway & Universal LLM Proxy
OmniRoute is an intelligent API gateway that unifies 20+ AI providers behind a single
OpenAI-compatible endpoint. Features include intelligent routing with 6 strategies,
multi-format translation (OpenAI/Claude/Gemini/Responses API), circuit breakers,
semantic caching, combo fallback chains, real-time health monitoring, and a full
dashboard with provider management, analytics, and CLI tool integration.

Key highlights:
- 20+ providers (Claude Code, Codex, Gemini CLI, GitHub Copilot, iFlow, Qwen, Kiro, etc.)
- 6 routing strategies (Fill First, Round Robin, P2C, Random, Least Used, Cost Optimized)
- Export/Import database backup with full archive support
- Translator Playground with 4 modes (Playground, Chat Tester, Test Bench, Live Monitor)
- 100% TypeScript across src/ and open-sse/
- Docker support with multi-stage builds
- Comprehensive documentation and 9 dashboard screenshots
2026-02-18 00:02:15 -03:00