1import { describe, expect, it } from "@effect/vitest";
2import * as Schema from "effect/Schema";
3
4import * as V1 from "./_generated/schema-v1.gen.ts";
5import * as V2 from "./schema.ts";
6
7describe("pinned ACP wire schemas", () => {
8 it("validates known content variants without accepting malformed ones as future content", () => {
9 const accepts = Schema.is(V2.ContentBlock);
10 expect(accepts({ type: "text", text: "hello" })).toBe(true);
11 expect(accepts({ type: "text" })).toBe(false);
12 expect(accepts({ type: "image", data: "aGVsbG8=" })).toBe(false);
13 expect(accepts({ type: "future_content", payload: { value: 1 } })).toBe(true);
14 });
15
16 it("decodes titled multi-select form fields in v1 and v2", () => {
17 const titled = (anyOf: ReadonlyArray<unknown>) => ({
18 sessionId: "session-1",
19 mode: "form",
20 message: "Pick areas",
21 requestedSchema: {
22 type: "object",
23 properties: { areas: { type: "array", minItems: 1, items: { anyOf } } },
24 required: ["areas"],
25 },
26 });
27 const form = titled([
28 { const: "api", title: "API", description: "Server routes" },
29 { const: "ui", title: "Interface" },
30 ]);
31 for (const request of [V1.CreateElicitationRequest, V2.CreateElicitationRequest]) {
32 expect(Schema.decodeUnknownSync(request)(form)).toEqual(form);
33 expect(Schema.is(request)(titled([{ const: "api" }]))).toBe(false);
34 }
35 });
36
37 it("keeps v1 command inputs compatible with native agents", () => {
38 const command = { name: "plan", description: "Make a plan", input: { hint: "Task" } };
39 const isAvailableCommand = Schema.is(V1.AvailableCommand);
40
41 expect(isAvailableCommand(command)).toBe(true);
42 const isAvailableCommand2 = Schema.is(V2.AvailableCommand);
43
44 expect(isAvailableCommand2({ ...command, input: { type: "text", hint: "Task" } })).toBe(true);
45 });
46});