Commit Graph
62 Commits
Author SHA1 Message Date
Louis Phạm bc3be0cb28 fix(antigravity): scope cached thought signatures to the model family 2026-09-18 17:09:36 +07:00
Christian Gennari 092c84eac9 fix(commandcode): retry on transient stream error and avoid fake stop chunks 2026-09-18 17:09:24 +07:00
Qisthi Ramadhani c49efdf528 fix(kiro): preserve underscores in tool names and restore sanitized names in responses
Do not collapse consecutive underscores in uniqueName so mcp__server__tool is sent intact to Kiro, attach reverse map on request translation, and restore client tool names in responses.
2026-09-17 18:14:59 +07:00
Manan Santoki f4f06f290c fix(translator): keep tool-result images, restore Kiro tool names, preserve thinking display
Forward images inside tool_result to OpenAI and Kiro upstreams via following user messages, restore original client tool names on Kiro responses via _toolNameMap, and preserve thinking display settings across translations.
2026-09-17 18:12:05 +07:00
LLL 248d7da01c revert(qoder): drop the Responses usage plumbing from shared code
The merged Qoder work also rewrote shared translator/handler code so that
/v1/responses clients got token usage on response.completed. That changed
behaviour for every provider, not just Qoder: proxies saw input tokens
rise by the 2000-token context buffer, and the plain token mapping was
replaced by one that always adds input_tokens_details.

A probe confirms the Qoder benefit does not depend on those edits: the
executor's coalescer already emits one include_usage-style finish chunk, so
a Claude client receives input_tokens and cache_read_input_tokens with
every shared file at its original state. Only the Responses path relies on
the shared translator, and that path has no Qoder-owned seam to put it in.

Reverts the shared files to their pre-PR state and drops the Responses
usage test. The Cline envelope unwrap in nonStreamingHandler.js, which
landed after the PR in the same file, is kept.
2026-09-10 23:13:06 +07:00
LLL 1f10f9e5c4 fix(qoder): report usage to all clients and stop inlining large attachments
- Coalesce Qoder's empty finish-in-delta frame with the later choices:[] usage
  frame so OpenAI and Claude clients receive prompt_tokens, completion_tokens
  and cache-hit tokens (the dashboard already saw them)
- Upload inlined images through /api/v2/image/upload like qodercli, and stub
  oversized non-image files instead of stuffing 30MB+ data URIs into
  agent_chat_generation
- Emit response.completed -> response.usage for chat-native upstreams so
  /v1/responses clients (Codex CLI, sub2api) no longer log 0/0/0
- Keep Claude message_delta.usage working when usage arrives without choices[0]
- Escalate to the smallest advertised Qoder context tier (200K/400K/1M) when
  the estimated prompt no longer fits max_input_tokens
- Pass apiKey for PAT connections and list hidden enable:false catalog keys
  from /v1/models
2026-09-10 22:08:19 +07:00
Sina Sadeghi e74db4d0a6 feat(opencode-go): add muse-spark-1.3-contributor and fix parallel tool calls on Responses paths (#3819)
- Add muse-spark-1.3-contributor as responses-only model on OpenCode Go with dedicated executor
- Key Responses→chat streaming tool calls by item_id to prevent parallel tool calls merging into index 0
- Standardize tool coercions and call_id clamping in Responses API translation
2026-09-05 21:49:53 +07:00
decoluaandClaude Code c08efdbe2b feat(gemini): persist and replay thoughtSignature with session namespace
- Add open-sse/services/thoughtSignatureStore.js managing LRU Map (2k) + SQLite kv table
- Store thoughtSignature with sessionId namespace and toolCallId fallback
- Replay cached signature by sessionId:tool_call_id to prevent multi-process collisions
- Normalize Antigravity sessionId to numeric int64 format

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 18:20:04 +07:00
chisewaguri 10a923da11 fix(responses): don't close message on empty tool_calls array
Some providers (e.g. codebuddy/cbcn) attach an empty tool_calls array to every streaming chunk. An empty array is truthy in JS, so the guard 'if (delta.tool_calls)' closed the message on the first content token and emitted response.output_text.done early, dropping the remaining deltas. Guard on a non-empty array; finish_reason still closes the message and real tool calls still close it before emitting function_call items.

fixes #3234
2026-08-13 11:40:45 +07:00
nguyenha935 b44bb09f72 fix(kiro): report real output tokens and stop discarding usable turns 2026-08-13 11:33:41 +07:00
nguyenha935 d06e0d26c6 fix(translator): preserve Responses Lite tools across Chat providers
Codex Responses Lite clients routed to a chat-native OpenAI-compatible
provider lost tool use in three places: non-streaming Chat responses
leaked the raw chat.completion envelope instead of Responses output
items, internal reasoning continuity fields leaked into the outbound
Chat body causing some upstreams to reject the request, and the
Responses to Chat request translator ignored additional_tools,
custom_tool_call, and custom_tool_call_output items entirely.

Also fixes apiType (chat vs responses) for openai-compatible nodes
being resolved from the immutable provider ID instead of the stored
node config, so editing a node's API Type had no runtime effect.
2026-08-05 13:27:25 +07:00
hodtienandCursor 54e3245ace feat(usage): track cached tokens + correct input/output/cache cost (#2209)
Normalize every provider to one cache-inclusive convention via
canonicalizeUsage() before persist, and price cached + cache_creation as
subsets of prompt_tokens in calculateCostFromTokens() to stop
double-counting. usageRepo now delegates cost math to a single source.
Surface Cached tokens/cost across dashboard (overview, tokens, cost,
details). Merge Claude message_start cache with message_delta output so
cache counts survive. Compatible LLM nodes now allow multiple API-key
connections (key pool).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 15:18:27 +07:00
Sutarto Jordan ChrisfivoandCursor 8f81f17b99 fix(antigravity): preserve Claude tool delta index (#2223)
Gemini response translation wrote OpenAI-shaped bookkeeping into the
shared state.toolCalls map, which the downstream openai-to-claude
translator uses for Claude block metadata. That pre-population skipped
blockIndex creation, so Anthropic input_json_delta events lost index.

Track Gemini function calls via state.geminiToolCallCount instead,
leaving state.toolCalls clean for the Claude translator.

Closes #2218

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 09:36:43 +07:00
decolua 526235872a Fix OpenCode Go GLM 2026-06-29 15:00:03 +07:00
706e6513c9 feat(kiro): headless API-key auth + direct Claude/Kiro route
Adds long-lived API-key (ksk_) authentication for Kiro/AWS CodeWhisperer
and a direct claude:kiro / kiro:claude translation route that avoids the
lossy OpenAI two-hop pivot.

- translator: claude-to-kiro request + kiro-to-claude response translators,
  registered on the exact source:target pair (direct route ahead of the
  OpenAI pivot in index.js). claude-to-kiro uses shared schema constants
  (ROLE/CLAUDE_BLOCK/DEFAULT_IMAGE_MIME) per app convention.
- auth: POST /api/oauth/kiro/api-key imports + validates a key via
  ListAvailableProfiles, persists authMethod="api_key" (no refresh token).
- executor: send tokentype: API_KEY header and try *.amazonaws.com hosts
  first for api-key creds; OAuth keeps kiro.dev first.
- fix: never inject the default placeholder profileArn for api-key auth
  (CodeWhisperer 403s an ARN not owned by the key's account).
- ui: API Key method in the Kiro connect modal; surface api-key accounts
  on the Quota Tracker and provider count.
- stream: env-overridable TTFT vs stall timeouts + Kiro keepalive frame.
- tests: claude-kiro-direct + kiro-profile-arn (11 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 10:01:30 +07:00
decolua b282f05549 Refactor 2026-06-15 18:18:04 +07:00
decoluaandCursor d3f61aac2f refactor(open-sse): translator DRY + schema enums, bug fixes, dead code cleanup
- Bug B1-B7: media UI m.kind||m.type, serviceKinds, gemini mediaPriority, schema kind, models/info lookup by kind
- Dead code D1-D6: safeParseJSON, drop PROVIDER_ENDPOINTS, orphan fetcher, GITHUB_CONFIG derive, getProviderConfig internal, legacy kiro file
- Translator concerns: toOpenAIUsage, toOpenAIFinish (gemini/kiro/ollama + fix kiro tool finish), thinking effort maps
- Reorg helpers/ → concerns/ (logic) + formats/ (per-format) + schema/ (pure enums: roles/blocks/finishReasons/defaults)
- Wire ~280 hardcoded role/block/finish/default literals to schema enums across 20+ files
- collapseTextParts + extractTextContent dedup
- Normalize translator fn names to openaiToXRequest / xToOpenAIResponse
- Golden tests lock behavior; 0 regression (byte-for-byte providers/alias, 26=26 known fails)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 18:49:38 +07:00
decoluaandCursor 633b66dcb6 refactor(translator): P4 concern #5 buildUsage — apply to kiro/ollama/commandcode
- Replace 3 inline {prompt,completion,total} usage objects with buildUsage()
- Preserves ?? vs total fallback semantics (commandcode)
- Golden tests pass, identical output

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 21:27:22 +07:00
decoluaandCursor 252bf56a9f refactor(translator): P4 concern #2 encodeDataUri — dedupe base64 data-uri building
- imageHelper.encodeDataUri(mime, base64) replaces 5 inline `data:${m};base64,${d}` templates
- Applied to gemini/claude/antigravity request + gemini response translators
- Golden tests pass, identical output

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 21:23:32 +07:00
decoluaandCursor 4cc667253a refactor(translator): P4 concern #6 finishReasonMap — switch-by-format, default common
- concerns/finishReasonMap.js: toOpenAIFinish/fromOpenAIFinish, switch special formats, default passthrough
- Replace 3 inline switch maps (claude→oai, oai→claude, commandcode→oai)
- Golden translator tests pass, behavior identical

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 21:20:22 +07:00
decoluaandCursor 6597b81e5e refactor(open-sse): add reasoningDelta helper, dedup thinking deltas (B4)
Centralize the reasoning_content delta shape (optional assistant role) used by
claude/gemini/kiro/codex/commandcode response translators. Keeps the cross-format
convention consistent for future translators. Output byte-for-byte identical;
golden + gate clean. Ollama left as-is (mutates existing delta object).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 18:21:46 +07:00
decoluaandCursor 997860aa1f refactor(open-sse): dedup fallback tool_call id helper (B3)
Add fallbackToolCallId() and apply to kiro/ollama/openai-responses response
translators (identical id shape). Leave commandcode (different order) and
request-side gemini/antigravity (random suffix) untouched. Golden + gate clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 18:12:40 +07:00
decoluaandCursor 39278e9613 refactor(open-sse): extract buildUsage helper, dedup token-details (B2)
Add helpers/usageHelper.js for conditional prompt/completion token details.
Apply to gemini/codex/claude response translators; keep each provider's token
math intact. No behavior change; golden + gate: no regression.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 17:18:15 +07:00
decoluaandCursor 17202f7111 refactor(open-sse): extract chunkBuilder, dedup chat.completion.chunk (B1)
Add helpers/chunkBuilder.js; apply to claude/gemini/kiro/ollama/commandcode/
openai-responses response translators. Caller supplies id/created/model so each
keeps exact id-generation + usage semantics. Extend golden response stream to
openai-responses (codex). No behavior change; gate: no regression.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 17:05:42 +07:00
Giang Truong VuandCursor d9b030011f fix(gemini-to-openai): route unsigned thought parts to reasoning_content
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 10:34:42 +07:00
9caea88528 fix(codex): harden streaming timeouts + Responses terminal events
Raise stall/connect timeouts to 60s (configurable per-provider), accept
codex response.done, and always emit a terminal response.failed + [DONE]
for Responses passthrough when a stream closes, stalls, or aborts before
a terminal event — preventing codex clients from hanging.

Co-authored-by: jonathanli12 <jonathanli12@users.noreply.github.com>
Co-authored-by: rifuki <rifuki@users.noreply.github.com>
Co-authored-by: nguyenha935 <nguyenha935@users.noreply.github.com>
Co-authored-by: trananhtung <trananhtung@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 16:07:43 +07:00
decolua a648a42bdb Fix codex 2026-05-26 11:35:39 +07:00
GodrezJr2andClaude Sonnet 4.6 96a9a2b36d fix: sanitize Read tool args to prevent retry loops from non-Anthropic models (#1144)
* fix: sanitize Read tool args to prevent retry loops from non-Anthropic models

* fix: sanitize invalid Read pages from tool args

Non-Anthropic models sometimes emit optional Read args like pages: "" for
non-PDF files, which Claude Code rejects before the tool runs. Drop invalid
pages values, keep valid PDF page ranges, and coerce numeric string bounds
before clamping limit/offset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 11:33:38 +07:00
Hamsa_MandJoJo 315dcaa37a fix: strip empty Read pages argument in OpenAI-to-Claude translator (#1354)
Some OpenAI-compatible providers emit optional string tool parameters
as empty strings (e.g. pages: "") instead of omitting them. Claude
Code rejects pages: "" as invalid, breaking the Read tool for
non-PDF files routed through 9router.

Add sanitizeToolArguments() that parses tool-call arguments and
removes known optional empty-string fields before emitting
input_json_delta back to Claude format. Currently handles the
Read tool pages field specifically.

Includes regression test.

Fixes #1278

Co-authored-by: JoJo <noreply@github.com>
2026-05-23 09:27:13 +07:00
decolua 4a575f21a2 https://github.com/decolua/9router/pull/1167
https://github.com/decolua/9router/pull/1166
2026-05-16 11:20:08 +07:00
decolua ad661c1286 feat: enhance CommandCode integration with improved message handling 2026-05-07 23:02:07 +07:00
decolua b72a443bd3 feat: add CommandCode provider support 2026-05-07 23:01:33 +07:00
decolua 875a1282ea Fix bug 2026-04-11 11:36:33 +07:00
decolua 1973fe5a83 fix(translator): correct thought signatures for AG, Gemini CLI, Vertex; fix missing Vertex response translator
- Add DEFAULT_THINKING_AG_SIGNATURE, DEFAULT_THINKING_GEMINI_CLI_SIGNATURE, DEFAULT_THINKING_VERTEX_SIGNATURE
- Rename DEFAULT_THINKING_GEMINI_SIGNATURE → DEFAULT_THINKING_AG_SIGNATURE for clarity
- Pass provider-specific signature into openaiToGeminiBase (AG vs Gemini CLI)
- Replace synthetic thoughtSignatures with Vertex-native signature in postProcessForVertex
- Register Vertex → OpenAI response translator (fixes empty Vertex streaming responses)

Made-with: Cursor
2026-04-05 00:38:36 +07:00
decolua 93b8668e9e Fix AG 2026-04-01 11:48:38 +07:00
Kwan96 ffa172c92d fix(claude-to-openai): emit closing </think> tag instead of empty reasoning_content (#454)
Replace empty reasoning_content with explicit </think> closing tag when exiting thinking block to properly signal end of reasoning section in streaming responses.
2026-03-31 09:21:11 +07:00
decolua 01787a3d5b Fix bug 2026-03-30 17:27:15 +07:00
kwanLeeFrmVi 054facb08b fix(gemini): preserve thoughtSignature via tool_call ID smuggling + fix ELOCKED mutex
- Encode thoughtSignature into tool_call.id using _TSIG_ delimiter and base64url
- Decode _TSIG_ on request to restore thoughtSignature for Gemini multi-turn thinking
- Track pendingThoughtSignature across parts for deferred signature attachment
- Add LocalMutex (2-layer locking) to prevent ELOCKED on concurrent DB access
- Increase lockfile retries from 5 to 15 for multi-process robustness
- Restore db.json seed on first run to prevent ENOENT on lockfile.lock
- Use process.env.BASE_URL fallback in models test route
- Remove gemini-3-flash-lite-preview from provider models

Co-authored-by: kwanLeeFrmVi <quanle96@outlook.com>
Closes #450

Made-with: Cursor
2026-03-30 16:57:28 +07:00
decolua e6299eef56 Fix Bug 2026-03-30 12:21:24 +07:00
decolua 11e6004fcb fix: correct finish_reason for tool calls in OpenAI Responses translator
Apply fix from PR #354 by @tannk4w to properly signal tool_calls finish_reason
when model emits tool calls, allowing OpenAI-compatible clients to continue with
tool result processing instead of stopping prematurely.

Refactored finish_reason logic into computeFinishReason() helper to eliminate
duplication and improve maintainability across flush and completion paths.

Co-authored-by: tannk4w <tannk@tmi-soft.vn>

Thanks to @tannk4w, @trungtq2799, @quanhavn, and @East-rayyy for the thorough
review and improvement suggestions on the original PR.

Made-with: Cursor
2026-03-28 14:45:07 +07:00
Anurag Saxena e3a7733a08 fix: strip functionCall/functionResponse id and synthetic thoughtSignature for Vertex AI (closes #388) (#414) 2026-03-27 10:46:47 +07:00
Liam 01e4a28f0a fix: normalize finish_reason to 'tool_calls' when tool calls are present (#379)
Some upstream providers (e.g. Antigravity) return non-standard finish_reason
values like 'other' instead of the OpenAI-standard 'tool_calls' when the
model invokes tools. This causes downstream consumers (e.g. OpenClaw) to
fail to execute tool calls, breaking agentic sub-agent workflows.

Changes:
- nonStreamingHandler: post-translation guard that normalizes finish_reason
  to 'tool_calls' when message.tool_calls is present
- sseToJsonHandler: accumulate tool_calls from streaming deltas in
  parseSSEToOpenAIResponse; extract function_call items from Responses API
  output in handleForcedSSEToJson
- openai-responses translator: use toolCallIndex to choose between
  'tool_calls' and 'stop' in flush and response.completed events

Tested: 7 scenarios (non-stream text, single/multiple tool calls, stream
text/tool calls, multi-turn tool conversation, tools present but unused)
2026-03-23 09:35:25 +07:00
decolua 83d94daa82 feat(ollama): Enhance Ollama support by adding new models, updating API format handling, and integrating translation functionality. 2026-03-12 15:24:10 +07:00
Xmllist 6437a1c55f refactor(claude-to-openai): simplify usage token calculation and final chunk assembly
Made-with: Cursor
2026-03-09 17:18:49 +07:00
decolua adf57aa0c9 Fixed Codex 2026-02-21 14:36:06 +07:00
apple-techieandCursor d7d5dc90bc fix: update Codex executor for gpt-5.3-codex support
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 18:12:38 +07:00
decolua d3c3a4ae0a Remove Docker publish workflow and update error handling in various modules
- Added handling for HTTP_STATUS.NOT_ACCEPTABLE in error types and messages.
- Enhanced the `prepareClaudeRequest` function to filter built-in tools for non-Anthropic providers and clean up empty tool arrays.
- Updated the `openaiToClaudeRequest` function to handle built-in tools more effectively and ensure proper tool conversion.
- Improved the `claudeToOpenAIResponse` function to skip processing for built-in server tool blocks.
- Refined error message handling in the `parseUpstreamError` function to ensure meaningful output.
- Adjusted command checks for tool installations across various settings routes to use `command -v` for better compatibility.
2026-02-10 19:18:40 +07:00
Blade 85b7a0b136 Feature/ai observability dashboard (#79)
* feat: add AI request details feature with latency tracking

Add comprehensive request history and debugging capability to the Usage dashboard:

**Storage Layer** (usageDb.js):
- Add saveRequestDetail() for storing full request/response details
- Implement FIFO queue with 1000-record limit in request-details.json
- Auto-sanitize sensitive headers (authorization, api-key, cookie, token)
- Add getRequestDetails() with pagination and filtering support
- Add getRequestDetailById() for single record lookup

**Pipeline Integration** (chatCore.js):
- Track request start time and calculate total latency
- Record TTFT (Time To First Token) and total latency for all requests
- Capture full request details (messages, model, parameters)
- Save response content for non-streaming, mark streaming responses
- Handle error cases with detailed error information
- Async non-blocking saves to avoid impacting request performance

**API Layer** (/api/usage/request-details):
- GET endpoint with pagination (page, pageSize: 1-100)
- Filter by provider, model, connectionId, status, date range
- Returns { details: [...], pagination: {...} } format

**UI Components**:
- Drawer.js: Right slide-out panel with backdrop blur and ESC close
- Pagination.js: Full pagination with page size selector (10/20/50)
- RequestDetailsTab.js: Complete table view with filters and detail drawer

**Dashboard Integration**:
- Add "Details" tab to Usage page (4th tab after Overview/Logger/Limits)
- Table columns: Timestamp, Model, Provider, Input Tokens, Output Tokens, Latency (TTFT/Total), Action
- Provider filter dropdown (9 providers supported)
- Date range filters (start/end datetime)
- Click "Detail" button to view full request/response JSON in slide-out drawer

**Features**:
- Real-time latency monitoring (TTFT & Total)
- Complete request/response inspection for debugging
- Filterable and searchable request history
- Responsive design with mobile-friendly filters
- Data security with automatic header sanitization
- Performance: async saves don't block request pipeline

**Files Created/Modified**:
- src/lib/usageDb.js (modified)
- open-sse/handlers/chatCore.js (modified)
- src/app/api/usage/request-details/route.js (new)
- src/shared/components/Drawer.js (new)
- src/shared/components/Pagination.js (new)
- src/app/(dashboard)/dashboard/usage/components/RequestDetailsTab.js (new)
- src/app/(dashboard)/dashboard/usage/page.js (modified)

Closes: AI Observability Dashboard feature

* feat: enhance request details with full config and streaming content capture

Improve Request Details feature to capture comprehensive request parameters
and actual streaming response content:

**Request Configuration Enhancement** (chatCore.js):
- Add extractRequestConfig() helper function to capture all request parameters
- Include temperature controls: temperature, top_p, top_k
- Include token limits: max_tokens, max_completion_tokens
- Include thinking/reasoning modes: thinking, reasoning, enable_thinking
- Include OpenAI parameters: presence_penalty, frequency_penalty, seed, stop,
  tools, tool_choice, response_format, n, logprobs, top_logprobs, logit_bias,
  user, parallel_tool_calls, prediction, store, metadata
- Apply to all request types: non-streaming, streaming, and error cases

**Streaming Content Capture** (chatCore.js & stream.js):
- Add onStreamComplete callback mechanism to stream processors
- Accumulate content from all formats: OpenAI, Claude, Gemini
- Track content from delta.content, delta.reasoning_content, delta.text,
  delta.thinking, and Gemini content.parts
- Save initial record with "[Streaming in progress...]" marker
- Update record with actual content when stream completes
- Include usage tokens when available from stream

**Files Modified**:
- open-sse/handlers/chatCore.js - extractRequestConfig() + streaming capture
- open-sse/utils/stream.js - onStreamComplete callback + content accumulation

**Benefits**:
- View complete request configuration in Request Details (thinking mode, etc.)
- See actual streaming response content instead of placeholder
- Better debugging and observability for AI requests

Refs: #request-details-enhancement

* feat: separate thinking/reasoning content from response content

Improve Request Details to display thinking process separately from final response:

**Backend Changes**:
- stream.js: Capture content and thinking separately in streaming mode
  - Add accumulatedThinking variable alongside accumulatedContent
  - Route delta.content to content, delta.reasoning_content to thinking
  - Support OpenAI (reasoning_content), Claude (thinking), Gemini (part.thought)
  - Update onStreamComplete callback to return { content, thinking } object

- chatCore.js: Update response structure to include thinking field
  - Non-streaming: Extract thinking from reasoning_content field
  - Streaming: Receive { content, thinking } from stream callback
  - Error responses: Include thinking: null
  - Initial streaming save: Include thinking: null

**Frontend Changes**:
- RequestDetailsTab.js: Display thinking and content in separate sections
  - Add amber/yellow themed "Thinking Process" section with psychology icon
  - Show "Final Response" label when thinking is present
  - Use distinct visual styling for thinking (amber bg) vs content (gray bg)
  - Only show thinking section when thinking content exists

**Benefits**:
- Users can clearly see model's reasoning process vs final answer
- Better debugging for models with thinking capabilities (Claude, o1, etc.)
- Visual distinction makes it easy to identify thinking vs response

Refs: #thinking-content-separation

* fix: map Claude thinking to reasoning_content field

Fix Claude thinking content to be properly captured as reasoning_content
instead of regular content, enabling separate display in Request Details:

**Changes**:
- claude-to-openai.js: Use reasoning_content field for thinking blocks
  - thinking start: send { reasoning_content: "" } instead of { content: "```\n```" }
  - thinking delta: map to reasoning_content instead of content
  - thinking stop: send { reasoning_content: "" } instead of { content: "```\n```" }

**Why This Matters**:
- Previously Claude thinking was sent as `content` field, mixed with actual response
- Now thinking uses `reasoning_content` field, matching OpenAI's o1 format
- stream.js can now properly route thinking to accumulatedThinking variable
- Request Details UI will show Claude thinking in separate "Thinking Process" section

**Supported Thinking Formats**:
- OpenAI: delta.reasoning_content → thinking
- Claude: delta.thinking → reasoning_content (now fixed)
- Gemini: part.thought === true → thinking

Refs: #claude-thinking-fix

* feat(observability): capture and display full 4-layer request chain

Capture complete request/response chain in AI Request Details:
- Add providerRequest field (translated request sent to provider)
- Add providerResponse field (raw provider response, streaming indicator)
- Update chatCore.js at all 5 saveRequestDetail() call sites
- Reorganize UI into 4 collapsible sections with Material icons
- Preserve backward compatibility for old records
- Add distinct styling for streaming indicator

* fix(observability): resolve React duplicate key warning in request details table

- Use composite key (detail.id + index) to ensure unique keys
- Prevents React warnings when database contains duplicate IDs from old ID generation

* fix(observability): display actual content in streaming request details

Change providerResponse field for streaming requests from placeholder
"[Streaming - raw response not captured]" to actual final content.

This improves debugging experience by showing the real AI response
in the "Provider Response (Raw)" section instead of a confusing
placeholder message.

Files changed:
- open-sse/handlers/chatCore.js: Save contentObj.content to providerResponse
- src/app/.../RequestDetailsTab.js: Remove special handling for placeholder

* refactor(observability): migrate request details to SQLite for improved concurrency

- Replace LowDB JSON storage with better-sqlite3
- Enable WAL mode for true concurrent read/write support
- Add 5 indexes to accelerate queries (timestamp, provider, model, connection_id, status)
- Perform pagination at the database level to reduce memory footprint
- Maintain 1000 record limit with automatic cleanup of old data
- Ensure API compatibility via re-exports, requiring no caller changes

Performance improvements:
- Concurrent Writes: Lock-free WAL mode prevents data contention
- Query Efficiency: Index-based searches replace full dataset loading
- Data Integrity: Atomic operations prevent file corruption

* fix(observability): resolve pagination statistics display issues

- Fix issue where totalItems=0 showed 'Showing 1 to 0 of 0 results'
- Hide pagination controls when totalItems=0 or totalPages<=1
- Standardize API response fields: pagination.total -> pagination.totalItems

Before: Incorrect stats shown for empty data, and pager visible even for single-page results
After: Stats hidden for empty data, pager hidden when navigation is unnecessary

* feat(observability): display friendly provider names in request details

- Add /api/usage/providers endpoint to dynamically fetch provider list with names
- Replace hardcoded provider options with dynamic loading from database
- Display friendly provider names instead of IDs in both table and detail drawer
- Support custom provider nodes (e.g., OpenAI-compatible) with user-defined names
- Add provider name caching to optimize performance

* fix(observability): use INSERT OR REPLACE for request details to handle streaming updates

* fix(observability): resolve zero-token display issue by ensuring streaming usage capture and fixing key mismatch

* fix(observability): separate TTFT and total latency calculation for streaming requests

* feat(observability): implement SQLite write queue and JSON size limits

- Added in-memory buffer and batch writing for SQLite to prevent lock contention
- Implemented  with configurable 1MB limit to prevent DB bloat
- Added dashboard UI for observability performance and data management settings
- Integrated graceful shutdown handlers to prevent data loss

* fix(observability): resolve ReferenceError by declaring dbInstance
2026-02-09 10:30:42 +07:00
decolua 388389c972 Revert "feat(request-details): implement observability settings and enhance request detail tracking"
This reverts commit cbabf5547c.
2026-02-09 10:29:38 +07:00
decolua cbabf5547c feat(request-details): implement observability settings and enhance request detail tracking
- Added new observability settings in the dashboard for max records, batch size, flush interval, and max JSON size.
- Introduced `extractRequestConfig` function to capture full request configurations.
- Enhanced error handling by saving detailed request information on failures.
- Updated usage tracking to include new token metrics.
- Modified streaming functions to support detailed content and reasoning tracking.
2026-02-09 10:20:24 +07:00