- Agents.vue: 大幅更新agent管理界面 - App.vue: 更新应用布局 - 各页面: 更新Account、Database、Knowledge、Memory、Script、Skill、Tools Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
311 lines
12 KiB
Vue
311 lines
12 KiB
Vue
<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>
|