import { assert, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Exit from "effect/Exit";import * as Schema from "effect/Schema";import { CommandId, ProjectId, ThreadId } from "./baseSchemas.ts"; import { DEFAULT_PROVIDER_INTERACTION_MODE, DEFAULT_RUNTIME_MODE, type ChatImageAttachment, ClientOrchestrationCommand, ModelSelection, OrchestrationCommand, OrchestrationDispatchCommandError, OrchestrationEvent, OrchestrationGetFullThreadDiffInput, OrchestrationGetTurnDiffInput, OrchestrationLatestTurn, ProjectCreatedPayload, ProjectMetaUpdatedPayload, OrchestrationProposedPlan, OrchestrationSession, OrchestrationThread, OrchestrationThreadShell, ProjectCreateCommand, OrchestrationMessage, ThreadMessageSentPayload, ThreadMetaUpdatedPayload, ThreadLinkedPullRequest, ThreadTurnStartCommand, ThreadCreatedPayload, ThreadTurnDiff, ThreadTurnStartRequestedPayload, SnapShotAccessibility, isProviderSendTurnSupportedImageMimeType, PROVIDER_SEND_TURN_MAX_FILE_BYTES,} from "./orchestration.ts";import { ProviderInstanceId } from "./providerInstance.ts"; const decodeTurnDiffInput = Schema.decodeUnknownEffect(OrchestrationGetTurnDiffInput);const decodeFullThreadDiffInput = Schema.decodeUnknownEffect(OrchestrationGetFullThreadDiffInput);const decodeThreadTurnDiff = Schema.decodeUnknownEffect(ThreadTurnDiff);const decodeProjectCreateCommand = Schema.decodeUnknownEffect(ProjectCreateCommand);const decodeProjectCreatedPayload = Schema.decodeUnknownEffect(ProjectCreatedPayload);const decodeProjectMetaUpdatedPayload = Schema.decodeUnknownEffect(ProjectMetaUpdatedPayload);const decodeThreadTurnStartCommand = Schema.decodeUnknownEffect(ThreadTurnStartCommand);const decodeClientOrchestrationCommand = Schema.decodeUnknownEffect(ClientOrchestrationCommand);const decodeOrchestrationMessage = Schema.decodeUnknownEffect(OrchestrationMessage);const decodeThreadMessageSentPayload = Schema.decodeUnknownEffect(ThreadMessageSentPayload);const decodeThreadTurnStartRequestedPayload = Schema.decodeUnknownEffect( ThreadTurnStartRequestedPayload,);const decodeOrchestrationLatestTurn = Schema.decodeUnknownEffect(OrchestrationLatestTurn);const decodeOrchestrationProposedPlan = Schema.decodeUnknownEffect(OrchestrationProposedPlan);const decodeOrchestrationSession = Schema.decodeUnknownEffect(OrchestrationSession);const decodeOrchestrationThread = Schema.decodeUnknownEffect(OrchestrationThread);const decodeOrchestrationThreadShell = Schema.decodeUnknownEffect(OrchestrationThreadShell);const encodeThreadCreatedPayload = Schema.encodeEffect(ThreadCreatedPayload); function getOptionValue( options: ReadonlyArray<{ id: string; value: unknown }> | undefined, id: string,): unknown { return options?.find((option) => option.id === id)?.value;}const decodeThreadCreatedPayload = Schema.decodeUnknownEffect(ThreadCreatedPayload);const decodeOrchestrationCommand = Schema.decodeUnknownEffect(OrchestrationCommand);const decodeOrchestrationEvent = Schema.decodeUnknownEffect(OrchestrationEvent);const decodeThreadMetaUpdatedPayload = Schema.decodeUnknownEffect(ThreadMetaUpdatedPayload);const decodeDispatchCommandError = Schema.decodeUnknownEffect(OrchestrationDispatchCommandError);const decodeSnapShotAccessibility = Schema.decodeUnknownEffect(SnapShotAccessibility); it.effect("decodes a dispatch error after its bootstrap thread was deleted", () => Effect.gen(function* () { const error = yield* decodeDispatchCommandError({ _tag: "OrchestrationDispatchCommandError", message: "Failed to create worktree.", bootstrapThreadDisposition: "deleted", }); assert.strictEqual(error.bootstrapThreadDisposition, "deleted"); }),); it.effect("parses turn diff input when fromTurnCount <= toTurnCount", () => Effect.gen(function* () { const parsed = yield* decodeTurnDiffInput({ threadId: "thread-1", fromTurnCount: 1, toTurnCount: 2, }); assert.strictEqual(parsed.fromTurnCount, 1); assert.strictEqual(parsed.toTurnCount, 2); }),); it.effect("parses turn diff input with whitespace ignoring enabled", () => Effect.gen(function* () { const parsed = yield* decodeTurnDiffInput({ threadId: "thread-1", fromTurnCount: 1, toTurnCount: 2, ignoreWhitespace: true, }); assert.strictEqual(parsed.ignoreWhitespace, true); }),); it.effect("parses full thread diff input with whitespace ignoring enabled", () => Effect.gen(function* () { const parsed = yield* decodeFullThreadDiffInput({ threadId: "thread-1", toTurnCount: 2, ignoreWhitespace: true, }); assert.strictEqual(parsed.ignoreWhitespace, true); }),); it.effect("rejects turn diff input when fromTurnCount > toTurnCount", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeTurnDiffInput({ threadId: "thread-1", fromTurnCount: 3, toTurnCount: 2, }), ); assert.strictEqual(result._tag, "Failure"); }),); it.effect("rejects thread turn diff when fromTurnCount > toTurnCount", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeThreadTurnDiff({ threadId: "thread-1", fromTurnCount: 3, toTurnCount: 2, diff: "patch", }), ); assert.strictEqual(result._tag, "Failure"); }),); it.effect("trims branded ids and command string fields at decode boundaries", () => Effect.gen(function* () { const parsed = yield* decodeProjectCreateCommand({ type: "project.create", commandId: " cmd-1 ", projectId: " project-1 ", title: " Project Title ", workspaceRoot: " /tmp/workspace ", defaultModelSelection: { provider: "codex", model: " gpt-5.2 ", }, createdAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.commandId, "cmd-1"); assert.strictEqual(parsed.projectId, "project-1"); assert.strictEqual(parsed.title, "Project Title"); assert.strictEqual(parsed.workspaceRoot, "/tmp/workspace"); assert.strictEqual(parsed.createWorkspaceRootIfMissing, undefined); assert.deepStrictEqual(parsed.defaultModelSelection, { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.2", }); }),); it.effect("decodes project.create with createWorkspaceRootIfMissing enabled", () => Effect.gen(function* () { const parsed = yield* decodeProjectCreateCommand({ type: "project.create", commandId: "cmd-1", projectId: "project-1", title: "Project Title", workspaceRoot: "/tmp/workspace", createWorkspaceRootIfMissing: true, createdAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.createWorkspaceRootIfMissing, true); }),); it.effect("decodes historical project.created payloads with a default provider", () => Effect.gen(function* () { const parsed = yield* decodeProjectCreatedPayload({ projectId: "project-1", title: "Project Title", workspaceRoot: "/tmp/workspace", defaultModelSelection: { provider: "codex", model: "gpt-5.4", }, scripts: [], createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.defaultModelSelection?.instanceId, "codex"); }),); it.effect("decodes project.meta-updated payloads with explicit default provider", () => Effect.gen(function* () { const parsed = yield* decodeProjectMetaUpdatedPayload({ projectId: "project-1", defaultModelSelection: { provider: "claudeAgent", model: "claude-opus-4-6", }, updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.defaultModelSelection?.instanceId, "claudeAgent"); }),); it.effect("rejects command fields that become empty after trim", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeProjectCreateCommand({ type: "project.create", commandId: "cmd-1", projectId: "project-1", title: " ", workspaceRoot: "/tmp/workspace", createdAt: "2026-01-01T00:00:00.000Z", }), ); assert.strictEqual(result._tag, "Failure"); }),); it.effect("decodes thread.turn.start defaults for provider and runtime mode", () => Effect.gen(function* () { const parsed = yield* decodeThreadTurnStartCommand({ type: "thread.turn.start", commandId: "cmd-turn-1", threadId: "thread-1", message: { messageId: "msg-1", role: "user", text: "hello", attachments: [], }, createdAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.modelSelection, undefined); assert.strictEqual(parsed.runtimeMode, DEFAULT_RUNTIME_MODE); assert.strictEqual(parsed.interactionMode, DEFAULT_PROVIDER_INTERACTION_MODE); }),); it.effect("accepts inline images, uploaded images, and uploaded files from clients", () => Effect.gen(function* () { const command = yield* decodeClientOrchestrationCommand({ type: "thread.turn.start", commandId: "cmd-turn-attachments", threadId: "thread-1", message: { messageId: "msg-attachments", role: "user", text: "hello", attachments: [ { type: "image", name: "legacy.png", mimeType: "image/png", sizeBytes: 3, dataUrl: "data:image/png;base64,YWJj", }, { type: "image", id: "pending-00000000-0000-4000-8000-000000000001", name: "uploaded.png", mimeType: "image/png", sizeBytes: 3, }, { type: "file", id: "pending-00000000-0000-4000-8000-000000000002-pdf", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 3, }, ], }, runtimeMode: "full-access", interactionMode: "default", createdAt: "2026-01-01T00:00:00.000Z", }); if (command.type !== "thread.turn.start") { assert.fail(`Expected thread.turn.start, received ${command.type}.`); } assert.strictEqual(command.message.attachments.length, 3); assert.strictEqual("dataUrl" in command.message.attachments[0]!, true); assert.strictEqual("id" in command.message.attachments[1]!, true); assert.strictEqual(command.message.attachments[2]!.type, "file"); }),); // Attachments ride on persisted events and thread streams with no client// version negotiation. A type this build does not know must decode instead of// failing the whole message.it.effect("tolerates attachment types from newer builds when decoding messages", () => Effect.gen(function* () { const futureAttachment = { type: "somethingnew", id: "thread-1-00000000-0000-4000-8000-000000000003-glb", name: "scene.glb", mimeType: "model/gltf-binary", sizeBytes: 12, }; const message = yield* decodeOrchestrationMessage({ id: "message-1", role: "user", text: "look at this", attachments: [futureAttachment], turnId: null, streaming: false, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(message.attachments?.length, 1); assert.strictEqual(message.attachments?.[0]!.type, "somethingnew"); const payload = yield* decodeThreadMessageSentPayload({ threadId: "thread-1", messageId: "message-1", role: "user", text: "look at this", attachments: [futureAttachment], turnId: null, streaming: false, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(payload.attachments?.[0]!.type, "somethingnew"); }),); // The tolerant member must not catch malformed known attachments: a file over// the size cap or an image with a bad mime has to fail its own schema, not// slide through the open one with those constraints unchecked.it.effect("rejects malformed known attachment types instead of tolerating them", () => Effect.gen(function* () { const base = { id: "thread-1-00000000-0000-4000-8000-000000000003-pdf", name: "report.pdf", mimeType: "application/pdf", }; const decode = (attachment: unknown) => decodeOrchestrationMessage({ id: "message-1", role: "user", text: "look at this", attachments: [attachment], turnId: null, streaming: false, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); const oversizedFile = yield* Effect.exit( decode({ ...base, type: "file", sizeBytes: PROVIDER_SEND_TURN_MAX_FILE_BYTES + 1 }), ); assert.strictEqual(Exit.isFailure(oversizedFile), true); const badMimeImage = yield* Effect.exit( decode({ ...base, type: "image", mimeType: "application/pdf", sizeBytes: 12 }), ); assert.strictEqual(Exit.isFailure(badMimeImage), true); }),); it.effect("preserves window capture metadata in thread.turn.start", () => Effect.gen(function* () { const parsed = yield* decodeThreadTurnStartCommand({ type: "thread.turn.start", commandId: "cmd-snap-shot", threadId: "thread-1", message: { messageId: "msg-snap-shot", role: "user", text: "Review this window", attachments: [ { type: "image", id: "snap-shot-1", name: "editor.png", mimeType: "image/png", sizeBytes: 4, source: { kind: "snap-shot", capturedAt: "2026-08-24T11:00:00.000Z", appName: "Editor", windowTitle: "main.ts", accessibleText: "const answer = 42;", accessibility: { format: "element-tree", coordinateSpace: "captured-image", imageSize: { width: 800, height: 600 }, truncated: false, root: { role: "window", name: "main.ts", bounds: { x: 0, y: 0, width: 800, height: 600 }, children: [ { role: "text", value: "const answer = 42;", bounds: { x: 20, y: 40, width: 180, height: 20 }, children: [], }, ], }, }, appIdentifier: "com.example.editor", appIconDataUrl: "data:image/png;base64,iVBORw==", }, }, ], }, createdAt: "2026-08-24T11:00:00.000Z", }); const attachment = parsed.message.attachments[0]; assert.strictEqual(attachment?.type, "image"); assert.deepStrictEqual((attachment as ChatImageAttachment).source, { kind: "snap-shot", capturedAt: "2026-08-24T11:00:00.000Z", appName: "Editor", windowTitle: "main.ts", accessibleText: "const answer = 42;", accessibility: { format: "element-tree", coordinateSpace: "captured-image", imageSize: { width: 800, height: 600 }, truncated: false, root: { role: "window", name: "main.ts", bounds: { x: 0, y: 0, width: 800, height: 600 }, children: [ { role: "text", value: "const answer = 42;", bounds: { x: 20, y: 40, width: 180, height: 20 }, children: [], }, ], }, }, appIdentifier: "com.example.editor", appIconDataUrl: "data:image/png;base64,iVBORw==", }); }),); it.effect("rejects accessibility trees above the serialized payload limit", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeSnapShotAccessibility({ format: "element-tree", coordinateSpace: "captured-image", imageSize: { width: 800, height: 600 }, truncated: false, root: { role: "window", bounds: { x: 0, y: 0, width: 800, height: 600 }, children: Array.from({ length: 10 }, () => ({ role: "text", value: "x".repeat(8_000), bounds: null, children: [], })), }, }), ); assert.strictEqual(Exit.isFailure(result), true); }),); it.effect("preserves explicit provider and runtime mode in thread.turn.start", () => Effect.gen(function* () { const parsed = yield* decodeThreadTurnStartCommand({ type: "thread.turn.start", commandId: "cmd-turn-2", threadId: "thread-1", message: { messageId: "msg-2", role: "user", text: "hello", attachments: [],Lines 1–500 of 1516. Load more
import { assert, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; import * as Schema from "effect/Schema"; import { CommandId, ProjectId, ThreadId } from "./baseSchemas.ts"; import { DEFAULT_PROVIDER_INTERACTION_MODE, DEFAULT_RUNTIME_MODE, type ChatImageAttachment, ClientOrchestrationCommand, ModelSelection, OrchestrationCommand, OrchestrationDispatchCommandError, OrchestrationEvent, OrchestrationGetFullThreadDiffInput, OrchestrationGetTurnDiffInput, OrchestrationLatestTurn, ProjectCreatedPayload, ProjectMetaUpdatedPayload, OrchestrationProposedPlan, OrchestrationSession, OrchestrationThread, OrchestrationThreadShell, ProjectCreateCommand, OrchestrationMessage, ThreadMessageSentPayload, ThreadMetaUpdatedPayload, ThreadLinkedPullRequest, ThreadTurnStartCommand, ThreadCreatedPayload, ThreadTurnDiff, ThreadTurnStartRequestedPayload, SnapShotAccessibility, isProviderSendTurnSupportedImageMimeType, PROVIDER_SEND_TURN_MAX_FILE_BYTES, } from "./orchestration.ts"; import { ProviderInstanceId } from "./providerInstance.ts"; const decodeTurnDiffInput = Schema.decodeUnknownEffect(OrchestrationGetTurnDiffInput); const decodeFullThreadDiffInput = Schema.decodeUnknownEffect(OrchestrationGetFullThreadDiffInput); const decodeThreadTurnDiff = Schema.decodeUnknownEffect(ThreadTurnDiff); const decodeProjectCreateCommand = Schema.decodeUnknownEffect(ProjectCreateCommand); const decodeProjectCreatedPayload = Schema.decodeUnknownEffect(ProjectCreatedPayload); const decodeProjectMetaUpdatedPayload = Schema.decodeUnknownEffect(ProjectMetaUpdatedPayload); const decodeThreadTurnStartCommand = Schema.decodeUnknownEffect(ThreadTurnStartCommand); const decodeClientOrchestrationCommand = Schema.decodeUnknownEffect(ClientOrchestrationCommand); const decodeOrchestrationMessage = Schema.decodeUnknownEffect(OrchestrationMessage); const decodeThreadMessageSentPayload = Schema.decodeUnknownEffect(ThreadMessageSentPayload); const decodeThreadTurnStartRequestedPayload = Schema.decodeUnknownEffect( ThreadTurnStartRequestedPayload, ); const decodeOrchestrationLatestTurn = Schema.decodeUnknownEffect(OrchestrationLatestTurn); const decodeOrchestrationProposedPlan = Schema.decodeUnknownEffect(OrchestrationProposedPlan); const decodeOrchestrationSession = Schema.decodeUnknownEffect(OrchestrationSession); const decodeOrchestrationThread = Schema.decodeUnknownEffect(OrchestrationThread); const decodeOrchestrationThreadShell = Schema.decodeUnknownEffect(OrchestrationThreadShell); const encodeThreadCreatedPayload = Schema.encodeEffect(ThreadCreatedPayload); function getOptionValue( options: ReadonlyArray<{ id: string; value: unknown }> | undefined, id: string, ): unknown { return options?.find((option) => option.id === id)?.value; } const decodeThreadCreatedPayload = Schema.decodeUnknownEffect(ThreadCreatedPayload); const decodeOrchestrationCommand = Schema.decodeUnknownEffect(OrchestrationCommand); const decodeOrchestrationEvent = Schema.decodeUnknownEffect(OrchestrationEvent); const decodeThreadMetaUpdatedPayload = Schema.decodeUnknownEffect(ThreadMetaUpdatedPayload); const decodeDispatchCommandError = Schema.decodeUnknownEffect(OrchestrationDispatchCommandError); const decodeSnapShotAccessibility = Schema.decodeUnknownEffect(SnapShotAccessibility); it.effect("decodes a dispatch error after its bootstrap thread was deleted", () => Effect.gen(function* () { const error = yield* decodeDispatchCommandError({ _tag: "OrchestrationDispatchCommandError", message: "Failed to create worktree.", bootstrapThreadDisposition: "deleted", }); assert.strictEqual(error.bootstrapThreadDisposition, "deleted"); }), ); it.effect("parses turn diff input when fromTurnCount <= toTurnCount", () => Effect.gen(function* () { const parsed = yield* decodeTurnDiffInput({ threadId: "thread-1", fromTurnCount: 1, toTurnCount: 2, }); assert.strictEqual(parsed.fromTurnCount, 1); assert.strictEqual(parsed.toTurnCount, 2); }), ); it.effect("parses turn diff input with whitespace ignoring enabled", () => Effect.gen(function* () { const parsed = yield* decodeTurnDiffInput({ threadId: "thread-1", fromTurnCount: 1, toTurnCount: 2, ignoreWhitespace: true, }); assert.strictEqual(parsed.ignoreWhitespace, true); }), ); it.effect("parses full thread diff input with whitespace ignoring enabled", () => Effect.gen(function* () { const parsed = yield* decodeFullThreadDiffInput({ threadId: "thread-1", toTurnCount: 2, ignoreWhitespace: true, }); assert.strictEqual(parsed.ignoreWhitespace, true); }), ); it.effect("rejects turn diff input when fromTurnCount > toTurnCount", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeTurnDiffInput({ threadId: "thread-1", fromTurnCount: 3, toTurnCount: 2, }), ); assert.strictEqual(result._tag, "Failure"); }), ); it.effect("rejects thread turn diff when fromTurnCount > toTurnCount", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeThreadTurnDiff({ threadId: "thread-1", fromTurnCount: 3, toTurnCount: 2, diff: "patch", }), ); assert.strictEqual(result._tag, "Failure"); }), ); it.effect("trims branded ids and command string fields at decode boundaries", () => Effect.gen(function* () { const parsed = yield* decodeProjectCreateCommand({ type: "project.create", commandId: " cmd-1 ", projectId: " project-1 ", title: " Project Title ", workspaceRoot: " /tmp/workspace ", defaultModelSelection: { provider: "codex", model: " gpt-5.2 ", }, createdAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.commandId, "cmd-1"); assert.strictEqual(parsed.projectId, "project-1"); assert.strictEqual(parsed.title, "Project Title"); assert.strictEqual(parsed.workspaceRoot, "/tmp/workspace"); assert.strictEqual(parsed.createWorkspaceRootIfMissing, undefined); assert.deepStrictEqual(parsed.defaultModelSelection, { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.2", }); }), ); it.effect("decodes project.create with createWorkspaceRootIfMissing enabled", () => Effect.gen(function* () { const parsed = yield* decodeProjectCreateCommand({ type: "project.create", commandId: "cmd-1", projectId: "project-1", title: "Project Title", workspaceRoot: "/tmp/workspace", createWorkspaceRootIfMissing: true, createdAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.createWorkspaceRootIfMissing, true); }), ); it.effect("decodes historical project.created payloads with a default provider", () => Effect.gen(function* () { const parsed = yield* decodeProjectCreatedPayload({ projectId: "project-1", title: "Project Title", workspaceRoot: "/tmp/workspace", defaultModelSelection: { provider: "codex", model: "gpt-5.4", }, scripts: [], createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.defaultModelSelection?.instanceId, "codex"); }), ); it.effect("decodes project.meta-updated payloads with explicit default provider", () => Effect.gen(function* () { const parsed = yield* decodeProjectMetaUpdatedPayload({ projectId: "project-1", defaultModelSelection: { provider: "claudeAgent", model: "claude-opus-4-6", }, updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.defaultModelSelection?.instanceId, "claudeAgent"); }), ); it.effect("rejects command fields that become empty after trim", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeProjectCreateCommand({ type: "project.create", commandId: "cmd-1", projectId: "project-1", title: " ", workspaceRoot: "/tmp/workspace", createdAt: "2026-01-01T00:00:00.000Z", }), ); assert.strictEqual(result._tag, "Failure"); }), ); it.effect("decodes thread.turn.start defaults for provider and runtime mode", () => Effect.gen(function* () { const parsed = yield* decodeThreadTurnStartCommand({ type: "thread.turn.start", commandId: "cmd-turn-1", threadId: "thread-1", message: { messageId: "msg-1", role: "user", text: "hello", attachments: [], }, createdAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(parsed.modelSelection, undefined); assert.strictEqual(parsed.runtimeMode, DEFAULT_RUNTIME_MODE); assert.strictEqual(parsed.interactionMode, DEFAULT_PROVIDER_INTERACTION_MODE); }), ); it.effect("accepts inline images, uploaded images, and uploaded files from clients", () => Effect.gen(function* () { const command = yield* decodeClientOrchestrationCommand({ type: "thread.turn.start", commandId: "cmd-turn-attachments", threadId: "thread-1", message: { messageId: "msg-attachments", role: "user", text: "hello", attachments: [ { type: "image", name: "legacy.png", mimeType: "image/png", sizeBytes: 3, dataUrl: "data:image/png;base64,YWJj", }, { type: "image", id: "pending-00000000-0000-4000-8000-000000000001", name: "uploaded.png", mimeType: "image/png", sizeBytes: 3, }, { type: "file", id: "pending-00000000-0000-4000-8000-000000000002-pdf", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 3, }, ], }, runtimeMode: "full-access", interactionMode: "default", createdAt: "2026-01-01T00:00:00.000Z", }); if (command.type !== "thread.turn.start") { assert.fail(`Expected thread.turn.start, received ${command.type}.`); } assert.strictEqual(command.message.attachments.length, 3); assert.strictEqual("dataUrl" in command.message.attachments[0]!, true); assert.strictEqual("id" in command.message.attachments[1]!, true); assert.strictEqual(command.message.attachments[2]!.type, "file"); }), ); // Attachments ride on persisted events and thread streams with no client // version negotiation. A type this build does not know must decode instead of // failing the whole message. it.effect("tolerates attachment types from newer builds when decoding messages", () => Effect.gen(function* () { const futureAttachment = { type: "somethingnew", id: "thread-1-00000000-0000-4000-8000-000000000003-glb", name: "scene.glb", mimeType: "model/gltf-binary", sizeBytes: 12, }; const message = yield* decodeOrchestrationMessage({ id: "message-1", role: "user", text: "look at this", attachments: [futureAttachment], turnId: null, streaming: false, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(message.attachments?.length, 1); assert.strictEqual(message.attachments?.[0]!.type, "somethingnew"); const payload = yield* decodeThreadMessageSentPayload({ threadId: "thread-1", messageId: "message-1", role: "user", text: "look at this", attachments: [futureAttachment], turnId: null, streaming: false, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); assert.strictEqual(payload.attachments?.[0]!.type, "somethingnew"); }), ); // The tolerant member must not catch malformed known attachments: a file over // the size cap or an image with a bad mime has to fail its own schema, not // slide through the open one with those constraints unchecked. it.effect("rejects malformed known attachment types instead of tolerating them", () => Effect.gen(function* () { const base = { id: "thread-1-00000000-0000-4000-8000-000000000003-pdf", name: "report.pdf", mimeType: "application/pdf", }; const decode = (attachment: unknown) => decodeOrchestrationMessage({ id: "message-1", role: "user", text: "look at this", attachments: [attachment], turnId: null, streaming: false, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", }); const oversizedFile = yield* Effect.exit( decode({ ...base, type: "file", sizeBytes: PROVIDER_SEND_TURN_MAX_FILE_BYTES + 1 }), ); assert.strictEqual(Exit.isFailure(oversizedFile), true); const badMimeImage = yield* Effect.exit( decode({ ...base, type: "image", mimeType: "application/pdf", sizeBytes: 12 }), ); assert.strictEqual(Exit.isFailure(badMimeImage), true); }), ); it.effect("preserves window capture metadata in thread.turn.start", () => Effect.gen(function* () { const parsed = yield* decodeThreadTurnStartCommand({ type: "thread.turn.start", commandId: "cmd-snap-shot", threadId: "thread-1", message: { messageId: "msg-snap-shot", role: "user", text: "Review this window", attachments: [ { type: "image", id: "snap-shot-1", name: "editor.png", mimeType: "image/png", sizeBytes: 4, source: { kind: "snap-shot", capturedAt: "2026-08-24T11:00:00.000Z", appName: "Editor", windowTitle: "main.ts", accessibleText: "const answer = 42;", accessibility: { format: "element-tree", coordinateSpace: "captured-image", imageSize: { width: 800, height: 600 }, truncated: false, root: { role: "window", name: "main.ts", bounds: { x: 0, y: 0, width: 800, height: 600 }, children: [ { role: "text", value: "const answer = 42;", bounds: { x: 20, y: 40, width: 180, height: 20 }, children: [], }, ], }, }, appIdentifier: "com.example.editor", appIconDataUrl: "data:image/png;base64,iVBORw==", }, }, ], }, createdAt: "2026-08-24T11:00:00.000Z", }); const attachment = parsed.message.attachments[0]; assert.strictEqual(attachment?.type, "image"); assert.deepStrictEqual((attachment as ChatImageAttachment).source, { kind: "snap-shot", capturedAt: "2026-08-24T11:00:00.000Z", appName: "Editor", windowTitle: "main.ts", accessibleText: "const answer = 42;", accessibility: { format: "element-tree", coordinateSpace: "captured-image", imageSize: { width: 800, height: 600 }, truncated: false, root: { role: "window", name: "main.ts", bounds: { x: 0, y: 0, width: 800, height: 600 }, children: [ { role: "text", value: "const answer = 42;", bounds: { x: 20, y: 40, width: 180, height: 20 }, children: [], }, ], }, }, appIdentifier: "com.example.editor", appIconDataUrl: "data:image/png;base64,iVBORw==", }); }), ); it.effect("rejects accessibility trees above the serialized payload limit", () => Effect.gen(function* () { const result = yield* Effect.exit( decodeSnapShotAccessibility({ format: "element-tree", coordinateSpace: "captured-image", imageSize: { width: 800, height: 600 }, truncated: false, root: { role: "window", bounds: { x: 0, y: 0, width: 800, height: 600 }, children: Array.from({ length: 10 }, () => ({ role: "text", value: "x".repeat(8_000), bounds: null, children: [], })), }, }), ); assert.strictEqual(Exit.isFailure(result), true); }), ); it.effect("preserves explicit provider and runtime mode in thread.turn.start", () => Effect.gen(function* () { const parsed = yield* decodeThreadTurnStartCommand({ type: "thread.turn.start", commandId: "cmd-turn-2", threadId: "thread-1", message: { messageId: "msg-2", role: "user", text: "hello", attachments: [],