feat: 接入 Agent 历史记录

- src/services/devopsApi.ts: 增加真实 Agent 调用历史列表接口
- src/components/GlobalAgentDrawer.vue: 抽屉打开时加载持久化历史,并展示用途、状态、问题和上下文摘要
This commit is contained in:
湛兮
2026-06-12 06:04:53 +08:00
parent a2eb83051c
commit da3bbb09e1
2 changed files with 75 additions and 2 deletions
+69 -2
View File
@@ -4,10 +4,10 @@
*/ */
import { Close, Promotion } from '@element-plus/icons-vue' import { Close, Promotion } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { computed, ref, watch } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
import { devopsApi } from '../services/devopsApi' import { devopsApi } from '../services/devopsApi'
import { usePlatformStore } from '../stores/platform' import { usePlatformStore } from '../stores/platform'
import type { AgentMode, AgentPurpose } from '../types/devops' import type { AgentInvocation, AgentMode, AgentPurpose } from '../types/devops'
type AgentMessage = { type AgentMessage = {
id: string id: string
@@ -28,6 +28,7 @@ const selectedProject = ref('')
const selectedRun = ref('') const selectedRun = ref('')
const prompt = ref('帮我检查当前发布是否存在配置、构建或通知风险。') const prompt = ref('帮我检查当前发布是否存在配置、构建或通知风险。')
const sending = ref(false) const sending = ref(false)
const historyLoading = ref(false)
const messages = ref<AgentMessage[]>([ const messages = ref<AgentMessage[]>([
{ {
id: 'welcome', id: 'welcome',
@@ -38,6 +39,14 @@ const messages = ref<AgentMessage[]>([
}, },
]) ])
const purposeTitles: Record<AgentPurpose, string> = {
'release-risk': '发布风险',
'failure-diagnosis': '失败诊断',
'runbook-qa': 'Runbook',
'release-note': '发布说明',
'incident-review': '事故复盘',
}
const activeCard = computed(() => { const activeCard = computed(() => {
return platform.agentCards.find((card) => card.mode === selectedMode.value) return platform.agentCards.find((card) => card.mode === selectedMode.value)
}) })
@@ -98,6 +107,26 @@ watch(selectedMode, (mode) => {
prompt.value = '帮我检查当前发布是否存在配置、构建或通知风险。' prompt.value = '帮我检查当前发布是否存在配置、构建或通知风险。'
}) })
onMounted(() => {
void loadInvocationHistory()
})
async function loadInvocationHistory() {
historyLoading.value = true
try {
const invocations = await devopsApi.listAgentInvocations()
messages.value = [
messages.value[0],
...invocations.slice(0, 20).map(toHistoryMessage),
]
} catch (error) {
ElMessage.error(error instanceof Error ? error.message : 'Agent 历史加载失败')
} finally {
historyLoading.value = false
}
}
async function sendPrompt() { async function sendPrompt() {
const text = prompt.value.trim() const text = prompt.value.trim()
@@ -137,6 +166,37 @@ async function sendPrompt() {
} }
} }
function toHistoryMessage(invocation: AgentInvocation): AgentMessage {
return {
id: invocation.id,
role: 'assistant',
title: `${purposeTitles[invocation.type]} · ${statusLabel(invocation.status)}`,
content: [
`问题:${invocation.promptSummary}`,
'',
invocation.resultMarkdown || 'Agent 未返回内容',
].join('\n'),
contextSummary: invocation.contextSummary,
createdAt: formatTime(invocation.createdAt),
}
}
function statusLabel(status: AgentInvocation['status']): string {
if (status === 'success') {
return '成功'
}
if (status === 'failed') {
return '失败'
}
if (status === 'running') {
return '运行中'
}
return '等待中'
}
function handleComposerKeydown(event: KeyboardEvent) { function handleComposerKeydown(event: KeyboardEvent) {
if (event.key !== 'Enter' || (!event.metaKey && !event.ctrlKey)) { if (event.key !== 'Enter' || (!event.metaKey && !event.ctrlKey)) {
return return
@@ -208,6 +268,7 @@ function formatTime(value: string): string {
</div> </div>
<div class="message-list"> <div class="message-list">
<div v-if="historyLoading" class="history-loading">正在加载历史记录...</div>
<article v-for="message in messages" :key="message.id" class="agent-message" :class="message.role"> <article v-for="message in messages" :key="message.id" class="agent-message" :class="message.role">
<div class="message-meta"> <div class="message-meta">
<strong>{{ message.title }}</strong> <strong>{{ message.title }}</strong>
@@ -300,6 +361,12 @@ function formatTime(value: string): string {
overflow-y: auto; overflow-y: auto;
} }
.history-loading {
color: #64748b;
font-size: 12px;
text-align: center;
}
.agent-message { .agent-message {
max-width: 100%; max-width: 100%;
padding: 12px; padding: 12px;
+6
View File
@@ -503,6 +503,12 @@ export const devopsApi = {
return data return data
}, },
async listAgentInvocations(): Promise<AgentInvocation[]> {
const { data } = await http.get<AgentInvocation[]>('/agent/invocations')
lastDataSource = 'backend'
return data
},
async getSettings(): Promise<SystemSetting[]> { async getSettings(): Promise<SystemSetting[]> {
const [health, integrationConfig] = await Promise.all([ const [health, integrationConfig] = await Promise.all([
fetchHealth(), fetchHealth(),