feat(executors): Improved UI components for displaying provider limits and usage statistics in the dashboard.

This commit is contained in:
decolua
2026-02-05 18:38:50 +07:00
parent 249fc28c49
commit 32aefe5a76
21 changed files with 1112 additions and 310 deletions
+38 -4
View File
@@ -53,10 +53,18 @@ const FIELD = {
MSG_CONTENT: 1,
MSG_ROLE: 2,
MSG_ID: 13,
MSG_TOOL_RESULTS: 18,
MSG_IS_AGENTIC: 29,
MSG_UNIFIED_MODE: 47,
MSG_SUPPORTED_TOOLS: 51,
// ConversationMessage.ToolResult
TOOL_RESULT_CALL_ID: 1,
TOOL_RESULT_NAME: 2,
TOOL_RESULT_INDEX: 3,
TOOL_RESULT_RAW_ARGS: 5,
TOOL_RESULT_RESULT: 8,
// Model
MODEL_NAME: 1,
MODEL_EMPTY: 4,
@@ -101,6 +109,7 @@ const FIELD = {
TOOL_ID: 3,
TOOL_NAME: 9,
TOOL_RAW_ARGS: 10,
TOOL_IS_LAST: 11,
TOOL_MCP_PARAMS: 27,
// MCPParams
@@ -166,11 +175,28 @@ function concatArrays(...arrays) {
// ==================== MESSAGE ENCODING ====================
export function encodeMessage(content, role, messageId, chatModeEnum = null, isLast = false, hasTools = false) {
export function encodeToolResult(toolResult) {
const toolCallId = toolResult.tool_call_id || "";
const toolName = toolResult.name || "";
const toolIndex = toolResult.index || 0;
const rawArgs = toolResult.raw_args || "{}";
return concatArrays(
encodeField(FIELD.TOOL_RESULT_CALL_ID, WIRE_TYPE.LEN, toolCallId),
encodeField(FIELD.TOOL_RESULT_NAME, WIRE_TYPE.LEN, toolName),
encodeField(FIELD.TOOL_RESULT_INDEX, WIRE_TYPE.VARINT, toolIndex),
encodeField(FIELD.TOOL_RESULT_RAW_ARGS, WIRE_TYPE.LEN, rawArgs)
);
}
export function encodeMessage(content, role, messageId, chatModeEnum = null, isLast = false, hasTools = false, toolResults = []) {
return concatArrays(
encodeField(FIELD.MSG_CONTENT, WIRE_TYPE.LEN, content),
encodeField(FIELD.MSG_ROLE, WIRE_TYPE.VARINT, role),
encodeField(FIELD.MSG_ID, WIRE_TYPE.LEN, messageId),
...(toolResults.length > 0 ? toolResults.map(tr =>
encodeField(FIELD.MSG_TOOL_RESULTS, WIRE_TYPE.LEN, encodeToolResult(tr))
) : []),
encodeField(FIELD.MSG_IS_AGENTIC, WIRE_TYPE.VARINT, hasTools ? 1 : 0),
encodeField(FIELD.MSG_UNIFIED_MODE, WIRE_TYPE.VARINT, hasTools ? UNIFIED_MODE.AGENT : UNIFIED_MODE.CHAT),
...(isLast && hasTools ? [encodeField(FIELD.MSG_SUPPORTED_TOOLS, WIRE_TYPE.LEN, encodeVarint(1))] : [])
@@ -254,7 +280,8 @@ export function encodeRequest(messages, modelName, tools = [], reasoningEffort =
role,
messageId: msgId,
isLast,
hasTools
hasTools,
toolResults: msg.tool_results || []
});
messageIds.push({ messageId: msgId, role });
@@ -270,7 +297,7 @@ export function encodeRequest(messages, modelName, tools = [], reasoningEffort =
// Messages
...formattedMessages.map(fm =>
encodeField(FIELD.MESSAGES, WIRE_TYPE.LEN,
encodeMessage(fm.content, fm.role, fm.messageId, null, fm.isLast, fm.hasTools)
encodeMessage(fm.content, fm.role, fm.messageId, null, fm.isLast, fm.hasTools, fm.toolResults)
)
),
@@ -439,6 +466,7 @@ function extractToolCall(toolCallData) {
let toolCallId = "";
let toolName = "";
let rawArgs = "";
let isLast = false;
// Extract tool call ID
if (toolCall.has(FIELD.TOOL_ID)) {
@@ -451,6 +479,11 @@ function extractToolCall(toolCallData) {
toolName = new TextDecoder().decode(toolCall.get(FIELD.TOOL_NAME)[0].value);
}
// Extract is_last flag
if (toolCall.has(FIELD.TOOL_IS_LAST)) {
isLast = toolCall.get(FIELD.TOOL_IS_LAST)[0].value !== 0;
}
// Extract MCP params - nested real tool info
if (toolCall.has(FIELD.TOOL_MCP_PARAMS)) {
try {
@@ -484,7 +517,8 @@ function extractToolCall(toolCallData) {
function: {
name: toolName,
arguments: rawArgs || "{}"
}
},
isLast
};
}
+20 -67
View File
@@ -2,70 +2,13 @@ import { translateResponse, initState } from "../translator/index.js";
import { FORMATS } from "../translator/formats.js";
import { trackPendingRequest, appendRequestLog } from "@/lib/usageDb.js";
import { extractUsage, hasValidUsage, estimateUsage, logUsage, addBufferToUsage, filterUsageForFormat, COLORS } from "./usageTracking.js";
import { parseSSELine, hasValuableContent, fixInvalidId, formatSSE } from "./streamHelpers.js";
// Re-export COLORS for backward compatibility
export { COLORS };
export { COLORS, formatSSE };
// Singleton TextEncoder/Decoder for performance (reuse across all streams)
const sharedDecoder = new TextDecoder();
const sharedEncoder = new TextEncoder();
// Parse SSE data line (optimized - reduce string operations)
function parseSSELine(line) {
if (!line || line.charCodeAt(0) !== 100) return null; // 'd' = 100
const data = line.slice(5).trim();
if (data === "[DONE]") return { done: true };
try {
return JSON.parse(data);
} catch (error) {
// Log parse errors for debugging incomplete chunks
if (data.length > 0 && data.length < 1000) {
console.log(`[WARN] Failed to parse SSE line (${data.length} chars): ${data.substring(0, 100)}...`);
}
return null;
}
}
/**
* Format output as SSE
* @param {object} data - Data to format
* @param {string} sourceFormat - Target format for client
* @returns {string} SSE formatted string
*/
export function formatSSE(data, sourceFormat) {
// Handle null/undefined
if (data === null || data === undefined) {
return "data: null\n\n";
}
if (data && data.done) return "data: [DONE]\n\n";
// OpenAI Responses API format: has event field
if (data && data.event && data.data) {
return `event: ${data.event}\ndata: ${JSON.stringify(data.data)}\n\n`;
}
// Claude format: include event prefix
if (sourceFormat === FORMATS.CLAUDE && data && data.type) {
// If perf_metrics is null, remove it to avoid serialization issues
if (data.usage && typeof data.usage === 'object' && data.usage.perf_metrics === null) {
const { perf_metrics, ...usageWithoutPerf } = data.usage;
data = { ...data, usage: usageWithoutPerf };
}
return `event: ${data.type}\ndata: ${JSON.stringify(data)}\n\n`;
}
// If perf_metrics is null, remove it to avoid serialization issues
if (data?.usage && typeof data.usage === 'object' && data.usage.perf_metrics === null) {
const { perf_metrics, ...usageWithoutPerf } = data.usage;
data = { ...data, usage: usageWithoutPerf };
}
return `data: ${JSON.stringify(data)}\n\n`;
}
/**
* Stream modes
*/
@@ -129,37 +72,42 @@ export function createSSEStream(options = {}) {
try {
const parsed = JSON.parse(trimmed.slice(5).trim());
// Track content length for estimation
const content = parsed.choices?.[0]?.delta?.content || parsed.choices?.[0]?.delta?.reasoning_content;
const idFixed = fixInvalidId(parsed);
if (!hasValuableContent(parsed, FORMATS.OPENAI)) {
continue;
}
const delta = parsed.choices?.[0]?.delta;
const content = delta?.content || delta?.reasoning_content;
if (content && typeof content === "string") {
totalContentLength += content.length;
}
// Extract usage from chunk
const extracted = extractUsage(parsed);
if (extracted) {
usage = extracted; // Keep original usage for logging
usage = extracted;
}
// Inject estimated usage into final chunk (has finish_reason but no valid usage)
const isFinishChunk = parsed.choices?.[0]?.finish_reason;
if (isFinishChunk && !hasValidUsage(parsed.usage)) {
const estimated = estimateUsage(body, totalContentLength, FORMATS.OPENAI);
parsed.usage = filterUsageForFormat(estimated, FORMATS.OPENAI); // Filter + already has buffer
parsed.usage = filterUsageForFormat(estimated, FORMATS.OPENAI);
output = `data: ${JSON.stringify(parsed)}\n`;
usage = estimated;
injectedUsage = true;
} else if (isFinishChunk && usage) {
// Add buffer and filter usage for client (but keep original for logging)
const buffered = addBufferToUsage(usage);
parsed.usage = filterUsageForFormat(buffered, FORMATS.OPENAI);
output = `data: ${JSON.stringify(parsed)}\n`;
injectedUsage = true;
} else if (idFixed) {
output = `data: ${JSON.stringify(parsed)}\n`;
injectedUsage = true;
}
} catch { }
}
// Normalize if not already injected
if (!injectedUsage) {
if (line.startsWith("data:") && !line.startsWith("data: ")) {
output = "data: " + line.slice(5) + "\n";
@@ -231,6 +179,11 @@ export function createSSEStream(options = {}) {
if (translated?.length > 0) {
for (const item of translated) {
// Filter empty chunks
if (!hasValuableContent(item, sourceFormat)) {
continue; // Skip this empty chunk
}
// Inject estimated usage if finish chunk has no valid usage
const isFinishChunk = item.type === "message_delta" || item.choices?.[0]?.finish_reason;
if (state.finishReason && isFinishChunk && !hasValidUsage(item.usage) && totalContentLength > 0) {
+85
View File
@@ -0,0 +1,85 @@
import { FORMATS } from "../translator/formats.js";
// Parse SSE data line
export function parseSSELine(line) {
if (!line || line.charCodeAt(0) !== 100) return null; // 'd' = 100
const data = line.slice(5).trim();
if (data === "[DONE]") return { done: true };
try {
return JSON.parse(data);
} catch (error) {
if (data.length > 0 && data.length < 1000) {
console.log(`[WARN] Failed to parse SSE line (${data.length} chars): ${data.substring(0, 100)}...`);
}
return null;
}
}
// Check if chunk has valuable content (not empty)
export function hasValuableContent(chunk, format) {
// OpenAI format
if (format === FORMATS.OPENAI && chunk.choices?.[0]?.delta) {
const delta = chunk.choices[0].delta;
return delta.content && delta.content !== "" ||
delta.reasoning_content && delta.reasoning_content !== "" ||
delta.tool_calls && delta.tool_calls.length > 0 ||
chunk.choices[0].finish_reason ||
delta.role;
}
// Claude format
if (format === FORMATS.CLAUDE) {
const isContentBlockDelta = chunk.type === "content_block_delta";
const hasText = chunk.delta?.text && chunk.delta.text !== "";
const hasThinking = chunk.delta?.thinking && chunk.delta.thinking !== "";
if (isContentBlockDelta && !hasText && !hasThinking) {
return false;
}
return true;
}
return true; // Other formats: keep all chunks
}
// Fix invalid id (generic or too short)
export function fixInvalidId(parsed) {
if (parsed.id && (parsed.id === "chat" || parsed.id === "completion" || parsed.id.length < 8)) {
const fallbackId = parsed.extend_fields?.requestId ||
parsed.extend_fields?.traceId ||
Date.now().toString(36);
parsed.id = `chatcmpl-${fallbackId}`;
return true;
}
return false;
}
// Format output as SSE
export function formatSSE(data, sourceFormat) {
if (data === null || data === undefined) return "data: null\n\n";
if (data && data.done) return "data: [DONE]\n\n";
// OpenAI Responses API format
if (data && data.event && data.data) {
return `event: ${data.event}\ndata: ${JSON.stringify(data.data)}\n\n`;
}
// Claude format
if (sourceFormat === FORMATS.CLAUDE && data && data.type) {
if (data.usage && typeof data.usage === 'object' && data.usage.perf_metrics === null) {
const { perf_metrics, ...usageWithoutPerf } = data.usage;
data = { ...data, usage: usageWithoutPerf };
}
return `event: ${data.type}\ndata: ${JSON.stringify(data)}\n\n`;
}
// Remove null perf_metrics
if (data?.usage && typeof data.usage === 'object' && data.usage.perf_metrics === null) {
const { perf_metrics, ...usageWithoutPerf } = data.usage;
data = { ...data, usage: usageWithoutPerf };
}
return `data: ${JSON.stringify(data)}\n\n`;
}