feat: improve agent runtime observability

This commit is contained in:
2026-06-22 07:27:56 +08:00
parent 46248c1745
commit 17031cc3c9
5 changed files with 180 additions and 22 deletions
@@ -134,48 +134,89 @@ const handleCopy = async () => {
// 获取步骤类型标签
const getStepLabel = (step: ReasoningStep) => {
if (step.status === 'failed') {
return '失败';
}
if (step.status === 'running') {
return '执行中';
}
// 如果是节点类型,根据 status 显示不同的标签
if (step.type === 'node_start' || step.type === 'node_complete') {
if (step.status === 'running') {
return '执行中';
}
return '已完成';
}
const labels: Record<string, string> = {
thought: '思考',
action: '执行',
annotation_reply: '标注回复',
error: '错误',
knowledge_retrieval: '知识库检索',
llm_chunk: '模型输出',
loop_complete: '循环完成',
loop_iteration_complete: '单次完成',
loop_iteration_error: '单次失败',
loop_iteration_start: '循环开始',
observation: '观察',
parallel_complete: '并行完成',
parallel_start: '并行开始',
thought: '思考',
tool_call: '调用工具',
tool_result: '工具结果',
knowledge_retrieval: '知识库检索',
annotation_reply: '标注回复',
waiting_input: '等待输入',
};
return labels[step.type] || step.type;
};
// 获取步骤类型颜色
const getStepColor = (step: ReasoningStep) => {
if (step.status === 'failed' || step.type === 'error') {
return 'text-red-500';
}
if (step.status === 'running') {
return 'text-blue-500';
}
// 如果是节点类型,根据 status 显示不同的颜色
if (step.type === 'node_start' || step.type === 'node_complete') {
if (step.status === 'running') {
return 'text-blue-500';
}
return 'text-emerald-500';
}
const colors: Record<string, string> = {
thought: 'text-blue-500',
action: 'text-orange-500',
annotation_reply: 'text-emerald-500',
knowledge_retrieval: 'text-cyan-500',
llm_chunk: 'text-blue-500',
loop_complete: 'text-emerald-500',
loop_iteration_complete: 'text-emerald-500',
loop_iteration_error: 'text-red-500',
loop_iteration_start: 'text-blue-500',
observation: 'text-green-500',
parallel_complete: 'text-emerald-500',
parallel_start: 'text-blue-500',
thought: 'text-blue-500',
tool_call: 'text-purple-500',
tool_result: 'text-teal-500',
knowledge_retrieval: 'text-cyan-500',
annotation_reply: 'text-emerald-500',
waiting_input: 'text-amber-500',
};
return colors[step.type] || 'text-gray-500';
};
const getStepMeta = (step: ReasoningStep) => {
const items: string[] = [];
if (step.agent_name) items.push(step.agent_name);
if (step.branch_label) items.push(`分支 ${step.branch_label}`);
if (step.subflow_name) items.push(`子流程 ${step.subflow_name}`);
const modelText = [step.provider_name, step.model || step.model_id]
.filter(Boolean)
.join(' / ');
if (modelText) items.push(modelText);
return items.join(' · ');
};
// 格式化文件大小
const formatFileSize = (bytes?: number) => {
if (!bytes) return '';
@@ -302,6 +343,9 @@ const formatVoiceDuration = (seconds: number) => {
{{ getStepLabel(step) }}
</span>
<span class="step-text">{{ step.content }}</span>
<span v-if="getStepMeta(step)" class="step-meta">
{{ getStepMeta(step) }}
</span>
</div>
</div>
</div>
@@ -495,6 +539,9 @@ const formatVoiceDuration = (seconds: number) => {
class="chat-actions"
>
<div class="action-info">
<span v-if="message.provider_name || message.model_name">
{{ [message.provider_name, message.model_name].filter(Boolean).join(' / ') }}
</span>
<span v-if="message.elapsed_time">{{ message.elapsed_time }}ms</span>
<span v-if="message.tokens_used">{{ message.tokens_used }} tokens</span>
</div>
@@ -1263,8 +1310,18 @@ const formatVoiceDuration = (seconds: number) => {
.step-text {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.step-meta {
max-width: 220px;
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--el-text-color-placeholder);
}
</style>
@@ -41,13 +41,22 @@ export interface ReasoningStep {
type:
| 'action'
| 'annotation_reply'
| 'error'
| 'knowledge_retrieval'
| 'llm_chunk'
| 'loop_complete'
| 'loop_iteration_complete'
| 'loop_iteration_error'
| 'loop_iteration_start'
| 'node_complete'
| 'node_start'
| 'observation'
| 'parallel_complete'
| 'parallel_start'
| 'thought'
| 'tool_call'
| 'tool_result';
| 'tool_result'
| 'waiting_input';
content: string;
tool?: string;
params?: Record<string, any>;
@@ -55,8 +64,21 @@ export interface ReasoningStep {
node_id?: string;
node_type?: string;
output?: any;
/** 步骤状态:running 执行中,completed 已完成 */
status?: 'completed' | 'running';
branch_id?: string;
branch_label?: string;
agent_code?: string;
agent_name?: string;
model?: string;
model_id?: string;
provider_name?: string;
provider_type?: string;
subflow_name?: string;
from_subflow?: boolean;
collaboration_role?: string;
collaboration_mode?: string;
communication?: Record<string, any>;
/** 步骤状态:running 执行中,completed 已完成,failed 失败 */
status?: 'completed' | 'failed' | 'running';
timestamp?: string;
}
@@ -126,7 +148,12 @@ export interface ChatMessage {
tokens_used?: number;
error_message?: string;
feedback?: 'dislike' | 'like' | null;
model_id?: string;
model_name?: string;
provider_name?: string;
agent_code?: string;
agent_name?: string;
collaboration_mode?: string;
/** 语音消息 */
voice?: VoiceMessage;
/** 对话流交互配置(等待用户输入时) */
@@ -238,6 +238,19 @@ export function useChatApi(props: AiChatPanelProps): {
output: step.output,
status: step.status,
timestamp: step.timestamp,
branch_id: step.branch_id,
branch_label: step.branch_label,
agent_code: step.agent_code,
agent_name: step.agent_name,
model: step.model,
model_id: step.model_id,
provider_name: step.provider_name,
provider_type: step.provider_type,
subflow_name: step.subflow_name,
from_subflow: step.from_subflow,
collaboration_role: step.collaboration_role,
collaboration_mode: step.collaboration_mode,
communication: step.communication,
})),
interaction: msg.interaction,
voice: msg.voice,
@@ -178,8 +178,14 @@ export function useEventHandler(config: EventHandlerConfig) {
branch_label: event.branch_label,
agent_code: collaboration.agent_code || event.agent_code,
agent_name: collaboration.agent_name || event.agent_name,
model: collaboration.model || event.model,
model:
collaboration.model ||
collaboration.model_name ||
event.model ||
event.model_name,
model_id: collaboration.model_id || event.model_id,
provider_name: collaboration.provider_name || event.provider_name,
provider_type: collaboration.provider_type || event.provider_type,
subflow_name:
event.subflow_name || collaboration.subflow_name || event.event?.subflow_name,
from_subflow: Boolean(
@@ -198,10 +204,16 @@ export function useEventHandler(config: EventHandlerConfig) {
event.model ||
event.model_name ||
collaboration.model ||
collaboration.model_name ||
collaboration.model_id;
return {
...(modelName ? { model_name: modelName } : {}),
...(collaboration.model_id ? { model_id: collaboration.model_id } : {}),
...(event.model_id || collaboration.model_id
? { model_id: event.model_id || collaboration.model_id }
: {}),
...(event.provider_name || collaboration.provider_name
? { provider_name: event.provider_name || collaboration.provider_name }
: {}),
...(collaboration.agent_code
? { agent_code: collaboration.agent_code }
: {}),
@@ -426,6 +438,7 @@ export function useEventHandler(config: EventHandlerConfig) {
status: 'failed',
error_message: errorMessage,
reasoning_steps: [...currentSteps.value],
...buildMessageMeta(event),
});
running.value = false;
break;