286 lines · 7.6 KB · TypeScript
RawDownload
import { describe, expect, it } from "vite-plus/test"; import type * as EffectAcpSchema from "effect-acp/schema"; import {  extractModelConfigId,  mergeToolCallState,  parsePermissionRequest,  parseSessionModeState,  parseSessionUpdateEvent,} from "./AcpRuntimeModel.ts"; describe("AcpRuntimeModel", () => {  it("parses session mode state from typed ACP session setup responses", () => {    const modeState = parseSessionModeState({      sessionId: "session-1",      modes: {        currentModeId: " code ",        availableModes: [          { id: " ask ", name: " Ask ", description: " Request approval " },          { id: " code ", name: " Code " },        ],      },      configOptions: [],    } satisfies EffectAcpSchema.NewSessionResponse);     expect(modeState).toEqual({      currentModeId: "code",      availableModes: [        { id: "ask", name: "Ask", description: "Request approval" },        { id: "code", name: "Code" },      ],    });  });   it("extracts the model config id from typed ACP config options", () => {    const modelConfigId = extractModelConfigId({      sessionId: "session-1",      configOptions: [        {          id: "approval",          name: "Approval Mode",          category: "permission",          type: "select",          currentValue: "ask",          options: [{ value: "ask", name: "Ask" }],        },        {          id: "model",          name: "Model",          category: "model",          type: "select",          currentValue: "default",          options: [{ value: "default", name: "Auto" }],        },      ],    } satisfies EffectAcpSchema.NewSessionResponse);     expect(modelConfigId).toBe("model");  });   it("projects typed ACP tool call updates into runtime events", () => {    const created = parseSessionUpdateEvent({      sessionId: "session-1",      update: {        sessionUpdate: "tool_call",        toolCallId: "tool-1",        title: "Terminal",        kind: "execute",        status: "pending",        rawInput: {          executable: "bun",          args: ["run", "typecheck"],        },        content: [          {            type: "content",            content: {              type: "text",              text: "Running checks",            },          },        ],      },    } satisfies EffectAcpSchema.SessionNotification);     expect(created.events).toEqual([      {        _tag: "ToolCallUpdated",        toolCall: {          toolCallId: "tool-1",          kind: "execute",          title: "Ran command",          status: "pending",          command: "bun run typecheck",          detail: "bun run typecheck",          data: {            toolCallId: "tool-1",            kind: "execute",            command: "bun run typecheck",            rawInput: {              executable: "bun",              args: ["run", "typecheck"],            },            content: [              {                type: "content",                content: {                  type: "text",                  text: "Running checks",                },              },            ],          },        },        rawPayload: {          sessionId: "session-1",          update: {            sessionUpdate: "tool_call",            toolCallId: "tool-1",            title: "Terminal",            kind: "execute",            status: "pending",            rawInput: {              executable: "bun",              args: ["run", "typecheck"],            },            content: [              {                type: "content",                content: {                  type: "text",                  text: "Running checks",                },              },            ],          },        },      },    ]);     const updated = parseSessionUpdateEvent({      sessionId: "session-1",      update: {        sessionUpdate: "tool_call_update",        toolCallId: "tool-1",        status: "completed",        rawOutput: { exitCode: 0 },      },    } satisfies EffectAcpSchema.SessionNotification);     expect(updated.events).toHaveLength(1);    expect(updated.events[0]?._tag).toBe("ToolCallUpdated");    const createdEvent = created.events[0];    const updatedEvent = updated.events[0];    if (createdEvent?._tag === "ToolCallUpdated" && updatedEvent?._tag === "ToolCallUpdated") {      expect(mergeToolCallState(createdEvent.toolCall, updatedEvent.toolCall)).toMatchObject({        toolCallId: "tool-1",        status: "completed",        title: "Ran command",        detail: "bun run typecheck",        command: "bun run typecheck",      });    }  });   it("trims padded current mode updates before emitting a mode change", () => {    const result = parseSessionUpdateEvent({      sessionId: "session-1",      update: {        sessionUpdate: "current_mode_update",        currentModeId: " code ",      },    } satisfies EffectAcpSchema.SessionNotification);     expect(result.modeId).toBe("code");    expect(result.events).toEqual([      {        _tag: "ModeChanged",        modeId: "code",      },    ]);  });   it("projects typed ACP plan and content updates", () => {    const planResult = parseSessionUpdateEvent({      sessionId: "session-1",      update: {        sessionUpdate: "plan",        entries: [          { content: " Inspect state ", priority: "high", status: "completed" },          { content: "", priority: "medium", status: "in_progress" },        ],      },    } satisfies EffectAcpSchema.SessionNotification);     expect(planResult.events).toEqual([      {        _tag: "PlanUpdated",        payload: {          plan: [            { step: "Inspect state", status: "completed" },            { step: "Step 2", status: "inProgress" },          ],        },        rawPayload: {          sessionId: "session-1",          update: {            sessionUpdate: "plan",            entries: [              { content: " Inspect state ", priority: "high", status: "completed" },              { content: "", priority: "medium", status: "in_progress" },            ],          },        },      },    ]);     const contentResult = parseSessionUpdateEvent({      sessionId: "session-1",      update: {        sessionUpdate: "agent_message_chunk",        content: {          type: "text",          text: "hello from acp",        },      },    } satisfies EffectAcpSchema.SessionNotification);     expect(contentResult.events).toEqual([      {        _tag: "ContentDelta",        text: "hello from acp",        rawPayload: {          sessionId: "session-1",          update: {            sessionUpdate: "agent_message_chunk",            content: {              type: "text",              text: "hello from acp",            },          },        },      },    ]);  });   it("keeps permission request parsing compatible with loose extension payloads", () => {    const request = parsePermissionRequest({      sessionId: "session-1",      options: [        {          optionId: "allow-once",          name: "Allow once",          kind: "allow_once",        },      ],      toolCall: {        toolCallId: "tool-1",        title: "`cat package.json`",        kind: "execute",        status: "pending",        content: [          {            type: "content",            content: {              type: "text",              text: "Not in allowlist",            },          },        ],      },    });     expect(request).toMatchObject({      kind: "execute",      detail: "cat package.json",      toolCall: {        toolCallId: "tool-1",        kind: "execute",        status: "pending",        command: "cat package.json",      },    });  });});