更新工具链

This commit is contained in:
2026-06-11 18:04:47 +08:00
parent 440f83f6a7
commit d1324dc2f2
9 changed files with 718 additions and 570 deletions
+52 -4
View File
@@ -265,6 +265,30 @@
white-space: normal;
}
.trace-panel:empty { display: none; }
.reasoning-panel {
display: none;
margin-bottom: 8px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--surface2);
color: var(--text-dim);
font-size: 0.78rem;
white-space: normal;
overflow: hidden;
}
.reasoning-panel.show { display: block; }
.reasoning-title {
padding: 6px 9px;
border-bottom: 1px solid var(--border);
font-weight: 600;
}
.reasoning-content {
padding: 7px 9px;
white-space: pre-wrap;
max-height: 220px;
overflow-y: auto;
font-family: Consolas, 'Fira Code', monospace;
}
.trace-item {
border-left: 2px solid var(--accent-border);
padding-left: 8px;
@@ -859,18 +883,23 @@ function addAIBubble() {
const trace = document.createElement('div');
trace.className = 'trace-panel';
const reasoning = document.createElement('div');
reasoning.className = 'reasoning-panel';
reasoning.innerHTML = '<div class="reasoning-title">思考过程(模型返回)</div><div class="reasoning-content"></div>';
const txt = document.createElement('span');
txt.className = 'answer-text';
const stats = document.createElement('div');
stats.className = 'token-stats';
bub.appendChild(trace);
bub.appendChild(reasoning);
bub.appendChild(txt);
bub.appendChild(stats);
row.appendChild(av);
row.appendChild(bub);
msgBox.appendChild(row);
scrollToBottom();
return { bub, txt, trace, stats };
return { bub, txt, trace, reasoning, stats };
}
function formatTokenStats(stats) {
@@ -903,18 +932,24 @@ function appendTrace(aiBubble, frame) {
if (!aiBubble.trace) return;
const item = document.createElement('div');
item.className = `trace-item ${frame.status || ''}`;
const prefix = [frame.tool, frame.stage].filter(Boolean).join('/');
const label = frame.message || [frame.tool, frame.stage, frame.status].filter(Boolean).join(' ');
item.textContent = label;
item.textContent = prefix ? `${prefix}${label}` : label;
const data = frame.data || {};
const details = [];
if (data.sql) details.push(data.sql);
if (data.arguments) details.push(`参数:\n${data.arguments}`);
if (data.sql) details.push(`SQL:\n${data.sql}`);
if (data.result_preview) details.push(`结果预览:\n${data.result_preview}`);
const stats = [];
if (typeof data.iteration === 'number') stats.push(`轮次: ${data.iteration}${data.max_iterations ? '/' + data.max_iterations : ''}`);
if (data.tool_call_id) stats.push(`调用 ID: ${data.tool_call_id}`);
if (data.database) stats.push(`数据库: ${data.database}`);
if (typeof data.rows === 'number') stats.push(`行数: ${data.rows}`);
if (typeof data.columns === 'number') stats.push(`列数: ${data.columns}`);
if (typeof data.count === 'number') stats.push(`结果数: ${data.count}`);
if (Array.isArray(data.tools) && data.tools.length) stats.push(`工具: ${data.tools.join(', ')}`);
if (typeof data.duration_ms === 'number') stats.push(`耗时: ${data.duration_ms}ms`);
if (data.truncated) stats.push(`已截断,最多 ${data.max_rows || ''}`);
if (data.reason) stats.push(`原因: ${data.reason}`);
if (data.error) stats.push(`错误: ${data.error}`);
@@ -923,7 +958,7 @@ function appendTrace(aiBubble, frame) {
if (details.length) {
const detail = document.createElement('div');
detail.className = 'trace-detail';
detail.textContent = details.join('\n');
detail.textContent = details.join('\n\n');
item.appendChild(detail);
}
@@ -931,6 +966,15 @@ function appendTrace(aiBubble, frame) {
scrollToBottom();
}
function appendReasoning(aiBubble, text) {
if (!aiBubble.reasoning || !text) return;
aiBubble.reasoning.classList.add('show');
const content = aiBubble.reasoning.querySelector('.reasoning-content');
content.textContent += text;
content.scrollTop = content.scrollHeight;
scrollToBottom();
}
async function streamChat(messages, aiBubble) {
const txtEl = aiBubble.txt;
let full = '';
@@ -996,6 +1040,10 @@ async function streamChat(messages, aiBubble) {
scrollToBottom();
continue;
}
if (parsed.type === 'reasoning') {
appendReasoning(aiBubble, parsed.text || '');
continue;
}
if (parsed.type === 'trace') {
appendTrace(aiBubble, parsed);
continue;