Backend fixes:
- Fix totalTokens defaulting to 0 when API omits totalTokenCount (now computes prompt+completion)
- Fix streaming metadata extraction: unwrap response wrapper in Anthropic/Gemini handlers
- Fix Zod schemas: handle SQL SUM(null) with nullable().transform()
- Add is_estimated column migration to token_usage table
Frontend redesign:
- Rewrite Usage page with area charts (nivo/line), horizontal bar model ranking
- StatCard: add trend indicators (% vs previous period) and inline SVG sparklines
- Premium color palette, prompt/completion ratio bar, top models mini-list
- Live indicator with 15s auto-refresh
Design system migration:
- Standardize all components on Gemini Nexus tokens (rounded-xl, border-white/[0.06])
- Refine UI components, proxy tabs, cloud account list, provider groups
- Emit tool call id+name in first SSE delta and arguments in subsequent deltas
- Split large tool arguments into 1000-char chunks to prevent framing issues
- Set FastifyAdapter bodyLimit to 10MB to handle large payloads
- Add TDD tests for tool call streaming verification
- Add cacheHitRate to ProxyMetricsService, handler, and router schema
- Fix StatCard to support string values and purple accent
- Fix duplicate tabs keys in i18n translations (EN/ZH/RU)
- Add missing cacheStatus translations across all languages
- Change author from Draculabo to evandrodevbr in package.json
- Update GitHub publisher config in forge.config.ts (owner/repo/iconUrl)
- Add favicon link in index.html pointing to src/assets/icon.png
- Ensure all app icon references use images/icon.* consistently
- Create scripts/build-windows.js that extracts wix314-binaries.zip to tools/wix314/
- Adds extracted dir to PATH so electron-wix-msi can find candle.exe/light.exe
- Adds npm script 'make:win' for one-command Windows installer build
The initial role chunk (role:'assistant', content:'') added in a3eabc2
was causing the OpenCode TUI to receive an empty first delta and
discard all subsequent content, showing only the completion time with
no text output.
Restored to the exact streaming behavior from e524a340 that worked:
- Remove the pre-emptive initial chunk entirely
- Move hasEmittedChunk=true back inside pushChunk (original position)
- Use reasoning_content delta field for thought parts instead of
wrapping in <think> tags (which corrupts plain text responses)
- Remove streamOptions/include_usage/lastUsageMetadata tracking
(not present in the working version)
- Remove isThinking state machine (was adding </think> noise to output)
Kept from the spec compliance work (a3eabc2):
- toolCallIndex counter for correct finish_reason:'tool_calls' mapping
- Comment explaining why we override Gemini's STOP finish reason
Route fixes:
- Add POST /v1/messages/chat/completions alias so OpenCode clients
misconfigured with baseURL ending in /v1/messages no longer get 404
Session affinity:
- Extract x-session-affinity HTTP header (sent by OpenCode) and use it
as the session key for token stickiness, falling back to body-level
session_id fields if the header is absent
Tool calling (streaming):
- finish_reason is now 'tool_calls' when function calls were emitted in
the stream (Gemini always sends STOP, so we check toolCallIndex > 0)
- createSyntheticOpenAIStream (stream fallback path) now emits all
tool_call deltas before the finish chunk instead of silently dropping
them when content is null
Tool calling (non-streaming):
- content is now always null when tool_calls are present, satisfying
strict clients that reject non-null content alongside tool_calls
- system_fingerprint field added to OpenAIChatResponse interface and
response builder for OpenAI spec compliance
Usage accounting:
- thoughtsTokenCount is now included in completion_tokens and
total_tokens for the streaming usage chunk, fixing undercount for
thinking/reasoning model runs
- GoogleAPIService: try loadCodeAssist first for AI credits since
fetchCredits returns 404 for many accounts; keep fetchCredits as
fallback, removing the spurious warn on every poll cycle
- CloudAccountRepo: auto-activate the most-recently-used account when
no account has is_active=1; downgrade noisy [DEBUG] log from info
to debug level
- StatusBar: increase process-status refetch interval from 10s to 30s
to reduce redundant IPC calls and log noise
- Add dedicated API logger (api-logger.ts) with winston daily rotation
- Create Fastify plugin (api-logging.plugin.ts) to intercept all API requests/responses
- Log request start, body, response, errors, and summary with precise timestamps
- Auto-mask sensitive data using existing sanitizeObject utility
- Register API logging plugin in NestJS bootstrap (server/main.ts)
- Add npm run dev script with cross-env for automatic DEBUG on Windows
- Install cross-env as devDependency for cross-platform env vars