Browse Source

Refactor code structure for improved readability and maintainability

feat/agent-independence
npmrun 2 months ago
parent
commit
a10c0eb2e5
  1. 64
      app/components/agent/AgentDocumentDrawer.vue
  2. 42
      app/pages/agent-documents/[id].vue
  3. 11
      app/pages/agent-documents/index.vue
  4. BIN
      packages/drizzle-pkg/db.sqlite
  5. 1
      packages/drizzle-pkg/lib/schema/agent-document.ts
  6. 1
      packages/drizzle-pkg/migrations/0005_chunky_rick_jones.sql
  7. 2798
      packages/drizzle-pkg/migrations/meta/0005_snapshot.json
  8. 7
      packages/drizzle-pkg/migrations/meta/_journal.json
  9. 2
      server/api/agent-documents/[id].patch.ts
  10. 6
      server/service/agent-document/index.ts

64
app/components/agent/AgentDocumentDrawer.vue

@ -18,6 +18,7 @@ interface AgentDocumentItem {
type: 'memory' | 'document' type: 'memory' | 'document'
summary: string | null summary: string | null
tags: string[] tags: string[]
disabled: boolean
createdAt: string createdAt: string
updatedAt: string updatedAt: string
} }
@ -38,6 +39,7 @@ interface DocDetail {
summary: string | null summary: string | null
tags: string[] tags: string[]
agentId: number | null agentId: number | null
disabled: boolean
createdAt: string createdAt: string
updatedAt: string updatedAt: string
} }
@ -57,6 +59,25 @@ const searchQuery = ref('')
const scope = ref<'agent' | 'all'>('agent') const scope = ref<'agent' | 'all'>('agent')
const agents = ref<AgentItem[]>([]) const agents = ref<AgentItem[]>([])
const scopeSaving = ref(false) const scopeSaving = ref(false)
const toggling = ref(false)
async function toggleDisabled() {
if (!selectedDoc.value) return
toggling.value = true
try {
await request(`/api/agent-documents/${selectedDoc.value.id}`, {
method: 'PATCH',
body: { disabled: !selectedDoc.value.disabled },
})
$toast.success(selectedDoc.value.disabled ? '已启用' : '已禁用')
await openDetail(selectedDoc.value.id)
await fetchDocuments()
} catch (e: any) {
$toast.error(e?.data?.message || e?.message || '操作失败')
} finally {
toggling.value = false
}
}
async function fetchAgents() { async function fetchAgents() {
try { try {
@ -267,6 +288,7 @@ watch(() => props.show, (val) => {
<span class="type-badge" :class="item.type"> <span class="type-badge" :class="item.type">
{{ item.type === 'document' ? '文档' : '记忆' }} {{ item.type === 'document' ? '文档' : '记忆' }}
</span> </span>
<span v-if="item.type === 'memory' && item.disabled" class="disabled-badge">已禁用</span>
<span class="card-date">{{ new Date(item.updatedAt).toLocaleDateString('zh-CN') }}</span> <span class="card-date">{{ new Date(item.updatedAt).toLocaleDateString('zh-CN') }}</span>
<button <button
class="card-delete-btn" class="card-delete-btn"
@ -298,6 +320,14 @@ watch(() => props.show, (val) => {
<Icon name="lucide:trash-2" /> <Icon name="lucide:trash-2" />
<span>{{ deleting ? '删除中…' : '删除' }}</span> <span>{{ deleting ? '删除中…' : '删除' }}</span>
</button> </button>
<button
v-if="selectedDoc.type === 'memory'"
class="toggle-btn"
:disabled="toggling"
@click="toggleDisabled"
>
{{ toggling ? '处理中…' : (selectedDoc.disabled ? '启用' : '禁用') }}
</button>
<button class="close-btn" @click="emit('close')"> <button class="close-btn" @click="emit('close')">
<Icon name="lucide:x" /> <Icon name="lucide:x" />
</button> </button>
@ -310,6 +340,7 @@ watch(() => props.show, (val) => {
<span class="type-badge" :class="selectedDoc.type"> <span class="type-badge" :class="selectedDoc.type">
{{ selectedDoc.type === 'document' ? '文档' : '记忆' }} {{ selectedDoc.type === 'document' ? '文档' : '记忆' }}
</span> </span>
<span v-if="selectedDoc.type === 'memory' && selectedDoc.disabled" class="disabled-badge">已禁用</span>
<span class="detail-date"> <span class="detail-date">
{{ new Date(selectedDoc.updatedAt).toLocaleString('zh-CN') }} {{ new Date(selectedDoc.updatedAt).toLocaleString('zh-CN') }}
</span> </span>
@ -629,6 +660,39 @@ watch(() => props.show, (val) => {
color: #1a5276; color: #1a5276;
} }
.disabled-badge {
font-size: 10px;
padding: 2px 6px;
border-radius: 4px;
font-weight: 500;
background: #fde8e8;
color: #c0392b;
}
.toggle-btn {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 10px;
border: none;
background: none;
border-radius: 8px;
cursor: pointer;
color: var(--color-muted, #6c6a64);
font-size: 13px;
transition: all 0.15s;
}
.toggle-btn:hover:not(:disabled) {
background: var(--color-surface-soft, #efe9de);
color: var(--color-ink, #141413);
}
.toggle-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.card-date { .card-date {
font-size: 11px; font-size: 11px;
color: var(--color-muted, #b8b2a6); color: var(--color-muted, #b8b2a6);

42
app/pages/agent-documents/[id].vue

@ -17,6 +17,7 @@ interface AgentDocumentDetail {
tags: string[] tags: string[]
sessionId: string | null sessionId: string | null
agentId: number | null agentId: number | null
disabled: boolean
createdAt: string createdAt: string
updatedAt: string updatedAt: string
} }
@ -44,6 +45,24 @@ const confirmShow = ref(false)
const agents = ref<AgentItem[]>([]) const agents = ref<AgentItem[]>([])
const scopeSaving = ref(false) const scopeSaving = ref(false)
const toggling = ref(false)
async function toggleDisabled() {
if (!doc.value) return
toggling.value = true
try {
await request(`/api/agent-documents/${route.params.id}`, {
method: 'PATCH',
body: { disabled: !doc.value.disabled },
})
$toast.success(doc.value.disabled ? '已启用' : '已禁用')
await fetchDocument()
} catch (e: any) {
$toast.error(e?.data?.message || e?.message || '操作失败')
} finally {
toggling.value = false
}
}
async function fetchAgents() { async function fetchAgents() {
try { try {
@ -180,6 +199,14 @@ onMounted(() => {
<div class="detail-header"> <div class="detail-header">
<NuxtLink to="/agent-documents" class="back-link">← 返回列表</NuxtLink> <NuxtLink to="/agent-documents" class="back-link">← 返回列表</NuxtLink>
<div v-if="loggedIn" class="header-actions"> <div v-if="loggedIn" class="header-actions">
<button
v-if="doc.type === 'memory'"
class="action-btn"
:disabled="toggling"
@click="toggleDisabled"
>
{{ toggling ? '处理中…' : (doc.disabled ? '启用' : '禁用') }}
</button>
<button class="action-btn" @click="openEdit">编辑</button> <button class="action-btn" @click="openEdit">编辑</button>
<button class="action-btn danger" @click="confirmShow = true">删除</button> <button class="action-btn danger" @click="confirmShow = true">删除</button>
</div> </div>
@ -189,6 +216,7 @@ onMounted(() => {
<span class="type-badge" :class="doc.type"> <span class="type-badge" :class="doc.type">
{{ doc.type === 'document' ? '文档' : '记忆' }} {{ doc.type === 'document' ? '文档' : '记忆' }}
</span> </span>
<span v-if="doc.type === 'memory' && doc.disabled" class="disabled-badge">已禁用</span>
<span class="meta-date"> <span class="meta-date">
创建于 {{ new Date(doc.createdAt).toLocaleString('zh-CN') }} 创建于 {{ new Date(doc.createdAt).toLocaleString('zh-CN') }}
</span> </span>
@ -349,11 +377,25 @@ onMounted(() => {
color: #cc785c; color: #cc785c;
} }
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.action-btn.danger:hover { .action-btn.danger:hover {
border-color: #c64545; border-color: #c64545;
color: #c64545; color: #c64545;
} }
.disabled-badge {
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
background: #fde8e8;
color: #c0392b;
}
.detail-meta { .detail-meta {
display: flex; display: flex;
align-items: center; align-items: center;

11
app/pages/agent-documents/index.vue

@ -13,6 +13,7 @@ interface AgentDocumentItem {
type: 'memory' | 'document' type: 'memory' | 'document'
summary: string | null summary: string | null
tags: string[] tags: string[]
disabled: boolean
createdAt: string createdAt: string
updatedAt: string updatedAt: string
} }
@ -150,6 +151,7 @@ onMounted(() => {
<span class="type-badge" :class="item.type"> <span class="type-badge" :class="item.type">
{{ item.type === 'document' ? '文档' : '记忆' }} {{ item.type === 'document' ? '文档' : '记忆' }}
</span> </span>
<span v-if="item.type === 'memory' && item.disabled" class="disabled-badge">已禁用</span>
<span class="card-date">{{ new Date(item.updatedAt).toLocaleDateString('zh-CN') }}</span> <span class="card-date">{{ new Date(item.updatedAt).toLocaleDateString('zh-CN') }}</span>
<span v-if="item.tags && item.tags.length > 0" class="card-tags"> <span v-if="item.tags && item.tags.length > 0" class="card-tags">
<span v-for="tag in item.tags" :key="tag" class="tag-chip">{{ tag }}</span> <span v-for="tag in item.tags" :key="tag" class="tag-chip">{{ tag }}</span>
@ -340,6 +342,15 @@ onMounted(() => {
color: #1a5276; color: #1a5276;
} }
.disabled-badge {
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
background: #fde8e8;
color: #c0392b;
}
.card-date { .card-date {
font-size: 12px; font-size: 12px;
color: #b8b2a6; color: #b8b2a6;

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.

1
packages/drizzle-pkg/lib/schema/agent-document.ts

@ -17,6 +17,7 @@ export const agentDocuments = sqliteTable(
content: text("content").notNull(), content: text("content").notNull(),
summary: text("summary"), summary: text("summary"),
tags: text("tags"), tags: text("tags"),
disabled: integer("disabled", { mode: "boolean" }).notNull().default(false),
createdAt: integer("created_at", { mode: "timestamp_ms" }) createdAt: integer("created_at", { mode: "timestamp_ms" })
.defaultNow() .defaultNow()
.notNull(), .notNull(),

1
packages/drizzle-pkg/migrations/0005_chunky_rick_jones.sql

@ -0,0 +1 @@
ALTER TABLE `agent_documents` ADD `disabled` integer DEFAULT false NOT NULL;

2798
packages/drizzle-pkg/migrations/meta/0005_snapshot.json

File diff suppressed because it is too large

7
packages/drizzle-pkg/migrations/meta/_journal.json

@ -36,6 +36,13 @@
"when": 1786459321606, "when": 1786459321606,
"tag": "0004_public_dracula", "tag": "0004_public_dracula",
"breakpoints": true "breakpoints": true
},
{
"idx": 5,
"version": "6",
"when": 1786773570565,
"tag": "0005_chunky_rick_jones",
"breakpoints": true
} }
] ]
} }

2
server/api/agent-documents/[id].patch.ts

@ -9,6 +9,7 @@ const updateSchema = z.object({
content: z.string().max(50000).optional(), content: z.string().max(50000).optional(),
tags: z.array(z.string()).optional(), tags: z.array(z.string()).optional(),
agentSlug: z.string().nullable().optional(), agentSlug: z.string().nullable().optional(),
disabled: z.boolean().optional(),
}); });
export default defineWrappedResponseHandler(async (event) => { export default defineWrappedResponseHandler(async (event) => {
@ -36,6 +37,7 @@ export default defineWrappedResponseHandler(async (event) => {
content: body.content, content: body.content,
tags: body.tags, tags: body.tags,
agentId, agentId,
disabled: body.disabled,
}); });
if (!updated) return R.throwError(404, "文档不存在或无权访问", null); if (!updated) return R.throwError(404, "文档不存在或无权访问", null);

6
server/service/agent-document/index.ts

@ -25,6 +25,7 @@ export interface UpdateDocumentInput {
content?: string; content?: string;
tags?: string[] | null; tags?: string[] | null;
agentId?: number | null; agentId?: number | null;
disabled?: boolean;
} }
export interface ListDocumentsOptions { export interface ListDocumentsOptions {
@ -152,6 +153,7 @@ export async function listDocuments(
title: agentDocuments.title, title: agentDocuments.title,
summary: agentDocuments.summary, summary: agentDocuments.summary,
tags: agentDocuments.tags, tags: agentDocuments.tags,
disabled: agentDocuments.disabled,
createdAt: agentDocuments.createdAt, createdAt: agentDocuments.createdAt,
updatedAt: agentDocuments.updatedAt, updatedAt: agentDocuments.updatedAt,
}) })
@ -198,6 +200,9 @@ export async function updateDocument(
if (input.agentId !== undefined) { if (input.agentId !== undefined) {
updateData.agentId = input.agentId; updateData.agentId = input.agentId;
} }
if (input.disabled !== undefined) {
updateData.disabled = input.disabled;
}
if (Object.keys(updateData).length === 0) { if (Object.keys(updateData).length === 0) {
return existing; return existing;
@ -233,6 +238,7 @@ export async function getMemoryContext(
const conditions = [ const conditions = [
eq(agentDocuments.userId, userId), eq(agentDocuments.userId, userId),
eq(agentDocuments.type, "memory"), eq(agentDocuments.type, "memory"),
eq(agentDocuments.disabled, false),
]; ];
if (agentId !== undefined && agentId !== null) { if (agentId !== undefined && agentId !== null) {

Loading…
Cancel
Save