144 lines
4.7 KiB
Vue
144 lines
4.7 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onMounted, ref } from 'vue';
|
||
import { ChatDotRound, Coin, Timer } from '@element-plus/icons-vue';
|
||
import { ElMessage } from 'element-plus';
|
||
|
||
import type { AgentMessageRecord, AgentWorkspace } from '@/api/agent';
|
||
import { appendAgentMessage, getAgentWorkspace } from '@/api/agent';
|
||
|
||
const loading = ref(false);
|
||
const agentId = ref('1001');
|
||
const workspace = ref<AgentWorkspace | null>(null);
|
||
const draftMessage = ref('');
|
||
|
||
const citations = computed(() => {
|
||
return (workspace.value?.messages ?? [])
|
||
.filter((message) => message.citationJson?.includes('chunkId'))
|
||
.map((message, index) => ({
|
||
key: `${message.id || index}`,
|
||
title: `引用 ${index + 1}`,
|
||
text: message.citationJson ?? '',
|
||
}));
|
||
});
|
||
|
||
const latestAssistantMessage = computed(() => {
|
||
const assistantMessages = (workspace.value?.messages ?? []).filter((item) => item.role === 'assistant');
|
||
return assistantMessages.length > 0 ? assistantMessages[assistantMessages.length - 1] : null;
|
||
});
|
||
|
||
function roleLabel(role: AgentMessageRecord['role']) {
|
||
if (role === 'user') {
|
||
return '用户';
|
||
}
|
||
if (role === 'assistant') {
|
||
return 'Agent';
|
||
}
|
||
return '系统';
|
||
}
|
||
|
||
async function loadWorkspace() {
|
||
loading.value = true;
|
||
try {
|
||
const response = await getAgentWorkspace(agentId.value);
|
||
workspace.value = response.data;
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
async function sendMessage() {
|
||
if (!workspace.value?.sessionId || !draftMessage.value.trim()) {
|
||
return;
|
||
}
|
||
await appendAgentMessage(workspace.value.sessionId, {
|
||
role: 'user',
|
||
content: draftMessage.value.trim(),
|
||
});
|
||
ElMessage.success('调试消息已写入会话');
|
||
draftMessage.value = '';
|
||
await loadWorkspace();
|
||
}
|
||
|
||
function formatCost(tokens?: number) {
|
||
if (!tokens) {
|
||
return '¥0.000';
|
||
}
|
||
return `¥${(tokens / 100000).toFixed(3)}`;
|
||
}
|
||
|
||
onMounted(loadWorkspace);
|
||
</script>
|
||
|
||
<template>
|
||
<section class="studio-page agent-page">
|
||
<header class="page-title-row">
|
||
<div>
|
||
<p class="studio-kicker">AgentWorkspaceView</p>
|
||
<h1>Agent 对话调试</h1>
|
||
</div>
|
||
<el-button type="primary">{{ workspace?.status || 'Draft' }}</el-button>
|
||
</header>
|
||
|
||
<div class="agent-layout" v-loading="loading">
|
||
<section class="studio-panel chat-panel">
|
||
<div class="panel-heading">
|
||
<div>
|
||
<h2>{{ workspace?.agentName || 'Agent 工作台' }}</h2>
|
||
<span>GET /api/agent-sessions/workspace</span>
|
||
</div>
|
||
<el-tag>{{ workspace?.sessionStatus || workspace?.status || 'DRAFT' }}</el-tag>
|
||
</div>
|
||
<div class="message-list">
|
||
<article
|
||
v-for="message in workspace?.messages ?? []"
|
||
:key="message.id || message.content"
|
||
:class="message.role"
|
||
:data-test="`agent-message-${message.role}`"
|
||
>
|
||
<strong>{{ roleLabel(message.role) }}</strong>
|
||
<p>{{ message.content }}</p>
|
||
</article>
|
||
</div>
|
||
<div class="chat-composer">
|
||
<span>输入调试问题,写入当前 agent_session / agent_message</span>
|
||
<input v-model="draftMessage" data-test="agent-message-input" type="text" />
|
||
<el-button data-test="agent-send-message" type="primary" @click="sendMessage">
|
||
<el-icon><ChatDotRound /></el-icon>
|
||
发送
|
||
</el-button>
|
||
</div>
|
||
</section>
|
||
|
||
<aside class="studio-panel citation-panel">
|
||
<div class="panel-heading compact">
|
||
<h2>引用切片</h2>
|
||
<span>{{ workspace?.citationCount || 0 }} 个来源</span>
|
||
</div>
|
||
<article v-for="citation in citations" :key="citation.key" class="citation-card" data-test="agent-citation-card">
|
||
<strong>{{ citation.title }}</strong>
|
||
<el-tag type="success">引用</el-tag>
|
||
<p>{{ citation.text }}</p>
|
||
</article>
|
||
</aside>
|
||
|
||
<aside class="studio-panel run-inspector">
|
||
<div class="panel-heading compact">
|
||
<h2>运行追踪</h2>
|
||
<span data-test="agent-latest-request-id">requestId: {{ workspace?.latestRequestId || '-' }}</span>
|
||
</div>
|
||
<div class="metric-mini">
|
||
<span><el-icon><Timer /></el-icon> {{ workspace?.sessionStatus || '-' }}</span>
|
||
<span><el-icon><Coin /></el-icon> {{ formatCost(workspace?.totalTokens) }}</span>
|
||
<span>{{ workspace?.totalTokens || 0 }} tokens</span>
|
||
</div>
|
||
<ol class="log-list">
|
||
<li v-if="latestAssistantMessage">
|
||
<time>{{ workspace?.sessionCode || '-' }}</time>
|
||
<span>{{ latestAssistantMessage.content }}</span>
|
||
</li>
|
||
</ol>
|
||
</aside>
|
||
</div>
|
||
</section>
|
||
</template>
|