Commit Graph

893 Commits

Author SHA1 Message Date
diegosouzapw
d9ff0035f5 chore: bump version to 3.0.0-rc.6 (sub2api gap tasks T01-T15) v3.0.0-rc.6 2026-03-22 21:01:33 -03:00
diegosouzapw
7a7f3be0d2 feat(sub2api): implement T01-T15 gap analysis tasks (3.0.0-rc.6)
T01 (P1): requested_model column in call_logs
- Migration 009_requested_model.sql: ALTER TABLE call_logs ADD COLUMN requested_model
- callLogs.ts: INSERT + SELECT updated to include requestedModel field

T02 (P1): Strip empty text blocks from nested tool_result.content
- New stripEmptyTextBlocks() recursive helper in openai-to-claude.ts
- Applied on tool_result content before forwarding to Anthropic
- Prevents 400 'text content blocks must be non-empty' errors

T03 (P1): Parse x-codex-5h-*/x-codex-7d-* headers for precise quota reset
- parseCodexQuotaHeaders() in codex.ts extracts usage/limit/resetAt
- getCodexResetTime() returns furthest-out reset timestamp for safe unblocking

T04 (P1): X-Session-Id header for external sticky routing
- extractExternalSessionId() in sessionManager.ts reads x-session-id,
  x-omniroute-session, session-id headers with 'ext:' prefix to avoid collisions

T06 (P2): account_deactivated permanent expired status on 401
- ACCOUNT_DEACTIVATED_SIGNALS constant + isAccountDeactivated() in accountFallback.ts
- Returns 1-year cooldown (effectively permanent) to prevent retrying dead accounts

T07 (P2): X-Forwarded-For IP validation
- New src/lib/ipUtils.ts with extractClientIp() and getClientIpFromRequest()
- Skips 'unknown'/non-IP entries in X-Forwarded-For chain

T10 (P2): credits_exhausted distinct account status
- CREDITS_EXHAUSTED_SIGNALS + isCreditsExhausted() in accountFallback.ts
- Returns 1h cooldown with creditsExhausted flag, distinct from rate_limit 429

T11 (P1): max reasoning_effort -> budget_tokens: 131072
- EFFORT_BUDGETS and THINKING_LEVEL_MAP updated with max: 131072, xhigh: 131072
- Reverse mapping now returns 'max' for full-budget responses
- Unit test updated to expect 'max' (was 'high')

T12 (P3): Model pricing updates
- MiniMax M2.7 / MiniMax-M2.7 / minimax-m2.7-highspeed pricing added

T15 (P1): Array content normalization for system/tool messages
- normalizeContentToString() helper exported from openai-to-claude.ts
- System messages with array content now correctly collapsed to string
2026-03-22 20:55:35 -03:00
diegosouzapw
91e45fbe95 chore: remover new-features-sub21 do tracking do git
Remover as exceções !docs/new-features-sub21/ do .gitignore para que
a pasta de tasks internas não seja mais rastreada pelo git.
2026-03-22 20:32:17 -03:00
diegosouzapw
7d7e9da28c feat(providers): adicionar provedor Puter AI com 500+ modelos
Registrar o provedor Puter como gateway OpenAI-compatible que expõe
modelos de múltiplos fornecedores (GPT, Claude, Gemini, Grok, DeepSeek,
Qwen, Mistral, Llama) através de um único endpoint REST.

- Criar PuterExecutor com autenticação Bearer token
- Adicionar entrada no providerRegistry com 40+ modelos curados
- Habilitar passthroughModels para acesso aos 500+ modelos do catálogo
- Registrar alias "pu" para acesso rápido
- Adicionar metadados do provedor em shared/constants/providers.ts
2026-03-22 20:29:06 -03:00
diegosouzapw
24a9739604 docs: add sub2api gap analysis + 15 implementation tasks
Add competitive analysis of sub2api (v0.1.104, 87 contributors)
comparing features, open PRs, and model pricing against OmniRoute.

Files:
- docs/new-features-sub21/gap-analysis.md — full analysis (commits + 38 open PRs)
- docs/new-features-sub21/implementation-plan.md — phased plan for all 15 gaps
- docs/new-features-sub21/tasks/T01-T15 — detailed task files with:
  - Problem description + sub2api PR references
  - Step-by-step implementation with code snippets
  - Affected files list
  - Acceptance criteria

Priority breakdown:
  P1 (4): requested_model logs, empty tool_result blocks, x-codex-* headers, X-Session-Id
  P2 (6): rate-limit persistence, account_deactivated, XFF validation, session limits, Codex/Spark scopes, credits_exhausted
  P3 (5): max reasoning effort, model pricing, stale quota display, proxy fast-fail, array content

Source: https://github.com/Wei-Shaw/sub2api
2026-03-22 18:12:50 -03:00
diegosouzapw
4fb9687782 docs(3.0.0-rc.5): comprehensive CHANGELOG and README vs v2.9.5
- CHANGELOG: [3.0.0-rc.5] section now serves as full 'What's New vs v2.9.5':
  * 2 new providers (OpenCode Zen/Go via PR #530)
  * 3 new features: Registered Keys API (#464), provider icons (#529), model auto-sync (#488)
  * 10 bug fixes (#521, #522, #524, #527, #532, #535, #536, #537, #489, #510, #492)
  * 16 issues resolved total, DB migration 008
- README: added 'What's New in v3.0.0' table section after badges
v3.0.0-rc.5
2026-03-22 15:51:54 -03:00
diegosouzapw
95ffc21b60 feat(3.0.0-rc.5): Registered Keys Provisioning API (#464)
Complete implementation of auto-provisioning API:
- DB migration 008: registered_keys, provider_key_limits, account_key_limits
- src/lib/db/registeredKeys.ts: full quota enforcement, idempotency, sha256
  hashing, budget tracking, window auto-reset
- POST /api/v1/registered-keys — issue with quota check
- GET /api/v1/registered-keys — list (masked)
- GET|DELETE /api/v1/registered-keys/[id] — get/revoke
- POST /api/v1/registered-keys/[id]/revoke — explicit revoke
- GET /api/v1/quotas/check — pre-validate without issuing
- GET|PUT /api/v1/providers/[id]/limits — provider limits CRUD
- GET|PUT /api/v1/accounts/[id]/limits — account limits CRUD
- POST /api/v1/issues/report — optional GitHub issue reporting
  (requires GITHUB_ISSUES_REPO + GITHUB_ISSUES_TOKEN env vars)
- Exported all from localDb.ts
2026-03-22 15:33:45 -03:00
diegosouzapw
f3c5e55b26 feat(3.0.0-rc.4): merge PR #530 — OpenCode Zen and Go providers
Includes all commits from @kang-heewon's PR #530:
- OpencodeExecutor with multi-format routing
- opencode-zen + opencode-go registered in provider registry
- UI metadata added to providers.ts
- Unit tests for OpencodeExecutor (improved to avoid state coupling)

Cherry-picked from add-opencode-providers into 3.0.0-rc.
Conflicts resolved: executors/index.ts (merged pollinations+cloudflare-ai),
providerRegistry.ts (kept testKeyBaseUrl from rc.2 + PR's authType/models).
v3.0.0-rc.4
2026-03-22 15:23:00 -03:00
kang-heewon
40183c6a5c test(providers): improve OpencodeExecutor tests to avoid internal state coupling 2026-03-22 15:22:38 -03:00
kang-heewon
457c59e38a test(providers): add unit tests for OpencodeExecutor 2026-03-22 15:22:38 -03:00
diegosouzapw
aa93a3f2e2 feat(3.0.0-rc.3): provider icons, model auto-sync, Gemini OAuth fix
feat(ui): ProviderIcon component with @lobehub/icons + PNG fallback (#529)
  - 130+ providers covered by Lobehub SVG components via LobehubErrorBoundary
  - Falls back to existing /providers/{id}.png, then generic icon
  - Replaces manual img state machine in ProviderCard + ApiKeyProviderCard

feat(scheduler): modelSyncScheduler — 24h model list auto-update (#488)
  - Syncs 16 major providers every 24h (MODEL_SYNC_INTERVAL_HOURS configurable)
  - Wired into POST /api/sync/initialize startup hook

fix(oauth): Gemini CLI — clear error when client_secret missing in Docker (#537)
v3.0.0-rc.3
2026-03-22 15:01:38 -03:00
diegosouzapw
8b9abcb6cc fix(3.0.0-rc.2): resolve issues #536, #535, #524
fix(providers): LongCat AI key validation — correct base URL and auth header (#536)
  - baseUrl: longcat.chat/api/v1/chat/completions -> api.longcat.chat/openai
  - authHeader: 'bearer' -> 'Authorization' + authPrefix: 'Bearer'

fix(combo): implement pinnedModel override in comboAgentMiddleware (#535)
  - Previously: pinnedModel was detected but body.model was never updated
  - Now: body = { ...body, model: pinnedModel } when context_cache_protection fires

fix(cli-tools): add OpenCode config save to guide-settings endpoint (#524)
  - Added 'opencode' case to switch in guide-settings/[toolId]/route.ts
  - saveOpenCodeConfig(): XDG_CONFIG_HOME aware, writes [provider.omniroute] TOML block
v3.0.0-rc.2
2026-03-22 13:31:56 -03:00
diegosouzapw
1ecc1908c7 chore(3.0.0-rc.1): bump version to 3.0.0-rc.1, close resolved issues, update CHANGELOG
- package.json: 2.9.5 → 3.0.0-rc.1
- docs/openapi.yaml: version → 3.0.0-rc.1
- CHANGELOG.md: add [3.0.0-rc.1] section with all batch1-3 fixes
- scripts/check-docs-sync.mjs: isSemver now accepts pre-release versions (X.Y.Z-prerelease.N)

Closed issues: #489, #492, #510, #513, #520, #521, #522, #525, #527, #532
RC versioning: rc.1 → rc.2 → rc.N on each VPS deploy until v3.0.0 is approved
v3.0.0-rc.1
2026-03-22 12:25:30 -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
diegosouzapw
0acef57865 fix(3.0.0-rc/batch2): resolve issues #510, #492, and improve #520, #529
fix(cli): normalize MSYS2/Git-Bash paths in cliRuntime.ts (#510)
  - Add normalizeMsys2Path() helper: /c/Program Files/... → C:\Program Files\...
  - Apply to both Windows 'where' and Unix 'command -v' path resolution
  - Fixes 'CLI not detected' on Windows when running Git Bash / MSYS2

fix(cli-launcher): detect mise/nvm on server.js not found error (#492)
  - Show targeted fix instructions based on which Node manager is in use
  - mise users: told to use npx or mise exec
  - nvm users: reminded to nvm use --lts before reinstalling

docs(issues): add pnpm bindings workaround comment (#520)
docs(issues): note OpenCode/Lobehub icons coming in v3.0.0 (#529)
2026-03-22 11:41:04 -03:00
diegosouzapw
43046ee649 fix(3.0.0-rc/batch1): resolve issues #521, #522, #525, #532, #489
fix(login): redirect to /dashboard/onboarding when API returns needsSetup:true (#521)
  - Handle the case where user skips password setup and lands on login
  - Instead of showing a cryptic error, redirect to onboarding flow

fix(api-manager): replace useless 'copy masked key' button with lock tooltip (#522)
  - Copying a masked key (sk-proj123****abcd) is misleading and useless
  - Show a lock icon on hover explaining key is only available at creation time
  - Add i18n key 'keyOnlyAvailableAtCreation'

fix(opencode-go): use zen/v1 for API key validation, not zen/go/v1 (#532)
  - Added testKeyBaseUrl field to RegistryEntry interface
  - opencode-go: testKeyBaseUrl → zen/v1 (same key authenticates both tiers)
  - validation.ts: resolveBaseUrl for key testing now prefers testKeyBaseUrl

fix(antigravity): return structured 422 error when projectId is missing (#489)
  - Instead of throwing (crash), executor returns an OpenAI-format error JSON
  - Client receives message with instruction to reconnect OAuth
  - Prevents opaque 500 errors in the proxy logs

chore: close #525 (OmniRoute = 9router — same project, different name)
docs: add Docker password reset comment on #513 with INITIAL_PASSWORD workaround
2026-03-22 11:31:34 -03:00
Diego Rodrigues de Sa e Souza
a15fda0c08 Merge pull request #534 from diegosouzapw/release/v2.9.5
chore(release): v2.9.5 — OpenCode providers, embedding fix, CLI masked key fix
v2.9.5
2026-03-22 10:32:33 -03:00
diegosouzapw
e5988764ce chore(release): v2.9.5 — OpenCode providers, embedding credentials fix, CLI masked key fix, CACHE_TAG_PATTERN fix
- feat(providers): add OpenCode Zen and Go providers with multi-format executor (PR #530 by @kang-heewon)
- fix(embeddings): use provider node ID for custom embedding provider credential lookup (PR #528 by @jacob2826)
- fix(cli-tools): resolve real API key from DB (keyId) before writing to CLI config files (#523, #526)
- fix(combo): update CACHE_TAG_PATTERN to match literal \\n prefix/suffix around omniModel tag (#531)
- chore: bump version to 2.9.5 in package.json + docs/openapi.yaml
- docs: update CHANGELOG.md with v2.9.5 release notes
2026-03-22 10:30:04 -03:00
diegosouzapw
9c9d9b5a8d feat(providers): add OpenCode Zen and Go providers (#530) 2026-03-22 10:25:15 -03:00
kang-heewon
44dc564d85 chore: remove GHCR workflow from upstream PR 2026-03-22 10:24:50 -03:00
kang-heewon
83e367afab ci: add GHCR publish workflow for fork deployments 2026-03-22 10:24:50 -03:00
kang-heewon
8b7e7c2669 test(providers): improve OpencodeExecutor tests to avoid internal state coupling 2026-03-22 10:24:50 -03:00
kang-heewon
53474021b7 test(providers): add unit tests for OpencodeExecutor 2026-03-22 10:24:50 -03:00
kang-heewon
da1ed1b5b2 feat(providers): register opencode-zen and opencode-go in provider registry 2026-03-22 10:24:50 -03:00
kang-heewon
e08d661600 feat(providers): register opencode executors and add UI metadata
- Register OpencodeExecutor for 'opencode-zen' and 'opencode-go' in executors map
- Add OpencodeExecutor export in index.ts
- Add UI metadata for both providers in APIKEY_PROVIDERS:
  - OpenCode Zen: https://opencode.ai/zen
  - OpenCode Go: https://opencode.ai/zen/go
- Both use 'opencode' icon with #6366f1 color
2026-03-22 10:24:50 -03:00
kang-heewon
1aa1bc7a26 feat(providers): add OpencodeExecutor for opencode-zen/go multi-format routing 2026-03-22 10:23:32 -03:00
Diego Rodrigues de Sa e Souza
47634e942e Merge pull request #533 from diegosouzapw/fix/issues-521-523-526-531
fix: resolve masked key in CLI config saves + CACHE_TAG_PATTERN \n handling (#523, #526, #531)
2026-03-22 10:23:19 -03:00
Diego Rodrigues de Sa e Souza
15466cbf1a Merge pull request #528 from jacob2826/codex/fix-embedding-compatible-provider-credentials
fix: use provider node credentials for custom embedding providers
2026-03-22 10:23:16 -03:00
diegosouzapw
2a749db427 fix: resolve masked key bug in CLI config saves, fix CACHE_TAG_PATTERN for \n prefix (#523, #526, #531)
fix(cli-tools): save real API key to CLI config files instead of masked string (#523, #526)
  - claude-settings/route.ts: accept keyId, look up real key from DB (getApiKeyById)
  - cline-settings/route.ts: same keyId resolution pattern
  - openclaw-settings/route.ts: same keyId resolution pattern
  - ClaudeToolCard.tsx: store key.id as selected value, send keyId in POST body
  The /api/keys endpoint returns masked strings (first8+****+last4) which were being
  written verbatim to ~/.claude/settings.json and similar config files, causing auth
  failures on CLI tool launch.

fix(combo): update CACHE_TAG_PATTERN to strip surrounding \\n sequences (#531)
  - comboAgentMiddleware.ts: non-global regex now matches literal \\n (backslash-n)
    and actual newline U+000A that combo.ts injects around the <omniModel> tag.
2026-03-22 09:49:03 -03:00
jacob2826
ecccce86e4 fix: use provider node credentials for embeddings 2026-03-22 16:22:58 +08:00
Diego Rodrigues de Sa e Souza
bf3f64bea4 Merge pull request #519 from diegosouzapw/release/2.9.4
chore(release): v2.9.4 — bug fixes (#491, #515, #517)
v2.9.4
2026-03-21 17:40:23 -03:00
diegosouzapw
2f2d6b8535 chore(release): v2.9.4 — bug fixes (#491, #515, #517)
- fix(translator): preserve prompt_cache_key in Responses API translation (#517)
- fix(combo): escape \n in tagContent for valid JSON injection (#515)
- fix(usage): sync expired token status back to DB on live auth failure (#491)
- chore: bump version to 2.9.4 in package.json + docs/openapi.yaml
- docs: update CHANGELOG.md with v2.9.4 release notes
2026-03-21 17:37:51 -03:00
Diego Rodrigues de Sa e Souza
d68c884649 Merge pull request #518 from diegosouzapw/fix/issue-517-515-prompt-cache-key-tagcontent
fix: preserve prompt_cache_key in Responses API, escape \n in tagContent (#517, #515)
2026-03-21 17:32:24 -03:00
diegosouzapw
8b556de03b fix: preserve prompt_cache_key in Responses API translation, escape \n in tagContent (#517, #515)
fix(translator): preserve prompt_cache_key when translating Responses API requests
  (#517) — prompt_cache_key is an account-affinity signal used by Codex for
  prompt cache routing. Deleting it from the translated request prevented full
  cache effectiveness. Removed delete from openai-responses.ts and
  responsesApiHelper.ts cleanup blocks.

fix(combo): escape \n in tagContent so injected JSON string is valid (#515)
  — omniModel tag content used template literal newlines (U+000A) which produce
  unescaped newline chars inside a JSON string value. Replaced with literal \n
  escape sequences for valid JSON injection in streaming SSE content chunks.
2026-03-21 17:09:13 -03:00
Diego Rodrigues de Sa e Souza
7229af53c3 Merge pull request #516 from diegosouzapw/release/2.9.3
feat(providers): 5 new free AI providers — v2.9.3
v2.9.3
2026-03-21 16:55:29 -03:00
diegosouzapw
81b3034c2f feat(providers/logos): add logos for 5 new free providers
- public/providers/longcat.png — pink cat icon (generated)
- public/providers/pollinations.png — pixel bee icon (generated)
- public/providers/aimlapi.png — indigo neural network icon (generated)
- public/providers/cloudflare-ai.svg — Cloudflare official SVG (simpleicons.org)
- public/providers/scaleway.svg — Scaleway official SVG (simpleicons.org)

Icons serve at /providers/{id}.png (PNG fallback to SVG)
2026-03-21 16:47:49 -03:00
diegosouzapw
f0419396b5 chore(release): bump version to 2.9.3, update CHANGELOG
- Version bumped from 2.9.2 → 2.9.3 in package.json + docs/openapi.yaml
- CHANGELOG.md updated with full release notes for 2.9.3
  (5 new free providers, 2 metadata updates, 2 custom executors, docs)
2026-03-21 15:44:35 -03:00
diegosouzapw
6b9c2754e8 feat(providers): add LongCat AI, Pollinations, Cloudflare AI, Scaleway, AI/ML API
New free providers:
- LongCat AI (lc/): 50M tokens/day free during public beta
- Pollinations AI (pol/): no API key needed, GPT-5/Claude/DeepSeek/Llama free
- Cloudflare Workers AI (cf/): 10K Neurons/day, ~150 LLM responses, Whisper free
- Scaleway AI (scw/): 1M free tokens for new accounts (EU/GDPR, Paris)
- AI/ML API (aiml/): $0.025/day credits, 200+ models via single endpoint

Provider metadata updates:
- Together AI: hasFree=true + 3 permanently free model IDs (Llama 70B, Vision, DeepSeek)
- Gemini: hasFree=true + freeNote (1,500 req/day free, no credit card)
- NVIDIA NIM: already had hasFree=true, confirmed correct

New executors:
- open-sse/executors/pollinations.ts: optional auth (no key support)
- open-sse/executors/cloudflare-ai.ts: dynamic URL with accountId credential

Documentation:
- README.md: 11-provider Ultimate Free Stack, 4 new pricing table rows
- README.md: LongCat/Pollinations/Cloudflare AI/Scaleway provider detail sections
- docs/i18n/pt-BR/README.md: updated pricing table + 4 new free provider sections
- docs/i18n/cs/README.md: combo stack updated

Tests: 821/821 pass (no regressions)
2026-03-21 15:40:05 -03:00
diegosouzapw
8edb131f8b docs: add npm downloads and Docker Hub pulls badges to README 2026-03-21 14:48:48 -03:00
Diego Rodrigues de Sa e Souza
d6f6520a79 Merge pull request #514 from diegosouzapw/release/v2.9.2
chore(release): v2.9.2 — Transcription Content-Type fix, Deepgram language detection, TTS error display
v2.9.2
2026-03-21 14:03:33 -03:00
diegosouzapw
cc2bb4d719 chore: update generate-release workflow to two-phase PR-first flow
Phase 1: bump, docs, i18n, commit, push, open PR → STOP for user confirmation
Phase 2 (post-merge): tag, GitHub release, Docker Hub, deploy both VPS
2026-03-21 13:58:08 -03:00
diegosouzapw
3859f1c9ae chore(release): v2.9.2 — transcription Content-Type fix, Deepgram language detection, TTS error display
- fix(transcription): resolveAudioContentType() maps video/mp4 → audio/mp4 for Deepgram/HuggingFace
- fix(transcription): detect_language=true + punctuate=true for Deepgram auto-detection
- fix(tts): upstreamErrorResponse() correctly extracts string from nested error objects
- docs: README transcription/TTS rows updated with provider counts and capabilities
- i18n: sync 29/30 language README files with updated feature descriptions
- chore: bump version 2.9.1 → 2.9.2
2026-03-21 13:54:22 -03:00
diegosouzapw
5f8d774e19 fix: [object Object] error display in TTS/transcription upstream errors
upstreamErrorResponse() now guards against parsed.error being an
object (e.g. ElevenLabs { error: { message, status_code } }) instead
of blindly using it as the error message string.
Both audioSpeech.ts and audioTranscription.ts fixed.
2026-03-21 10:47:55 -03:00
diegosouzapw
538a3e855c fix: transcription Content-Type + language detection for Deepgram/HuggingFace
- Add resolveAudioContentType() to map video/* MIME to audio/* (fixes .mp4 uploads returning 'no speech detected')
- Add detect_language=true for Deepgram auto-language detection (fixes non-English audio)
- Add punctuate=true for better output quality
- Forward language form param to Deepgram when provided
- Apply same Content-Type fix to HuggingFace handler
2026-03-21 10:38:57 -03:00
diegosouzapw
03f2ef1e2b fix: omniModel SSE tag data loss + v2.9.1 release (#511) v2.9.1 2026-03-21 08:55:28 -03:00
Diego Rodrigues de Sa e Souza
237d0746cf Merge pull request #512 from zhangqiang8vip/feat/zws-v6
feat: per-protocol model compatibility, HMR leak fixes, and dev performance (V2-V5)
2026-03-21 08:53:54 -03:00
zhang-qiang
33b6c58087 fix(compat): store explicit false for per-protocol normalizeToolCallId
The truthy check treated false as falsy and deleted the property, preventing users from explicitly disabling normalization for a specific protocol when the top-level flag was true. Now stores both true and false values, consistent with preserveOpenAIDeveloperRole handling.

Made-with: Cursor
2026-03-21 16:38:46 +08:00
zhang-qiang
e96b023d04 fix(ci): reword comment in default.ts to avoid t11 any-budget false positive
The word 'any' in a JSDoc comment was matched by the regex-based t11 checker. Reworded to 'prefixes' to eliminate the false positive.

Made-with: Cursor
2026-03-21 16:33:44 +08:00
zhang-qiang
7ac1d4621b Merge remote-tracking branch 'upstream/main' into feat/zws-v6 2026-03-21 16:32:57 +08:00
zhang-qiang
a2d7cbe8fe feat(compat): per-protocol model compatibility config (V5)
Add per-protocol compatibility options (compatByProtocol) allowing users to configure normalizeToolCallId and preserveOpenAIDeveloperRole per client request protocol (OpenAI Chat, Responses API, Anthropic Messages) instead of globally. Includes frontend Map lookup optimization, type safety improvements, and client-safe constant extraction.

Made-with: Cursor
2026-03-21 15:23:42 +08:00