/** * AG-UI 状态同步示例 * * 展示 Agent 与前端的 Snapshot-Delta 状态同步模式 * * 参考文档: modules/events.md (行 1067-1155) * * 状态管理模式: * 1. StateSnapshot - 完整状态快照(初始同步/周期性刷新) * 2. StateDelta - 增量更新(JSON Patch RFC 6902) * 3. MessagesSnapshot - 消息历史快照 */ import { AbstractAgent, RunAgent, RunAgentInput, EventType, BaseEvent, } from "@ag-ui/client" import { Observable } from "rxjs" /** * Agent 状态定义示例 */ interface AgentState { user: { name: string preferences: { theme: "light" | "dark" language: string } } session: { currentPage: number itemsPerPage: number totalItems: number } formData?: { [key: string]: any } } class StateSyncAgent extends AbstractAgent { private state: AgentState = { user: { name: "Alice", preferences: { theme: "light", language: "en", }, }, session: { currentPage: 1, itemsPerPage: 10, totalItems: 100, }, } run(input: RunAgentInput): RunAgent { const { threadId, runId } = input return () => new Observable((observer) => { observer.next({ type: EventType.RUN_STARTED, threadId, runId, }) // 1. 发送初始状态快照 observer.next({ type: EventType.STATE_SNAPSHOT, snapshot: this.state, }) // 2. 发送消息历史快照 observer.next({ type: EventType.MESSAGES_SNAPSHOT, messages: [ { id: "msg_1", role: "user", content: "Show me page 2", }, { id: "msg_2", role: "assistant", content: "Loading page 2...", }, ], }) // 3. 模拟状态变化 - 分页更新 setTimeout(() => { // 发送 Delta 更新(JSON Patch 格式) observer.next({ type: EventType.STATE_DELTA, delta: [ { op: "replace", path: "/session/currentPage", value: 2 }, ], }) }, 500) // 4. 模拟用户偏好更新 setTimeout(() => { observer.next({ type: EventType.STATE_DELTA, delta: [ { op: "replace", path: "/user/preferences/theme", value: "dark" }, ], }) }, 1000) // 5. 添加新字段(表单数据) setTimeout(() => { observer.next({ type: EventType.STATE_DELTA, delta: [ { op: "add", path: "/formData", value: { searchQuery: "AG-UI tutorial", filters: ["beginner", "typescript"], }, }, ], }) }, 1500) // 6. 周期性完整快照(确保状态一致性) setTimeout(() => { const updatedState: AgentState = { ...this.state, session: { ...this.state.session, currentPage: 2, }, user: { ...this.state.user, preferences: { ...this.state.user.preferences, theme: "dark", }, }, formData: { searchQuery: "AG-UI tutorial", filters: ["beginner", "typescript"], }, } observer.next({ type: EventType.STATE_SNAPSHOT, snapshot: updatedState, }) observer.next({ type: EventType.RUN_FINISHED, threadId, runId, }) observer.complete() }, 2000) }) } } /** * 前端状态管理示例(接收端) */ class StateManager { private state: AgentState | null = null handleEvent(event: BaseEvent) { switch (event.type) { case EventType.STATE_SNAPSHOT: // 完整替换状态 this.state = (event as any).snapshot as AgentState console.log("[State] Snapshot received:", this.state) break case EventType.STATE_DELTA: // 应用 JSON Patch 增量更新 if (this.state) { const patches = (event as any).delta this.state = this.applyPatches(this.state, patches) console.log("[State] Delta applied:", patches) console.log("[State] Current state:", this.state) } break case EventType.MESSAGES_SNAPSHOT: console.log("[Messages] Snapshot:", (event as any).messages) break } } /** * 应用 JSON Patch 操作(简化实现) * 生产环境应使用 json-patch 库 */ private applyPatches(state: AgentState, patches: any[]): AgentState { const newState = JSON.parse(JSON.stringify(state)) for (const patch of patches) { const { op, path, value } = patch const pathParts = path.split("/").filter(Boolean) let target: any = newState // 导航到目标对象的父级 for (let i = 0; i < pathParts.length - 1; i++) { target = target[pathParts[i]] } const lastKey = pathParts[pathParts.length - 1] switch (op) { case "replace": target[lastKey] = value break case "add": target[lastKey] = value break case "remove": delete target[lastKey] break } } return newState } } // 使用示例 const agent = new StateSyncAgent() const stateManager = new StateManager() agent .runAgent({ runId: "run_state_sync", threadId: "thread_123", messages: [], tools: [], context: [], }) .subscribe({ next: (event) => { stateManager.handleEvent(event) }, complete: () => console.log("\n[Complete] State sync demo finished"), }) export { StateSyncAgent, StateManager, AgentState }