Files
X-Agents/web/src/views/Memory.vue
DESKTOP-72TV0V4\caoxiaozhu a07cc4498d feat: 更新前端页面
- Agents.vue: 大幅更新agent管理界面
- App.vue: 更新应用布局
- 各页面: 更新Account、Database、Knowledge、Memory、Script、Skill、Tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:19:04 +08:00

311 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, computed } from 'vue'
import { formatDate } from '@/utils/format'
import './database/database.css'
interface MemoryItem {
id: number
type: 'Experience' | 'Lessons'
content: string
subject: string
attribute: string
score: number
createdAt: string
selected: boolean
}
// 记忆数据
const memories = ref<MemoryItem[]>([
{
id: 1,
type: 'Experience',
content: '当任务明确要求获取外部信息搜索最新数据、新闻、财报、行业报告等模型必须主动调用搜索工具而非仅依赖内部知识。应在系统提示中明确要求「必须使用搜索工具获取XX最新数据」首次迭代即调用搜索工具采用「搜索→分析→输出」的递进式流程避免模型陷入纯文字生成的空转循环。',
subject: '外部信息获取规范',
attribute: '工具调用原则',
score: 0.95,
createdAt: '2026-03-10T15:35',
selected: false
},
{
id: 2,
type: 'Experience',
content: '当任务明确要求获取外部信息搜索最新数据、新闻、财报、行业报告等模型必须调用搜索工具而非仅依赖内部知识。应在系统提示中明确要求「必须使用搜索工具获取XX最新数据」并建立工具调用检测机制确保任务执行路径正确。',
subject: '工具调用',
attribute: '错误教训',
score: 0.95,
createdAt: '2026-03-10T12:34',
selected: false
},
{
id: 3,
type: 'Experience',
content: '任务执行应采用「一次性完整输出」策略避免分批次小幅输出导致的迭代空转。对于代码生成、文件写入等任务应要求模型一次性完成方案设计与工具执行的完整流程将确认性回复并入上一次响应将冗余迭代压缩合并复杂任务控制在2-3次迭代内完成。',
subject: '任务执行效率优化',
attribute: '迭代策略原则',
score: 0.92,
createdAt: '2026-03-10T15:35',
selected: false
},
{
id: 4,
type: 'Experience',
content: '任务执行过程中应建立工具调用检测机制监控模型是否按要求调用了必要的工具。若迭代中工具调用数为0说明执行路径不正确应触发异常处理或提示而非继续无效迭代。',
subject: '执行路径监控',
attribute: '质量控制机制',
score: 0.88,
createdAt: '2026-03-10T15:35',
selected: false
},
{
id: 5,
type: 'Experience',
content: '任务执行应采用「搜索→分析→输出」的递进式流程避免无效迭代和空转。纯文字生成的重复迭代应压缩或合并确认性回复应并入上一次响应。简单任务应在1-2次迭代内完成避免模型陷入重复思考或无意义的自我确认。',
subject: '迭代效率',
attribute: '错误教训',
score: 0.85,
createdAt: '2026-03-10T12:34',
selected: false
},
{
id: 6,
type: 'Experience',
content: '对于代码生成或文件写入类任务,应要求模型一次性完整输出或按模块批量输出,避免分批次的小幅输出导致迭代次数过多、执行效率低下。',
subject: '代码生成策略',
attribute: '错误教训',
score: 0.80,
createdAt: '2026-03-10T12:34',
selected: false
},
])
// 搜索和筛选
const searchQuery = ref('')
const filterType = ref('All Types')
// 统计数据
const stats = computed(() => ({
total: memories.value.length,
avgScore: (memories.value.reduce((sum, m) => sum + m.score, 0) / memories.value.length).toFixed(2),
experience: memories.value.filter(m => m.type === 'Experience').length,
lessons: memories.value.filter(m => m.type === 'Lessons').length,
}))
// 过滤后的记忆
const filteredMemories = computed(() => {
return memories.value.filter(m => {
const matchSearch = searchQuery.value === '' ||
m.content.includes(searchQuery.value) ||
m.subject.includes(searchQuery.value) ||
m.attribute.includes(searchQuery.value)
const matchType = filterType.value === 'All Types' || m.type === filterType.value
return matchSearch && matchType
})
})
// 切换选中状态
const toggleSelect = (id: number) => {
const memory = memories.value.find(m => m.id === id)
if (memory) {
memory.selected = !memory.selected
}
}
// 全选
const selectAll = ref(false)
const toggleSelectAll = () => {
selectAll.value = !selectAll.value
memories.value.forEach(m => m.selected = selectAll.value)
}
// 删除记忆
const deleteMemory = (id: number) => {
memories.value = memories.value.filter(m => m.id !== id)
}
// 编辑记忆
const editMemory = (id: number) => {
console.log('Edit memory:', id)
}
// 刷新
const refresh = () => {
console.log('Refresh')
}
// LLM 智能审查
const llmReview = () => {
console.log('LLM Review')
}
// 获取分数颜色
const getScoreColor = (score: number) => {
if (score >= 0.9) return 'text-emerald-400'
if (score >= 0.7) return 'text-amber-400'
return 'text-red-400'
}
</script>
<template>
<div class="min-h-screen bg-[#121212] text-gray-200 p-6">
<!-- 顶部标题 -->
<div class="flex items-center gap-2 mb-6">
<i class="fa-solid fa-brain text-orange-500"></i>
<span class="font-medium">Memory</span>
</div>
<!-- 统计卡片区域 -->
<div class="grid grid-cols-4 gap-4 mb-6">
<div class="bg-[#1e1e1e] rounded-xl p-5 text-center">
<div class="text-3xl font-bold text-white mb-1">{{ stats.total }}</div>
<div class="text-sm text-gray-400">Total Memories</div>
</div>
<div class="bg-[#1e1e1e] rounded-xl p-5 text-center">
<div class="text-3xl font-bold text-white mb-1">{{ stats.avgScore }}</div>
<div class="text-sm text-gray-400">Avg Score</div>
</div>
<div class="bg-[#1e1e1e] rounded-xl p-5 text-center">
<div class="text-3xl font-bold text-cyan-400 mb-1">{{ stats.experience }}</div>
<div class="text-sm text-gray-400">Experience</div>
</div>
<div class="bg-[#1e1e1e] rounded-xl p-5 text-center">
<div class="text-3xl font-bold text-red-400 mb-1">{{ stats.lessons }}</div>
<div class="text-sm text-gray-400">Lessons</div>
</div>
</div>
<!-- 搜索栏 -->
<div class="mb-4">
<div class="relative">
<i class="fa-solid fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input
v-model="searchQuery"
type="text"
placeholder="Search memories..."
class="w-full bg-dark-600 border border-dark-500 rounded-lg py-2 pl-10 pr-4 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange"
>
</div>
</div>
<!-- 筛选与操作栏 -->
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-3">
<el-select v-model="filterType" placeholder="Select" class="w-40" size="large" popper-class="dark-select-dropdown">
<el-option label="All Types" value="All Types" />
<el-option label="Experience" value="Experience" />
<el-option label="Lessons" value="Lessons" />
</el-select>
<button class="flex items-center space-x-2 bg-[#1e1e1e] border border-gray-700 rounded-lg py-2 px-4 text-gray-200 hover:bg-[#2a2a2a]">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
<span>Refresh</span>
</button>
<button class="flex items-center space-x-2 bg-orange-500 rounded-lg py-2 px-4 text-white hover:bg-orange-400">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
</svg>
<span>LLM Review</span>
</button>
</div>
</div>
<!-- 表格区域 -->
<div class="bg-dark-700 rounded-xl overflow-hidden">
<table class="w-full">
<thead class="bg-dark-600">
<tr>
<th class="w-10 px-5 py-3 text-left text-sm font-medium text-gray-400">
<input
type="checkbox"
v-model="selectAll"
@change="toggleSelectAll"
class="rounded bg-dark-600 border-dark-500"
>
</th>
<th class="px-5 py-3 text-left text-sm font-medium text-gray-400">Type</th>
<th class="px-5 py-3 text-left text-sm font-medium text-gray-400">Content</th>
<th class="px-5 py-3 text-left text-sm font-medium text-gray-400">Score</th>
<th class="px-5 py-3 text-left text-sm font-medium text-gray-400">Created</th>
<th class="px-5 py-3 text-center text-sm font-medium text-gray-400">Actions</th>
</tr>
</thead>
<tbody>
<tr
v-for="memory in filteredMemories"
:key="memory.id"
class="table-row"
>
<td class="px-5 py-4">
<input
type="checkbox"
:checked="memory.selected"
@change="toggleSelect(memory.id)"
class="rounded bg-dark-600 border-dark-500"
>
</td>
<td class="px-5 py-4">
<span class="px-2 py-1 bg-cyan-900/30 text-cyan-400 text-xs rounded-full">{{ memory.type }}</span>
</td>
<td class="px-5 py-4 text-sm text-gray-300 max-w-xl">
<div class="line-clamp-2">{{ memory.content }}</div>
<div class="text-xs text-gray-500 mt-1">Subject: {{ memory.subject }} · Attribute: {{ memory.attribute }}</div>
</td>
<td class="px-5 py-4">
<span :class="['font-medium', getScoreColor(memory.score)]">{{ memory.score }}</span>
</td>
<td class="px-5 py-4 text-sm text-gray-400">{{ formatDate(memory.createdAt, 'YYYY/MM/DD HH:mm') }}</td>
<td class="px-5 py-4">
<div class="flex items-center justify-center gap-2">
<button
@click="editMemory(memory.id)"
class="btn-icon"
>
<i class="fa-solid fa-pen text-gray-400 hover:text-white"></i>
</button>
<button
@click="deleteMemory(memory.id)"
class="btn-icon"
>
<i class="fa-solid fa-trash text-gray-400 hover:text-red-400"></i>
</button>
</div>
</td>
</tr>
</tbody>
</table>
<!-- 空状态 -->
<div v-if="filteredMemories.length === 0" class="py-12 text-center text-gray-500">
<i class="fa-solid fa-brain text-3xl mb-2"></i>
<p>No memories found</p>
</div>
</div>
</div>
</template>
<style scoped>
/* 自定义滚动条 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #1a1a1a;
}
::-webkit-scrollbar-thumb {
background: #333;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #444;
}
/* 行高限制 */
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>