feat(chat): 收拢式AI思考/执行过程可视化 + 修复span(name)重复传参导致技能/MCP执行崩溃
This commit is contained in:
1 parent
46528eddbb
commit
c32eed39bd
4 files changed
+4417
-2123
No files matched your search
+4273
-2123
File diff suppressed because it is too large.
Load diff
@@ -1557,3 +1557,110 @@ del {
|
||||
border-color: var(--color-accent, #5B5FED);
|
||||
color: var(--color-accent, #5B5FED);
|
||||
}
|
||||
|
||||
/* ===== AI 思考 / 执行过程面板(收拢式) ===== */
|
||||
.ai-process {
|
||||
margin-top: 10px;
|
||||
border: 1px solid var(--color-border-light, #e6e9f0);
|
||||
border-radius: var(--radius-md, 12px);
|
||||
background: color-mix(in srgb, var(--color-bg-secondary, #fff) 75%, var(--color-accent, #5B5FED) 4%);
|
||||
backdrop-filter: blur(8px) saturate(160%);
|
||||
overflow: hidden;
|
||||
transition: border-color var(--transition-fast, .2s), box-shadow var(--transition-fast, .2s);
|
||||
}
|
||||
|
||||
.ai-process[open] {
|
||||
box-shadow: 0 6px 22px rgba(91, 95, 237, 0.10);
|
||||
border-color: color-mix(in srgb, var(--color-accent, #5B5FED) 35%, transparent);
|
||||
}
|
||||
|
||||
.ai-process-summary {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 9px 14px;
|
||||
font-size: var(--text-sm, 13px);
|
||||
font-weight: 600;
|
||||
color: var(--color-text-secondary, #475069);
|
||||
user-select: none;
|
||||
transition: background var(--transition-fast, .2s);
|
||||
}
|
||||
|
||||
.ai-process-summary::-webkit-details-marker { display: none; }
|
||||
.ai-process-summary::marker { content: ""; }
|
||||
|
||||
.ai-process-summary:hover {
|
||||
background: color-mix(in srgb, var(--color-accent, #5B5FED) 7%, transparent);
|
||||
}
|
||||
|
||||
.ai-process-badge {
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
filter: drop-shadow(0 1px 2px rgba(91, 95, 237, 0.25));
|
||||
}
|
||||
|
||||
.ai-process-list {
|
||||
padding: 4px 14px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
animation: ai-process-in .28s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
@keyframes ai-process-in {
|
||||
from { opacity: 0; transform: translateY(-4px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.ai-process-item {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 9px 12px;
|
||||
border-radius: 10px;
|
||||
background: var(--color-bg-secondary, #fff);
|
||||
border: 1px solid var(--color-border-light, #e6e9f0);
|
||||
border-left: 3px solid var(--color-accent, #5B5FED);
|
||||
}
|
||||
|
||||
.ai-process-thinking { border-left-color: #8b8fe6; }
|
||||
.ai-process-skill { border-left-color: #5B5FED; }
|
||||
.ai-process-mcp { border-left-color: #12a594; }
|
||||
|
||||
.ai-process-ico {
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ai-process-body {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ai-process-title {
|
||||
display: block;
|
||||
font-size: var(--text-sm, 13px);
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary, #1f2430);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.ai-process-text {
|
||||
margin: 0;
|
||||
font-size: var(--text-xs, 12px);
|
||||
line-height: 1.55;
|
||||
color: var(--color-text-tertiary, #8a90a6);
|
||||
max-height: 160px;
|
||||
overflow-y: auto;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* 暗色主题微调 */
|
||||
[data-theme="dark"] .ai-process,
|
||||
html.dark .ai-process {
|
||||
background: color-mix(in srgb, var(--color-bg-secondary, #1b1d29) 70%, var(--color-accent, #5B5FED) 8%);
|
||||
border-color: color-mix(in srgb, var(--color-accent, #5B5FED) 25%, transparent);
|
||||
}
|
||||
@@ -895,6 +895,7 @@ const ChatPage: React.FC = () => {
|
||||
createdAt: data.assistant_message.created_at || new Date().toISOString(),
|
||||
used_skills: data.assistant_message.used_skills || [],
|
||||
used_mcp: data.assistant_message.used_mcp || [],
|
||||
process_steps: data.assistant_message.process_steps || [],
|
||||
});
|
||||
}
|
||||
return [...filtered, ...newMsgs];
|
||||
@@ -1168,6 +1169,7 @@ const ChatPage: React.FC = () => {
|
||||
// Real used_skills from API response
|
||||
const usedSkills: string[] = (msg.role === 'assistant' && msg.used_skills) ? msg.used_skills : [];
|
||||
const usedMcp: string[] = (msg.role === 'assistant' && msg.used_mcp) ? msg.used_mcp : [];
|
||||
const steps: any[] = (msg as any).process_steps || [];
|
||||
// 模糊创作意图确认卡片
|
||||
const clarify = msg.role === 'assistant' ? parseClarify(msg.content) : null;
|
||||
return (
|
||||
@@ -1235,6 +1237,34 @@ const ChatPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{msg.role === 'assistant' && steps.length > 0 && (
|
||||
<details className="ai-process" open={false}>
|
||||
<summary className="ai-process-summary">
|
||||
<span className="ai-process-badge">🧠</span>
|
||||
思考 / 执行过程({steps.length} 步,点击展开)
|
||||
</summary>
|
||||
<div className="ai-process-list">
|
||||
{steps.map((s: any, i: number) => (
|
||||
<div key={i} className={`ai-process-item ai-process-${s.type}`}>
|
||||
<span className="ai-process-ico">
|
||||
{s.type === 'thinking' ? '💡' : s.type === 'skill' ? '🛠' : '🔌'}
|
||||
</span>
|
||||
<div className="ai-process-body">
|
||||
{s.type === 'thinking' && (
|
||||
<><b className="ai-process-title">思考</b><p className="ai-process-text">{s.text}</p></>
|
||||
)}
|
||||
{s.type === 'skill' && (
|
||||
<><b className="ai-process-title">调用技能:{s.name}</b><p className="ai-process-text">{(s.result || '').slice(0, 400)}</p></>
|
||||
)}
|
||||
{s.type === 'mcp' && (
|
||||
<><b className="ai-process-title">MCP · {s.server}:{s.name}</b><p className="ai-process-text">{(s.result || '').slice(0, 400)}</p></>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</details>
|
||||
)}
|
||||
<div className={`message-meta ${msg.role}`}>
|
||||
<span className="message-time">{formatTime(msg.createdAt)}</span>
|
||||
<span className="message-tokens">{msg.tokenUsed} tokens</span>
|
||||
|
||||
@@ -62,6 +62,13 @@ export interface Message {
|
||||
createdAt: string;
|
||||
used_skills?: string[];
|
||||
used_mcp?: string[];
|
||||
process_steps?: Array<{
|
||||
type: 'thinking' | 'skill' | 'mcp';
|
||||
text?: string;
|
||||
name?: string;
|
||||
server?: string;
|
||||
result?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user