import { describe, expect, it, mock } from "bun:test"; import { Type } from "@sinclair/typebox"; import { registerDocumentAITools } from "../documentAITools"; import { NoyaManager } from "../NoyaManager"; const schema = Type.Object({ title: Type.String(), items: Type.Array( Type.Object({ id: Type.String(), done: Type.Boolean(), }) ), }); const createManager = () => { const manager = new NoyaManager( { title: "Initial", items: [{ id: "one", done: false }], }, { schema } ); manager.multiplayerStateManager.connect(); return manager; }; describe("registerDocumentAITools", () => { it("keeps document tools opt-in", () => { expect(createManager().aiManager.callableTools).toEqual({}); const optedIn = new NoyaManager( { title: "Initial", items: [] }, { schema, registerDefaultAITools: true } ); expect(Object.keys(optedIn.aiManager.callableTools).sort()).toEqual([ "applyDocumentOperations", "readDocument", "runDocumentScript", ]); }); it("reads exact paths and returns the current hash", async () => { const manager = createManager(); registerDocumentAITools(manager); const response = await manager.aiManager.callTool({ id: "read", name: "readDocument", parameters: { path: ["items", 0, "done"] }, }); expect(JSON.parse(response!)).toEqual({ ok: true, path: ["items", 0, "done"], value: false, hash: manager.multiplayerStateManager.getOptimisticHash(), }); }); it("applies path operations atomically", async () => { const manager = createManager(); registerDocumentAITools(manager); const response = await manager.aiManager.callTool({ id: "edit", name: "applyDocumentOperations", parameters: { operations: [ { op: "set", path: ["title"], value: "Updated" }, { op: "add", path: ["items", 1], value: { id: "two", done: true }, }, ], summary: "Update the document", }, }); expect(JSON.parse(response!)).toMatchObject({ ok: true, operationCount: 2, }); expect(manager.multiplayerStateManager.getOptimisticState()).toEqual({ title: "Updated", items: [ { id: "one", done: false }, { id: "two", done: true }, ], }); }); it("rejects stale edits before applying them", async () => { const manager = createManager(); registerDocumentAITools(manager); const response = await manager.aiManager.callTool({ id: "stale-edit", name: "applyDocumentOperations", parameters: { operations: [{ op: "set", path: ["title"], value: "Updated" }], expectedHash: "stale", summary: "Update the title", }, }); expect(JSON.parse(response!)).toMatchObject({ ok: false, expectedHash: "stale", }); expect(manager.multiplayerStateManager.getOptimisticState().title).toBe( "Initial" ); }); it("diffs and applies isolated script results", async () => { const manager = createManager(); registerDocumentAITools(manager); manager.evalManager.evaluate = mock(async () => ({ title: "Scripted", items: [{ id: "one", done: true }], })); const response = await manager.aiManager.callTool({ id: "script", name: "runDocumentScript", parameters: { sourceCode: "function updateState(state) { state.title = 'Scripted'; }", summary: "Run a document update", }, }); expect(JSON.parse(response!)).toMatchObject({ ok: true, patchCount: 2, }); expect(manager.multiplayerStateManager.getOptimisticState()).toEqual({ title: "Scripted", items: [{ id: "one", done: true }], }); }); });