import { CheckpointRef, CommandId, CorrelationId, EventId, MessageId, ProjectId, ThreadId, TurnId, WorkUnitId,} from "@t3tools/contracts";import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import { Effect, Layer, ManagedRuntime } from "effect";import fs from "node:fs";import os from "node:os";import path from "node:path";import * as SqlClient from "effect/unstable/sql/SqlClient"; import { OrchestrationCommandReceiptRepositoryLive } from "../../persistence/Layers/OrchestrationCommandReceipts.ts";import { OrchestrationEventStoreLive } from "../../persistence/Layers/OrchestrationEventStore.ts";import { makeSqlitePersistenceLive, SqlitePersistenceMemory,} from "../../persistence/Layers/Sqlite.ts";import { OrchestrationEventStore } from "../../persistence/Services/OrchestrationEventStore.ts";import { OrchestrationEngineLive } from "./OrchestrationEngine.ts";import { ORCHESTRATION_PROJECTOR_NAMES, OrchestrationProjectionPipelineLive,} from "./ProjectionPipeline.ts";import { OrchestrationEngineService } from "../Services/OrchestrationEngine.ts";import { OrchestrationProjectionPipeline } from "../Services/ProjectionPipeline.ts";import { ServerConfig } from "../../config.ts"; const makeProjectionPipelineTestLayer = (stateDir: string) => OrchestrationProjectionPipelineLive.pipe( Layer.provideMerge(OrchestrationEventStoreLive), Layer.provideMerge(ServerConfig.layerTest(process.cwd(), stateDir)), Layer.provideMerge(SqlitePersistenceMemory), Layer.provideMerge(NodeServices.layer), ); const runWithProjectionPipelineLayer = <A, E>( stateDir: string, effect: Effect.Effect< A, E, OrchestrationProjectionPipeline | OrchestrationEventStore | SqlClient.SqlClient >,) => Effect.acquireUseRelease( Effect.sync(() => ManagedRuntime.make(makeProjectionPipelineTestLayer(stateDir))), (runtime) => Effect.promise(() => runtime.runPromise(effect)), (runtime) => Effect.promise(() => runtime.dispose()), ); const projectionLayer = it.layer(makeProjectionPipelineTestLayer(process.cwd())); projectionLayer("OrchestrationProjectionPipeline", (it) => { it.effect("bootstraps all projection states and writes projection rows", () => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "project.created", eventId: EventId.makeUnsafe("evt-1"), aggregateKind: "project", aggregateId: ProjectId.makeUnsafe("project-1"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-1"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-1"), metadata: {}, payload: { projectId: ProjectId.makeUnsafe("project-1"), title: "Project 1", workspaceRoot: "/tmp/project-1", defaultModel: null, scripts: [], createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.created", eventId: EventId.makeUnsafe("evt-2"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-1"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-2"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-2"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-1"), projectId: ProjectId.makeUnsafe("project-1"), title: "Thread 1", model: "gpt-5-codex", runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.message-sent", eventId: EventId.makeUnsafe("evt-3"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-1"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-3"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-3"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-1"), messageId: MessageId.makeUnsafe("message-1"), role: "assistant", text: "hello", turnId: null, streaming: false, createdAt: now, updatedAt: now, }, }); yield* projectionPipeline.bootstrap; const projectRows = yield* sql<{ readonly projectId: string; readonly title: string; readonly scriptsJson: string; }>` SELECT project_id AS "projectId", title, scripts_json AS "scriptsJson" FROM projection_projects `; assert.deepEqual(projectRows, [ { projectId: "project-1", title: "Project 1", scriptsJson: "[]" }, ]); const messageRows = yield* sql<{ readonly messageId: string; readonly text: string; }>` SELECT message_id AS "messageId", text FROM projection_thread_messages `; assert.deepEqual(messageRows, [{ messageId: "message-1", text: "hello" }]); const stateRows = yield* sql<{ readonly projector: string; readonly lastAppliedSequence: number; }>` SELECT projector, last_applied_sequence AS "lastAppliedSequence" FROM projection_state ORDER BY projector ASC `; assert.equal(stateRows.length, Object.keys(ORCHESTRATION_PROJECTOR_NAMES).length); for (const row of stateRows) { assert.equal(row.lastAppliedSequence, 3); } }), ); it.effect("projects work units and activity work-unit links", () => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "thread.created", eventId: EventId.makeUnsafe("evt-work-unit-thread"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-work-unit"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-work-unit-thread"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-work-unit-thread"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-work-unit"), projectId: ProjectId.makeUnsafe("project-1"), title: "Thread work unit", model: "gpt-5-codex", runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.work-unit-upserted", eventId: EventId.makeUnsafe("evt-work-unit-upsert"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-work-unit"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-work-unit-upsert"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-work-unit-upsert"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-work-unit"), workUnit: { id: WorkUnitId.makeUnsafe("wu:thread-work-unit:turn:turn-1:root"), turnId: TurnId.makeUnsafe("turn-1"), parentWorkUnitId: null, kind: "primary_agent", state: "running", title: "Primary agent", detail: null, spawnedByActivityId: null, providerRefs: { providerTurnId: "provider-turn-1", }, startedAt: now, updatedAt: now, completedAt: null, }, }, }); yield* eventStore.append({ type: "thread.activity-appended", eventId: EventId.makeUnsafe("evt-work-unit-activity"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-work-unit"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-work-unit-activity"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-work-unit-activity"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-work-unit"), activity: { id: EventId.makeUnsafe("activity-work-unit"), tone: "info", kind: "task.progress", summary: "Reasoning update", payload: { detail: "Looking around", }, turnId: TurnId.makeUnsafe("turn-1"), workUnitId: WorkUnitId.makeUnsafe("wu:thread-work-unit:turn:turn-1:root"), createdAt: now, }, }, }); yield* projectionPipeline.bootstrap; const workUnitRows = yield* sql<{ readonly workUnitId: string; readonly turnId: string; readonly state: string; readonly providerRefsJson: string | null; }>` SELECT work_unit_id AS "workUnitId", turn_id AS "turnId", state, provider_refs_json AS "providerRefsJson" FROM projection_thread_work_units WHERE thread_id = 'thread-work-unit' `; assert.deepEqual(workUnitRows, [ { workUnitId: "wu:thread-work-unit:turn:turn-1:root", turnId: "turn-1", state: "running", providerRefsJson: '{"providerTurnId":"provider-turn-1"}', }, ]); const activityRows = yield* sql<{ readonly activityId: string; readonly workUnitId: string | null; }>` SELECT activity_id AS "activityId", work_unit_id AS "workUnitId" FROM projection_thread_activities WHERE thread_id = 'thread-work-unit' `; assert.deepEqual(activityRows, [ { activityId: "activity-work-unit", workUnitId: "wu:thread-work-unit:turn:turn-1:root", }, ]); }), ); it.effect("stores message attachment references without mutating payloads", () => Effect.sync(() => fs.mkdtempSync(path.join(os.tmpdir(), "t3-projection-attachments-"))).pipe( Effect.flatMap((stateDir) => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "thread.message-sent", eventId: EventId.makeUnsafe("evt-attachments"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-attachments"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-attachments"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-attachments"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-attachments"), messageId: MessageId.makeUnsafe("message-attachments"), role: "user", text: "Inspect this", attachments: [ { type: "image", id: "thread-attachments-att-1", name: "example.png", mimeType: "image/png", sizeBytes: 5, }, ], turnId: null, streaming: false, createdAt: now, updatedAt: now, }, }); yield* projectionPipeline.bootstrap; const rows = yield* sql<{ readonly attachmentsJson: string | null; }>` SELECT attachments_json AS "attachmentsJson" FROM projection_thread_messages WHERE message_id = 'message-attachments' `; assert.equal(rows.length, 1); assert.deepEqual(JSON.parse(rows[0]?.attachmentsJson ?? "null"), [ { type: "image", id: "thread-attachments-att-1", name: "example.png", mimeType: "image/png", sizeBytes: 5, }, ]); }).pipe( (effect) => runWithProjectionPipelineLayer(stateDir, effect), Effect.ensuring(Effect.sync(() => fs.rmSync(stateDir, { recursive: true, force: true }))), ), ), ), ); it.effect("preserves mixed image attachment metadata as-is", () => Effect.sync(() => fs.mkdtempSync(path.join(os.tmpdir(), "t3-projection-attachments-"))).pipe( Effect.flatMap((stateDir) => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "thread.message-sent", eventId: EventId.makeUnsafe("evt-attachments-safe"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-attachments-safe"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-attachments-safe"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-attachments-safe"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-attachments-safe"), messageId: MessageId.makeUnsafe("message-attachments-safe"), role: "user", text: "Inspect this", attachments: [ { type: "image", id: "thread-attachments-safe-att-1", name: "untrusted.exe", mimeType: "image/x-unknown", sizeBytes: 5, }, { type: "image", id: "thread-attachments-safe-att-2", name: "not-image.png", mimeType: "image/png", sizeBytes: 5, }, ], turnId: null, streaming: false, createdAt: now, updatedAt: now, }, }); yield* projectionPipeline.bootstrap; const rows = yield* sql<{ readonly attachmentsJson: string | null; }>` SELECT attachments_json AS "attachmentsJson" FROM projection_thread_messages WHERE message_id = 'message-attachments-safe' `; assert.equal(rows.length, 1); assert.deepEqual(JSON.parse(rows[0]?.attachmentsJson ?? "null"), [ { type: "image", id: "thread-attachments-safe-att-1", name: "untrusted.exe", mimeType: "image/x-unknown", sizeBytes: 5, }, { type: "image", id: "thread-attachments-safe-att-2", name: "not-image.png", mimeType: "image/png", sizeBytes: 5, }, ]); }).pipe( (effect) => runWithProjectionPipelineLayer(stateDir, effect), Effect.ensuring(Effect.sync(() => fs.rmSync(stateDir, { recursive: true, force: true }))), ), ), ), ); it.effect( "passes explicit empty attachment arrays through the projection pipeline to clear attachments", () => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); const later = new Date(Date.now() + 1_000).toISOString(); yield* eventStore.append({ type: "project.created", eventId: EventId.makeUnsafe("evt-clear-attachments-1"), aggregateKind: "project", aggregateId: ProjectId.makeUnsafe("project-clear-attachments"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-clear-attachments-1"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-clear-attachments-1"), metadata: {}, payload: { projectId: ProjectId.makeUnsafe("project-clear-attachments"), title: "Project Clear Attachments", workspaceRoot: "/tmp/project-clear-attachments", defaultModel: null, scripts: [], createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.created", eventId: EventId.makeUnsafe("evt-clear-attachments-2"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-clear-attachments"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-clear-attachments-2"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-clear-attachments-2"),Lines 1–500 of 2073. Load more
import { CheckpointRef, CommandId, CorrelationId, EventId, MessageId, ProjectId, ThreadId, TurnId, WorkUnitId, } from "@t3tools/contracts"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; import { Effect, Layer, ManagedRuntime } from "effect"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import * as SqlClient from "effect/unstable/sql/SqlClient"; import { OrchestrationCommandReceiptRepositoryLive } from "../../persistence/Layers/OrchestrationCommandReceipts.ts"; import { OrchestrationEventStoreLive } from "../../persistence/Layers/OrchestrationEventStore.ts"; import { makeSqlitePersistenceLive, SqlitePersistenceMemory, } from "../../persistence/Layers/Sqlite.ts"; import { OrchestrationEventStore } from "../../persistence/Services/OrchestrationEventStore.ts"; import { OrchestrationEngineLive } from "./OrchestrationEngine.ts"; import { ORCHESTRATION_PROJECTOR_NAMES, OrchestrationProjectionPipelineLive, } from "./ProjectionPipeline.ts"; import { OrchestrationEngineService } from "../Services/OrchestrationEngine.ts"; import { OrchestrationProjectionPipeline } from "../Services/ProjectionPipeline.ts"; import { ServerConfig } from "../../config.ts"; const makeProjectionPipelineTestLayer = (stateDir: string) => OrchestrationProjectionPipelineLive.pipe( Layer.provideMerge(OrchestrationEventStoreLive), Layer.provideMerge(ServerConfig.layerTest(process.cwd(), stateDir)), Layer.provideMerge(SqlitePersistenceMemory), Layer.provideMerge(NodeServices.layer), ); const runWithProjectionPipelineLayer = <A, E>( stateDir: string, effect: Effect.Effect< A, E, OrchestrationProjectionPipeline | OrchestrationEventStore | SqlClient.SqlClient >, ) => Effect.acquireUseRelease( Effect.sync(() => ManagedRuntime.make(makeProjectionPipelineTestLayer(stateDir))), (runtime) => Effect.promise(() => runtime.runPromise(effect)), (runtime) => Effect.promise(() => runtime.dispose()), ); const projectionLayer = it.layer(makeProjectionPipelineTestLayer(process.cwd())); projectionLayer("OrchestrationProjectionPipeline", (it) => { it.effect("bootstraps all projection states and writes projection rows", () => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "project.created", eventId: EventId.makeUnsafe("evt-1"), aggregateKind: "project", aggregateId: ProjectId.makeUnsafe("project-1"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-1"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-1"), metadata: {}, payload: { projectId: ProjectId.makeUnsafe("project-1"), title: "Project 1", workspaceRoot: "/tmp/project-1", defaultModel: null, scripts: [], createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.created", eventId: EventId.makeUnsafe("evt-2"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-1"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-2"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-2"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-1"), projectId: ProjectId.makeUnsafe("project-1"), title: "Thread 1", model: "gpt-5-codex", runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.message-sent", eventId: EventId.makeUnsafe("evt-3"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-1"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-3"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-3"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-1"), messageId: MessageId.makeUnsafe("message-1"), role: "assistant", text: "hello", turnId: null, streaming: false, createdAt: now, updatedAt: now, }, }); yield* projectionPipeline.bootstrap; const projectRows = yield* sql<{ readonly projectId: string; readonly title: string; readonly scriptsJson: string; }>` SELECT project_id AS "projectId", title, scripts_json AS "scriptsJson" FROM projection_projects `; assert.deepEqual(projectRows, [ { projectId: "project-1", title: "Project 1", scriptsJson: "[]" }, ]); const messageRows = yield* sql<{ readonly messageId: string; readonly text: string; }>` SELECT message_id AS "messageId", text FROM projection_thread_messages `; assert.deepEqual(messageRows, [{ messageId: "message-1", text: "hello" }]); const stateRows = yield* sql<{ readonly projector: string; readonly lastAppliedSequence: number; }>` SELECT projector, last_applied_sequence AS "lastAppliedSequence" FROM projection_state ORDER BY projector ASC `; assert.equal(stateRows.length, Object.keys(ORCHESTRATION_PROJECTOR_NAMES).length); for (const row of stateRows) { assert.equal(row.lastAppliedSequence, 3); } }), ); it.effect("projects work units and activity work-unit links", () => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "thread.created", eventId: EventId.makeUnsafe("evt-work-unit-thread"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-work-unit"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-work-unit-thread"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-work-unit-thread"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-work-unit"), projectId: ProjectId.makeUnsafe("project-1"), title: "Thread work unit", model: "gpt-5-codex", runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.work-unit-upserted", eventId: EventId.makeUnsafe("evt-work-unit-upsert"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-work-unit"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-work-unit-upsert"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-work-unit-upsert"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-work-unit"), workUnit: { id: WorkUnitId.makeUnsafe("wu:thread-work-unit:turn:turn-1:root"), turnId: TurnId.makeUnsafe("turn-1"), parentWorkUnitId: null, kind: "primary_agent", state: "running", title: "Primary agent", detail: null, spawnedByActivityId: null, providerRefs: { providerTurnId: "provider-turn-1", }, startedAt: now, updatedAt: now, completedAt: null, }, }, }); yield* eventStore.append({ type: "thread.activity-appended", eventId: EventId.makeUnsafe("evt-work-unit-activity"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-work-unit"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-work-unit-activity"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-work-unit-activity"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-work-unit"), activity: { id: EventId.makeUnsafe("activity-work-unit"), tone: "info", kind: "task.progress", summary: "Reasoning update", payload: { detail: "Looking around", }, turnId: TurnId.makeUnsafe("turn-1"), workUnitId: WorkUnitId.makeUnsafe("wu:thread-work-unit:turn:turn-1:root"), createdAt: now, }, }, }); yield* projectionPipeline.bootstrap; const workUnitRows = yield* sql<{ readonly workUnitId: string; readonly turnId: string; readonly state: string; readonly providerRefsJson: string | null; }>` SELECT work_unit_id AS "workUnitId", turn_id AS "turnId", state, provider_refs_json AS "providerRefsJson" FROM projection_thread_work_units WHERE thread_id = 'thread-work-unit' `; assert.deepEqual(workUnitRows, [ { workUnitId: "wu:thread-work-unit:turn:turn-1:root", turnId: "turn-1", state: "running", providerRefsJson: '{"providerTurnId":"provider-turn-1"}', }, ]); const activityRows = yield* sql<{ readonly activityId: string; readonly workUnitId: string | null; }>` SELECT activity_id AS "activityId", work_unit_id AS "workUnitId" FROM projection_thread_activities WHERE thread_id = 'thread-work-unit' `; assert.deepEqual(activityRows, [ { activityId: "activity-work-unit", workUnitId: "wu:thread-work-unit:turn:turn-1:root", }, ]); }), ); it.effect("stores message attachment references without mutating payloads", () => Effect.sync(() => fs.mkdtempSync(path.join(os.tmpdir(), "t3-projection-attachments-"))).pipe( Effect.flatMap((stateDir) => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "thread.message-sent", eventId: EventId.makeUnsafe("evt-attachments"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-attachments"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-attachments"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-attachments"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-attachments"), messageId: MessageId.makeUnsafe("message-attachments"), role: "user", text: "Inspect this", attachments: [ { type: "image", id: "thread-attachments-att-1", name: "example.png", mimeType: "image/png", sizeBytes: 5, }, ], turnId: null, streaming: false, createdAt: now, updatedAt: now, }, }); yield* projectionPipeline.bootstrap; const rows = yield* sql<{ readonly attachmentsJson: string | null; }>` SELECT attachments_json AS "attachmentsJson" FROM projection_thread_messages WHERE message_id = 'message-attachments' `; assert.equal(rows.length, 1); assert.deepEqual(JSON.parse(rows[0]?.attachmentsJson ?? "null"), [ { type: "image", id: "thread-attachments-att-1", name: "example.png", mimeType: "image/png", sizeBytes: 5, }, ]); }).pipe( (effect) => runWithProjectionPipelineLayer(stateDir, effect), Effect.ensuring(Effect.sync(() => fs.rmSync(stateDir, { recursive: true, force: true }))), ), ), ), ); it.effect("preserves mixed image attachment metadata as-is", () => Effect.sync(() => fs.mkdtempSync(path.join(os.tmpdir(), "t3-projection-attachments-"))).pipe( Effect.flatMap((stateDir) => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); yield* eventStore.append({ type: "thread.message-sent", eventId: EventId.makeUnsafe("evt-attachments-safe"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-attachments-safe"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-attachments-safe"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-attachments-safe"), metadata: {}, payload: { threadId: ThreadId.makeUnsafe("thread-attachments-safe"), messageId: MessageId.makeUnsafe("message-attachments-safe"), role: "user", text: "Inspect this", attachments: [ { type: "image", id: "thread-attachments-safe-att-1", name: "untrusted.exe", mimeType: "image/x-unknown", sizeBytes: 5, }, { type: "image", id: "thread-attachments-safe-att-2", name: "not-image.png", mimeType: "image/png", sizeBytes: 5, }, ], turnId: null, streaming: false, createdAt: now, updatedAt: now, }, }); yield* projectionPipeline.bootstrap; const rows = yield* sql<{ readonly attachmentsJson: string | null; }>` SELECT attachments_json AS "attachmentsJson" FROM projection_thread_messages WHERE message_id = 'message-attachments-safe' `; assert.equal(rows.length, 1); assert.deepEqual(JSON.parse(rows[0]?.attachmentsJson ?? "null"), [ { type: "image", id: "thread-attachments-safe-att-1", name: "untrusted.exe", mimeType: "image/x-unknown", sizeBytes: 5, }, { type: "image", id: "thread-attachments-safe-att-2", name: "not-image.png", mimeType: "image/png", sizeBytes: 5, }, ]); }).pipe( (effect) => runWithProjectionPipelineLayer(stateDir, effect), Effect.ensuring(Effect.sync(() => fs.rmSync(stateDir, { recursive: true, force: true }))), ), ), ), ); it.effect( "passes explicit empty attachment arrays through the projection pipeline to clear attachments", () => Effect.gen(function* () { const projectionPipeline = yield* OrchestrationProjectionPipeline; const eventStore = yield* OrchestrationEventStore; const sql = yield* SqlClient.SqlClient; const now = new Date().toISOString(); const later = new Date(Date.now() + 1_000).toISOString(); yield* eventStore.append({ type: "project.created", eventId: EventId.makeUnsafe("evt-clear-attachments-1"), aggregateKind: "project", aggregateId: ProjectId.makeUnsafe("project-clear-attachments"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-clear-attachments-1"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-clear-attachments-1"), metadata: {}, payload: { projectId: ProjectId.makeUnsafe("project-clear-attachments"), title: "Project Clear Attachments", workspaceRoot: "/tmp/project-clear-attachments", defaultModel: null, scripts: [], createdAt: now, updatedAt: now, }, }); yield* eventStore.append({ type: "thread.created", eventId: EventId.makeUnsafe("evt-clear-attachments-2"), aggregateKind: "thread", aggregateId: ThreadId.makeUnsafe("thread-clear-attachments"), occurredAt: now, commandId: CommandId.makeUnsafe("cmd-clear-attachments-2"), causationEventId: null, correlationId: CommandId.makeUnsafe("cmd-clear-attachments-2"),