@agentaily/agent-store
Agent 的状态 / 持久化层。可插拔的 seam + 对浏览器友好的默认实现,这样循环 (@agentaily/agent)与状态住在哪里保持解耦。
只依赖 @agentaily/llm(用它的 Message 线缆类型)。永不拉进 db 或 React —— 以保证它能安全地打进浏览器包。D1/fetch 后端的 store 是住在本包之外的适配器 (如 apps/web)。见 REFACTOR.md §8 / §8.1。
这里装着什么
| Seam | Interface | 默认实现 | 内置工具 |
|---|---|---|---|
| Skill | Skill | — | useSkillTool(skills) → use_skill |
| Memory | MemoryStore (MemoryEntry) | InMemoryStore、LocalStorageStore | rememberTool(memory) → remember |
| Conversation | ConversationStore (Conversation, ConversationRecord) | InMemoryConversationStore、LocalStorageConversationStore | — |
还导出内置工具返回时共用的 Tool / ToolResult 形状。
ConversationStore 对标 LangGraph 的 checkpointer / Agents SDK 的 SessionABC (list / create / load / append / remove),它的存在是为了给会话跨会话的持久化 —— 今天循环把 messages[] 攥在一个私有字段里,所以一刷新就丢了对话记录。
状态: conversation seam 在这里已经定义 + 实现 + 测试,但循环还没消费它 —— 把
messages挪到 store 背后(+ 重新水合)是下一个 PR。
用法
ts
import {
InMemoryStore, LocalStorageStore, rememberTool,
useSkillTool, type Skill,
InMemoryConversationStore, LocalStorageConversationStore, type ConversationStore,
} from '@agentaily/agent-store';
const memory = new LocalStorageStore(); // persists notes across browser sessions
const skills: Skill[] = [{ name: 'market', description: '…', instructions: '…' }];
const sessions: ConversationStore = new LocalStorageConversationStore();
const conv = await sessions.create({ title: 'New chat' });
await sessions.append(conv.id, [{ role: 'user', content: [{ type: 'text', text: 'hi' }] }]);
const { messages } = (await sessions.load(conv.id))!;向后兼容
Skill / useSkillTool / MemoryStore / MemoryEntry / InMemoryStore / rememberTool 以及 Tool / ToolResult 类型都从 @agentaily/agent re-export;LocalStorageStore 从 @agentaily/agent-ui re-export。从那些包来的现有 import 保持原样可用。
测试
sh
pnpm --filter @agentaily/agent-store test # vitest (node)
pnpm --filter @agentaily/agent-store typecheck