127 lines · 4.1 KB · TypeScript
RawDownload
import { ProjectId, ThreadId } from "@t3tools/contracts";import { assert, it } from "@effect/vitest";import { Effect, Layer, Option } from "effect";import * as SqlClient from "effect/unstable/sql/SqlClient"; import { SqlitePersistenceMemory } from "./Sqlite.ts";import { ProjectionProjectRepositoryLive } from "./ProjectionProjects.ts";import { ProjectionThreadRepositoryLive } from "./ProjectionThreads.ts";import { ProjectionProjectRepository } from "../Services/ProjectionProjects.ts";import { ProjectionThreadRepository } from "../Services/ProjectionThreads.ts"; const projectionRepositoriesLayer = it.layer(  Layer.mergeAll(    ProjectionProjectRepositoryLive.pipe(Layer.provideMerge(SqlitePersistenceMemory)),    ProjectionThreadRepositoryLive.pipe(Layer.provideMerge(SqlitePersistenceMemory)),    SqlitePersistenceMemory,  ),); projectionRepositoriesLayer("Projection repositories", (it) => {  it.effect("stores SQL NULL for missing project model options", () =>    Effect.gen(function* () {      const projects = yield* ProjectionProjectRepository;      const sql = yield* SqlClient.SqlClient;       yield* projects.upsert({        projectId: ProjectId.make("project-null-options"),        title: "Null options project",        workspaceRoot: "/tmp/project-null-options",        defaultModelSelection: {          provider: "codex",          model: "gpt-5.4",        },        scripts: [],        createdAt: "2026-03-24T00:00:00.000Z",        updatedAt: "2026-03-24T00:00:00.000Z",        deletedAt: null,      });       const rows = yield* sql<{        readonly defaultModelSelection: string | null;      }>`        SELECT default_model_selection_json AS "defaultModelSelection"        FROM projection_projects        WHERE project_id = 'project-null-options'      `;      const row = rows[0];      if (!row) {        return yield* Effect.fail(new Error("Expected projection_projects row to exist."));      }       assert.strictEqual(        row.defaultModelSelection,        JSON.stringify({          provider: "codex",          model: "gpt-5.4",        }),      );       const persisted = yield* projects.getById({        projectId: ProjectId.make("project-null-options"),      });      assert.deepStrictEqual(Option.getOrNull(persisted)?.defaultModelSelection, {        provider: "codex",        model: "gpt-5.4",      });    }),  );   it.effect("stores JSON for thread model options", () =>    Effect.gen(function* () {      const threads = yield* ProjectionThreadRepository;      const sql = yield* SqlClient.SqlClient;       yield* threads.upsert({        threadId: ThreadId.make("thread-null-options"),        projectId: ProjectId.make("project-null-options"),        title: "Null options thread",        modelSelection: {          provider: "claudeAgent",          model: "claude-opus-4-6",        },        runtimeMode: "full-access",        interactionMode: "default",        branch: null,        worktreePath: null,        latestTurnId: null,        createdAt: "2026-03-24T00:00:00.000Z",        updatedAt: "2026-03-24T00:00:00.000Z",        archivedAt: null,        latestUserMessageAt: null,        pendingApprovalCount: 0,        pendingUserInputCount: 0,        hasActionableProposedPlan: 0,        deletedAt: null,      });       const rows = yield* sql<{        readonly modelSelection: string | null;      }>`        SELECT model_selection_json AS "modelSelection"        FROM projection_threads        WHERE thread_id = 'thread-null-options'      `;      const row = rows[0];      if (!row) {        return yield* Effect.fail(new Error("Expected projection_threads row to exist."));      }       assert.strictEqual(        row.modelSelection,        JSON.stringify({          provider: "claudeAgent",          model: "claude-opus-4-6",        }),      );       const persisted = yield* threads.getById({        threadId: ThreadId.make("thread-null-options"),      });      assert.deepStrictEqual(Option.getOrNull(persisted)?.modelSelection, {        provider: "claudeAgent",        model: "claude-opus-4-6",      });    }),  );});