feat(studio): 补齐剩余工作台聚合接口与真实对接
This commit is contained in:
@@ -1,7 +1,72 @@
|
||||
<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 { chatMessages, citations, traceSteps } from '@/data/studioMock';
|
||||
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>
|
||||
@@ -11,38 +76,47 @@ import { chatMessages, citations, traceSteps } from '@/data/studioMock';
|
||||
<p class="studio-kicker">AgentWorkspaceView</p>
|
||||
<h1>Agent 对话调试</h1>
|
||||
</div>
|
||||
<el-button type="primary">发布 Agent</el-button>
|
||||
<el-button type="primary">{{ workspace?.status || 'Draft' }}</el-button>
|
||||
</header>
|
||||
|
||||
<div class="agent-layout">
|
||||
<div class="agent-layout" v-loading="loading">
|
||||
<section class="studio-panel chat-panel">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<h2>售前问答 Agent</h2>
|
||||
<span>POST /api/agents/1001/runs</span>
|
||||
<h2>{{ workspace?.agentName || 'Agent 工作台' }}</h2>
|
||||
<span>GET /api/agent-sessions/workspace</span>
|
||||
</div>
|
||||
<el-tag>Draft</el-tag>
|
||||
<el-tag>{{ workspace?.sessionStatus || workspace?.status || 'DRAFT' }}</el-tag>
|
||||
</div>
|
||||
<div class="message-list">
|
||||
<article v-for="message in chatMessages" :key="message.content" :class="message.role">
|
||||
<strong>{{ message.role === 'user' ? '用户' : 'Agent' }}</strong>
|
||||
<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>
|
||||
<el-button type="primary"><el-icon><ChatDotRound /></el-icon> 发送</el-button>
|
||||
<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>3 个来源</span>
|
||||
<span>{{ workspace?.citationCount || 0 }} 个来源</span>
|
||||
</div>
|
||||
<article v-for="citation in citations" :key="citation.title" class="citation-card">
|
||||
<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">score {{ citation.score }}</el-tag>
|
||||
<el-tag type="success">引用</el-tag>
|
||||
<p>{{ citation.text }}</p>
|
||||
</article>
|
||||
</aside>
|
||||
@@ -50,17 +124,17 @@ import { chatMessages, citations, traceSteps } from '@/data/studioMock';
|
||||
<aside class="studio-panel run-inspector">
|
||||
<div class="panel-heading compact">
|
||||
<h2>运行追踪</h2>
|
||||
<span>modelRequestId: f4215d</span>
|
||||
<span data-test="agent-latest-request-id">requestId: {{ workspace?.latestRequestId || '-' }}</span>
|
||||
</div>
|
||||
<div class="metric-mini">
|
||||
<span><el-icon><Timer /></el-icon> 1.42s</span>
|
||||
<span><el-icon><Coin /></el-icon> ¥0.018</span>
|
||||
<span>1,248 tokens</span>
|
||||
<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-for="step in traceSteps" :key="step.node">
|
||||
<time>{{ step.duration }}</time>
|
||||
<span>{{ step.node }} · {{ step.output }}</span>
|
||||
<li v-if="latestAssistantMessage">
|
||||
<time>{{ workspace?.sessionCode || '-' }}</time>
|
||||
<span>{{ latestAssistantMessage.content }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user