feat(agent-memory): UI fuer Agent-Memories mit semantischer Suche — Modul 8/16
Check Cross-Plugin Imports / check (push) Has been cancelled

Drittes Modul via Phase-Q-Manifest-Architektur: Registrierung komplett
ueber das agent_memory-Plugin-Manifest (page_route /agent-memory +
menu_item, Brain-Icon) — routes/index.tsx unangetastet. Komponenten-Map
mit 40 Eintraegen.

Zusaetzlicher Fix: Sidebar-ICON_MAP um Brain, Store, Tags erweitert —
Marketplace (Store) und Tags zeigten bisher Fallback-Icons, weil die
Manifest-Icons nicht in der kuratierten Map standen.

Backend existierte vollstaendig (create mit Embedding, list mit
agent_id-Pflichtfilter + Typ + Pagination, semantische Suche via pgvector,
update mit Embedding-Regeneration, delete; agent_memory:read/write),
Frontend hatte 0% Abdeckung.

- api/agentMemory.ts: TanStack-Hooks (useAgentMemories mit
  enabled-Gating, useAgentMemorySearch, create/update/delete)
- pages/AgentMemory.tsx: Agent-Picker (Pflichtfeld — Backend filtert
  zwingend nach agent_id), Pick-Agent-Prompt, semantische Suche mit
  Relevanz-Score-Badges und Clear, Memory-Karten mit Typ-Badges
  (fact/context/pattern/instruction), Create/Edit-Dialog, Delete mit
  Confirm — Aktionen hinter agent_memory:write
- i18n agentMemory.* + nav.agentMemory de/en

Verifikation: Vitest 11/11 (Agent-Picker-Pflicht, Pick-Prompt, Badges,
Suche mit Score + Clear, Create/Edit prefilled, Delete mit+ohne Confirm,
Gating, Empty/Error) · tsc exit 0 · production build exit 0 ·
Backend-Regressionen (route-order, m5-miniapps) 10/10 · compileall
sauber · Manifest-Check OK.
This commit is contained in:
Agent Zero
2026-09-13 19:45:18 +02:00
parent e7b746809b
commit 24423b6802
8 changed files with 898 additions and 4 deletions
+124
View File
@@ -0,0 +1,124 @@
/**
* Agent Memory API client — persistent agent memories with pgvector
* semantic search.
*
* Backend: /api/v1/agent-memory (create, list, search, update, delete).
* Memories store facts, context, patterns and instructions for AI agents.
* Permissions: agent_memory:read (list/search) / agent_memory:write
* (create, update, delete).
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiGet, apiPost, apiPatch, apiDelete } from '@/api/client';
export interface AgentMemory {
id: string;
agent_id: string;
memory_type: string;
content: string;
owner_id: string | null;
created_at: string | null;
updated_at: string | null;
/** Similarity score — only set by semantic search results. */
score?: number;
}
export interface AgentMemoryListResponse {
items: AgentMemory[];
total: number;
}
export interface AgentMemoryCreatePayload {
agent_id: string;
memory_type: string;
content: string;
}
export interface AgentMemoryUpdatePayload {
content?: string;
memory_type?: string;
}
export interface AgentMemoryListParams {
agentId: string;
memoryType?: string;
page?: number;
pageSize?: number;
}
export interface AgentMemorySearchParams {
agentId: string;
query: string;
memoryType?: string;
limit?: number;
minScore?: number;
}
// ─── Query hooks ─────────────────────────────────────────────
export function useAgentMemories(params: AgentMemoryListParams) {
const searchParams = new URLSearchParams();
searchParams.set('agent_id', params.agentId);
if (params.memoryType) searchParams.set('memory_type', params.memoryType);
if (params.page) searchParams.set('page', String(params.page));
if (params.pageSize) searchParams.set('page_size', String(params.pageSize));
return useQuery<AgentMemoryListResponse>({
queryKey: ['agent-memories', params.agentId, params.memoryType, params.page, params.pageSize],
queryFn: () => apiGet<AgentMemoryListResponse>(`/agent-memory?${searchParams.toString()}`),
enabled: !!params.agentId,
});
}
export function useAgentMemorySearch(params: AgentMemorySearchParams) {
const searchParams = new URLSearchParams();
searchParams.set('agent_id', params.agentId);
searchParams.set('query', params.query);
if (params.memoryType) searchParams.set('memory_type', params.memoryType);
if (params.limit) searchParams.set('limit', String(params.limit));
if (params.minScore !== undefined) searchParams.set('min_score', String(params.minScore));
return useQuery<AgentMemoryListResponse>({
queryKey: ['agent-memories', 'search', params.agentId, params.query, params.memoryType],
queryFn: () => apiGet<AgentMemoryListResponse>(`/agent-memory/search?${searchParams.toString()}`),
enabled: !!params.agentId && !!params.query,
});
}
// ─── Mutation hooks ──────────────────────────────────────────
function useInvalidateMemories() {
const qc = useQueryClient();
return () => {
qc.invalidateQueries({ queryKey: ['agent-memories'] });
};
}
export function useCreateAgentMemory() {
const invalidate = useInvalidateMemories();
return useMutation<AgentMemory, Error, AgentMemoryCreatePayload>({
mutationFn: (data) => apiPost<AgentMemory>('/agent-memory', data),
onSuccess: invalidate,
});
}
export function useUpdateAgentMemory() {
const invalidate = useInvalidateMemories();
return useMutation<
AgentMemory,
Error,
{ memoryId: string; payload: AgentMemoryUpdatePayload }
>({
mutationFn: ({ memoryId, payload }) =>
apiPatch<AgentMemory>(`/agent-memory/${memoryId}`, payload),
onSuccess: invalidate,
});
}
export function useDeleteAgentMemory() {
const invalidate = useInvalidateMemories();
return useMutation<void, Error, string>({
mutationFn: (memoryId) => apiDelete(`/agent-memory/${memoryId}`),
onSuccess: invalidate,
});
}