up
This commit is contained in:
+90
-4
@@ -259,6 +259,40 @@
|
||||
}
|
||||
@keyframes blink { 50% { opacity: 0; } }
|
||||
|
||||
/* 执行过程 */
|
||||
.trace-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin-bottom: 8px;
|
||||
color: var(--text-dim);
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.45;
|
||||
white-space: normal;
|
||||
}
|
||||
.trace-panel:empty { display: none; }
|
||||
.trace-item {
|
||||
border-left: 2px solid var(--accent-border);
|
||||
padding-left: 8px;
|
||||
}
|
||||
.trace-item.running { color: var(--text-dim); }
|
||||
.trace-item.success { opacity: .86; }
|
||||
.trace-item.error {
|
||||
color: var(--danger);
|
||||
border-left-color: var(--danger);
|
||||
}
|
||||
.trace-detail {
|
||||
margin-top: 4px;
|
||||
font-family: Consolas, 'Fira Code', monospace;
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 6px 8px;
|
||||
white-space: pre-wrap;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.answer-text { display: inline; }
|
||||
|
||||
/* 错误消息 */
|
||||
.error-msg {
|
||||
color: var(--danger);
|
||||
@@ -830,13 +864,49 @@ function addAIBubble() {
|
||||
const bub = document.createElement('div');
|
||||
bub.className = 'bubble typing-cursor';
|
||||
|
||||
const trace = document.createElement('div');
|
||||
trace.className = 'trace-panel';
|
||||
|
||||
const txt = document.createElement('span');
|
||||
txt.className = 'answer-text';
|
||||
bub.appendChild(trace);
|
||||
bub.appendChild(txt);
|
||||
row.appendChild(av);
|
||||
row.appendChild(bub);
|
||||
msgBox.appendChild(row);
|
||||
scrollToBottom();
|
||||
return { bub, txt };
|
||||
return { bub, txt, trace };
|
||||
}
|
||||
|
||||
function appendTrace(aiBubble, frame) {
|
||||
if (!aiBubble.trace) return;
|
||||
const item = document.createElement('div');
|
||||
item.className = `trace-item ${frame.status || ''}`;
|
||||
const label = frame.message || [frame.tool, frame.stage, frame.status].filter(Boolean).join(' ');
|
||||
item.textContent = label;
|
||||
|
||||
const data = frame.data || {};
|
||||
const details = [];
|
||||
if (data.sql) details.push(data.sql);
|
||||
const stats = [];
|
||||
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 (data.truncated) stats.push(`已截断,最多 ${data.max_rows || ''} 行`);
|
||||
if (data.reason) stats.push(`原因: ${data.reason}`);
|
||||
if (data.error) stats.push(`错误: ${data.error}`);
|
||||
if (stats.length) details.push(stats.join(' | '));
|
||||
|
||||
if (details.length) {
|
||||
const detail = document.createElement('div');
|
||||
detail.className = 'trace-detail';
|
||||
detail.textContent = details.join('\n');
|
||||
item.appendChild(detail);
|
||||
}
|
||||
|
||||
aiBubble.trace.appendChild(item);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
async function streamChat(messages, aiBubble, webSearch = false) {
|
||||
@@ -880,13 +950,29 @@ async function streamChat(messages, aiBubble, webSearch = false) {
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed && typeof parsed === 'object' && parsed.error) {
|
||||
throw new Error(parsed.error);
|
||||
}
|
||||
if (typeof parsed === 'string') {
|
||||
full += parsed;
|
||||
txtEl.innerHTML = renderMarkdown(full);
|
||||
scrollToBottom();
|
||||
continue;
|
||||
}
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
if (parsed.type === 'error' || parsed.error) {
|
||||
throw new Error(parsed.error || parsed.message || '流式响应错误');
|
||||
}
|
||||
if (parsed.type === 'delta') {
|
||||
const delta = parsed.text || '';
|
||||
if (delta) {
|
||||
full += delta;
|
||||
txtEl.innerHTML = renderMarkdown(full);
|
||||
scrollToBottom();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (parsed.type === 'trace') {
|
||||
appendTrace(aiBubble, parsed);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) continue;
|
||||
|
||||
Reference in New Issue
Block a user