Before this fix, geminiToClaudeResponse() called content_block_start +
content_block_stop on EVERY streaming chunk. Claude Code interprets each
content_block as a separate text element and renders them on separate
lines, making responses unreadable.
Fix: introduce state.openTextBlockIdx to track an open text block across
chunks. The block is opened on the first text chunk and only closed when:
- switching to a different block type (thinking, tool_use)
- the stream finishes (at finishReason)
All other block types (thinking, tool_use) are still opened+closed per
chunk as before since they are naturally atomic events.
Also: add 'Download opencode.json' button to the Agents dashboard.
The button appears when opencode is detected as installed and generates
a ready-to-use opencode.json config with the OmniRoute provider,
base URL and all models fetched from /v1/models.
fix(test): security-fase01.test.mjs imports inputSanitizer.js → .ts
- The file is TypeScript-only (no compiled .js). Node was failing with
ERR_MODULE_NOT_FOUND in CI because the import path pointed to a
non-existent .js file.
fix(acp): add validateBody(jsonObjectSchema) to POST /api/acp/agents
- Satisfies check:route-validation:t06 lint rule that requires all
routes using request.json() to go through validateBody().
- Uses jsonObjectSchema (passthrough) since body shape varies between
the 'refresh' action and the custom agent creation payload.
- Manual field validation below remains unchanged.
- All 139 routes now pass the route-validation lint check.
fix(deploy-vps): add continue-on-error on SSH step + command_timeout
- SSH connection failures (host unreachable / secrets not set) no
longer mark the workflow run as failed.
- The DEPLOY_ENABLED guard still prevents the job from running when
the variable is not set to 'true'.
- New CLI sidebar section: Tools + Agents
- Move Media to Debug section
- Move Health + Logs to System section
- Move CLI Fingerprint card from Settings > Security to Agents page
- Add cliToolsShort i18n key to all 30 languages
- Add Dashboard > Debug > Agents page: grid of 14 built-in CLI agents
with installation status, version detection, protocol badges
- Add custom agent support: users can register any CLI tool via form
- Expand registry from 5 to 14 built-in agents (aider, opencode, cline,
qwen-code, forge, amazon-q, interpreter, cursor-cli, warp)
- Add 60-second detection cache to avoid repeated execSync calls
- API: GET lists all agents, POST adds custom/refreshes, DELETE removes
- Settings schema: add customAgents array field
- Fix missing themeCoral in settings namespace for all 30 languages
- Add agents sidebar key in all 30 languages
- Add agents page i18n namespace (en + pt-BR)
- Add model playground page to dashboard (provider/model/endpoint selectors, Monaco editor, streaming, abort)
- Add CLI fingerprint matching (per-provider header/body ordering to match native CLI binaries)
- Add ACP module (CLI agent discovery, process spawner, session manager, API endpoint)
- Add playground to sidebar debug section with i18n support
- Close#192 and #200 as stale (v1.8.1, no repro info)
- Fix inverted Claude OAuth utilization (remaining, not used)
- Add hasUtilization() guard to prevent false exhaustion from empty responses
- Centralize anthropic-version into CLAUDE_CONFIG.apiVersion
- Add parseDate() for safe date validation in quota cache
- Batch background refresh with MAX_CONCURRENT_REFRESHES=5
- Move setModelUnavailable to after all accounts exhausted, not first 429
- Extract safePercentage() to shared utils (dedup)
- Use isRecord() type guard in usage API route
- Exclude binary files from Tailwind v4 source scanning
- Move setModelUnavailable from per-account loop to all-accounts-exhausted path
- Clear model unavailability on successful fallback
- Add in-memory quota cache with background refresh (5min active, 20min exhausted)
- Integrate quota cache in account selection to skip exhausted accounts
- Mark accounts as exhausted from 429 when no cached quota data exists
- Populate quota cache from dashboard usage endpoint
- Created httpTransport.ts with singleton MCP server and WebStandard
Streamable HTTP transport running inside Next.js process
- Added /api/mcp/sse route (GET+POST) for SSE transport
- Added /api/mcp/stream route (GET+POST+DELETE) for Streamable HTTP
- Added mcpTransport enum to settingsSchemas (stdio|sse|streamable-http)
- Updated /api/mcp/status to report HTTP transport state
- Added TransportSelector UI with mode buttons and connection URL display
- Routes guard against disabled MCP or wrong transport mode
- Created settingsSchemas.ts with updateSettingsSchema to avoid webpack
tree-shaking the schema from the 908-line schemas.ts barrel file
- Updated settings/route.ts import to use new dedicated file
- Fixed focusRingColor lint error in ServiceToggle
- Added mcpEnabled/a2aEnabled boolean fields to updateSettingsSchema
- Rewrote ServiceToggle as clickable on/off switch with status indicator
- Toggle persists state via PATCH /api/settings
- Both services default to disabled (OFF)
- Renamed sidebar 'Endpoint' to 'Endpoints', removed standalone MCP/A2A entries
- Created tabbed layout with SegmentedControl: Endpoint Proxy | MCP | A2A | API Endpoints
- Added inline ServiceToggle (online/offline status) for MCP and A2A tabs
- Created ApiEndpointsTab placeholder with Coming Soon badge
- Updated i18n in en.json and pt.json with new endpoints namespace
Extracted validateBody, isValidationFailure, and loginSchema from the
935-line schemas.ts barrel file into a dedicated helpers.ts module.
Updated 70 API route files to import directly from helpers.ts.
Root cause: webpack on certain environments fails to resolve exports
from the bottom of large barrel files (schemas.ts), causing
'(0, O.Jb) is not a function' errors in production builds.
Fix: Split validation helpers into a small dedicated module (helpers.ts)
so webpack can correctly resolve all exports regardless of file size.
- TypeScript compiles with 0 errors
- All API routes updated to import from helpers.ts
- schemas.ts re-exports from helpers.ts for backward compatibility
- Fix createQuotaObject: utilization is percentage USED, not remaining
- Add optional chaining to window access in createQuotaObject
- Use typeof object guards for five_hour/seven_day instead of !== undefined
- Use nullish coalescing for extra_usage
- Propagate remainingPercentage in parseQuotaData claude case
Code Quality Improvements:
- Export COLOR_THEMES from themeStore.ts for reuse (DRY)
- Add coral preset to color list (fixes default inconsistency)
- Sync local customThemeColor state reactively via Zustand subscribe
- Add hex color validation with visual feedback (red border + disabled button)
- Remove dead /themes route from Header.tsx (page doesn't exist)
- Add CSS color-mix() fallback for older browsers
- Add themeCoral i18n key to all 30 locale files
- syncAndVerify now returns cloudUrl in API response for frontend to use
- EndpointPageClient uses dynamic cloudBaseUrl state instead of relying on env var
- Falls back gracefully when NEXT_PUBLIC_CLOUD_URL is not set (Docker deployments)
- Fixed setInterval in accountFallback.ts global scope for Cloudflare Workers compat
- Modified OAuth exchange route to use upsert logic at all 3 connection-save locations
- Before creating a new connection, checks for existing connections with same provider+email+authType
- If match found, calls updateProviderConnection() to refresh tokens instead of creating duplicate
- Falls back to createProviderConnection() for genuinely new connections
- Fixes: re-auth button creating new account entries instead of refreshing existing ones
- 24 unit tests for parseModelFromRegistry, getAllModelsFromRegistry, buildAuthHeaders
- Integration tests for video/music registries
- Media Playground dashboard page (Image/Video/Music tabs with model selector)
- Sidebar navigation entry for Media page
- i18n translations (EN + PT-BR)
- Fix Record<string, any> → Record<string, unknown> in registryUtils.ts
- Update /resolve-issues workflow to wait for user validation before commit/release
Approved — adds multi-modal support with new TTS/STT/Image/Video/Music providers. Follow-up commits will add frontend pages, unit tests, and configurable local provider URLs.
- Add path traversal validation for ElevenLabs voice_id and HuggingFace
model_id URL concatenation (prevents SSRF via ../ sequences)
- Add saveCallLog usage tracking to video and music handlers for
consistent analytics with imageGeneration.ts
- Extract shared upstreamErrorResponse() and audioStreamResponse()
helpers to reduce error handling duplication in audioSpeech.ts
- Extract shared upstreamErrorResponse() and isValidPathSegment()
helpers in audioTranscription.ts
- Add explicit format: "openai" to qwen TTS and STT provider entries
- Remove unused modelId parameter from handleCoquiSpeech and
handleTortoiseSpeech
- Filter cloud video/music providers by active status in models route
(local providers with authType: "none" always listed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 6 TTS providers (Nvidia NIM, ElevenLabs, HuggingFace, Coqui, Tortoise,
Qwen3), 3 STT providers (Nvidia NIM, HuggingFace, Qwen3), 2 local image
providers (SD WebUI, ComfyUI), and two new modalities — Text-to-Video
(/v1/videos/generations) and Text-to-Music (/v1/music/generations).
Key design decisions:
- Format-based unified providers: local providers grouped by API format
(comfyui, sdwebui, coqui, tortoise, openai-compatible) with configurable
base URLs and expandable model lists
- Cloud providers kept separate (unique auth and API shapes)
- Local providers use authType: "none" — credential checks bypassed at both
route and handler level
- Shared ComfyUI client (comfyuiClient.ts) reused across image/video/music
- Shared registry utilities (registryUtils.ts) for model parsing and listing
- Qwen3 TTS/ASR use format: "openai" — no custom handler needed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tailwind CSS v4 auto-detection failed to scan Next.js route group
directories with parentheses (e.g. '(dashboard)'), causing responsive
grid utilities to be purged from production CSS. Added explicit @source
directives in globals.css to fix the content scanning.
CSS output: 10KB (broken) → 110KB (correct), 12 media queries restored.
- Add collapsible '16 Real Pain Points' section to all 30 READMEs
- Fix 5 files bypassing dataPaths.ts with hardcoded os.homedir() (closes#156)
- Add per-provider User-Agent env var overrides in base executor (closes#155)
- Sync .env and .env.example with 9 provider UA defaults
- Update CHANGELOG.md for v1.7.0