// @effect-diagnostics nodeBuiltinImport:offimport * as NodeFS from "node:fs";import * as NodeOS from "node:os";import * as NodePath from "node:path"; import * as NodeServices from "@effect/platform-node/NodeServices";import { ProviderDriverKind, ThreadId } from "@t3tools/contracts";import { it, assert } from "@effect/vitest";import { assertSome } from "@effect/vitest/utils";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as SqlClient from "effect/unstable/sql/SqlClient"; import { makeSqlitePersistenceLive, SqlitePersistenceMemory,} from "../../persistence/Layers/Sqlite.ts";import * as ProviderSessionRuntime from "../../persistence/ProviderSessionRuntime.ts";import { ProviderSessionDirectory } from "../Services/ProviderSessionDirectory.ts";import { ProviderSessionDirectoryLive } from "./ProviderSessionDirectory.ts"; function makeDirectoryLayer<E, R>(persistenceLayer: Layer.Layer<SqlClient.SqlClient, E, R>) { const runtimeRepositoryLayer = ProviderSessionRuntime.layer.pipe(Layer.provide(persistenceLayer)); return Layer.mergeAll( runtimeRepositoryLayer, ProviderSessionDirectoryLive.pipe(Layer.provide(runtimeRepositoryLayer)), NodeServices.layer, );} it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryLive", (it) => { it("upserts and reads thread bindings", () => Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository; const initialThreadId = ThreadId.make("thread-1"); yield* directory.upsert({ provider: ProviderDriverKind.make("codex"), threadId: initialThreadId, }); const provider = yield* directory.getProvider(initialThreadId); assert.equal(provider, "codex"); const resolvedBinding = yield* directory.getBinding(initialThreadId); assertSome(resolvedBinding, { threadId: initialThreadId, provider: ProviderDriverKind.make("codex"), }); if (Option.isSome(resolvedBinding)) { assert.equal(resolvedBinding.value.threadId, initialThreadId); } const nextThreadId = ThreadId.make("thread-2"); yield* directory.upsert({ provider: ProviderDriverKind.make("codex"), threadId: nextThreadId, }); const updatedBinding = yield* directory.getBinding(nextThreadId); assert.equal(Option.isSome(updatedBinding), true); if (Option.isSome(updatedBinding)) { assert.equal(updatedBinding.value.threadId, nextThreadId); } const runtime = yield* runtimeRepository.getByThreadId({ threadId: nextThreadId }); assert.equal(Option.isSome(runtime), true); if (Option.isSome(runtime)) { assert.equal(runtime.value.threadId, nextThreadId); assert.equal(runtime.value.status, "running"); assert.equal(runtime.value.providerName, "codex"); } const threadIds = yield* directory.listThreadIds(); assert.deepEqual(threadIds, [nextThreadId]); })); it("persists runtime fields and merges payload updates", () => Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository; const threadId = ThreadId.make("thread-runtime"); yield* directory.upsert({ provider: ProviderDriverKind.make("codex"), threadId, status: "starting", resumeCursor: { threadId: "provider-thread-runtime", }, runtimePayload: { cwd: "/tmp/project", model: "gpt-5-codex", }, }); yield* directory.upsert({ provider: ProviderDriverKind.make("codex"), threadId, status: "running", runtimePayload: { activeTurnId: "turn-1", }, }); const runtime = yield* runtimeRepository.getByThreadId({ threadId }); assert.equal(Option.isSome(runtime), true); if (Option.isSome(runtime)) { assert.equal(runtime.value.threadId, threadId); assert.equal(runtime.value.status, "running"); assert.deepEqual(runtime.value.resumeCursor, { threadId: "provider-thread-runtime", }); assert.deepEqual(runtime.value.runtimePayload, { cwd: "/tmp/project", model: "gpt-5-codex", activeTurnId: "turn-1", }); } })); it("lists persisted bindings with metadata in oldest-first order", () => Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository; const olderThreadId = ThreadId.make("thread-runtime-older"); const newerThreadId = ThreadId.make("thread-runtime-newer"); yield* runtimeRepository.upsert({ threadId: newerThreadId, providerName: "codex", providerInstanceId: null, adapterKey: "codex", runtimeMode: "full-access", status: "running", lastSeenAt: "2026-04-14T12:05:00.000Z", resumeCursor: { opaque: "resume-newer", }, runtimePayload: { cwd: "/tmp/newer", }, }); yield* runtimeRepository.upsert({ threadId: olderThreadId, providerName: "claudeAgent", providerInstanceId: null, adapterKey: "claudeAgent", runtimeMode: "approval-required", status: "starting", lastSeenAt: "2026-04-14T12:00:00.000Z", resumeCursor: { opaque: "resume-older", }, runtimePayload: { cwd: "/tmp/older", }, }); const bindings = yield* directory.listBindings(); assert.deepEqual(bindings, [ { threadId: olderThreadId, provider: ProviderDriverKind.make("claudeAgent"), adapterKey: "claudeAgent", runtimeMode: "approval-required", status: "starting", lastSeenAt: "2026-04-14T12:00:00.000Z", resumeCursor: { opaque: "resume-older", }, runtimePayload: { cwd: "/tmp/older", }, }, { threadId: newerThreadId, provider: ProviderDriverKind.make("codex"), adapterKey: "codex", runtimeMode: "full-access", status: "running", lastSeenAt: "2026-04-14T12:05:00.000Z", resumeCursor: { opaque: "resume-newer", }, runtimePayload: { cwd: "/tmp/newer", }, }, ]); })); it("resets adapterKey to the new provider when provider changes without an explicit adapter key", () => Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository; const threadId = ThreadId.make("thread-provider-change"); yield* runtimeRepository.upsert({ threadId, providerName: "claudeAgent", providerInstanceId: null, adapterKey: "claudeAgent", runtimeMode: "full-access", status: "running", lastSeenAt: "2026-01-01T00:00:00.000Z", resumeCursor: null, runtimePayload: null, }); yield* directory.upsert({ provider: ProviderDriverKind.make("codex"), threadId, }); const runtime = yield* runtimeRepository.getByThreadId({ threadId }); assert.equal(Option.isSome(runtime), true); if (Option.isSome(runtime)) { assert.equal(runtime.value.providerName, "codex"); assert.equal(runtime.value.adapterKey, "codex"); } })); it("rehydrates persisted mappings across layer restart", () => Effect.gen(function* () { const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-directory-")); const dbPath = NodePath.join(tempDir, "orchestration.sqlite"); const directoryLayer = makeDirectoryLayer(makeSqlitePersistenceLive(dbPath)); const threadId = ThreadId.make("thread-restart"); yield* Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; yield* directory.upsert({ provider: ProviderDriverKind.make("codex"), threadId, }); }).pipe(Effect.provide(directoryLayer)); yield* Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; const sql = yield* SqlClient.SqlClient; const provider = yield* directory.getProvider(threadId); assert.equal(provider, "codex"); const resolvedBinding = yield* directory.getBinding(threadId); assertSome(resolvedBinding, { threadId, provider: ProviderDriverKind.make("codex"), }); if (Option.isSome(resolvedBinding)) { assert.equal(resolvedBinding.value.threadId, threadId); } const legacyTableRows = yield* sql<{ readonly name: string }>` SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'provider_sessions' `; assert.equal(legacyTableRows.length, 0); }).pipe(Effect.provide(directoryLayer)); NodeFS.rmSync(tempDir, { recursive: true, force: true }); }));});
// @effect-diagnostics nodeBuiltinImport:off
import * as NodeFS from "node:fs";
import * as NodeOS from "node:os";
import * as NodePath from "node:path";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { ProviderDriverKind, ThreadId } from "@t3tools/contracts";
import { it, assert } from "@effect/vitest";
import { assertSome } from "@effect/vitest/utils";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as SqlClient from "effect/unstable/sql/SqlClient";
import {
makeSqlitePersistenceLive,
SqlitePersistenceMemory,
} from "../../persistence/Layers/Sqlite.ts";
import * as ProviderSessionRuntime from "../../persistence/ProviderSessionRuntime.ts";
import { ProviderSessionDirectory } from "../Services/ProviderSessionDirectory.ts";
import { ProviderSessionDirectoryLive } from "./ProviderSessionDirectory.ts";
function makeDirectoryLayer<E, R>(persistenceLayer: Layer.Layer<SqlClient.SqlClient, E, R>) {
const runtimeRepositoryLayer = ProviderSessionRuntime.layer.pipe(Layer.provide(persistenceLayer));
return Layer.mergeAll(
runtimeRepositoryLayer,
ProviderSessionDirectoryLive.pipe(Layer.provide(runtimeRepositoryLayer)),
NodeServices.layer,
);
}
it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryLive", (it) => {
it("upserts and reads thread bindings", () =>
Effect.gen(function* () {
const directory = yield* ProviderSessionDirectory;
const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository;
const initialThreadId = ThreadId.make("thread-1");
yield* directory.upsert({
provider: ProviderDriverKind.make("codex"),
threadId: initialThreadId,
});
const provider = yield* directory.getProvider(initialThreadId);
assert.equal(provider, "codex");
const resolvedBinding = yield* directory.getBinding(initialThreadId);
assertSome(resolvedBinding, {
threadId: initialThreadId,
provider: ProviderDriverKind.make("codex"),
});
if (Option.isSome(resolvedBinding)) {
assert.equal(resolvedBinding.value.threadId, initialThreadId);
}
const nextThreadId = ThreadId.make("thread-2");
yield* directory.upsert({
provider: ProviderDriverKind.make("codex"),
threadId: nextThreadId,
});
const updatedBinding = yield* directory.getBinding(nextThreadId);
assert.equal(Option.isSome(updatedBinding), true);
if (Option.isSome(updatedBinding)) {
assert.equal(updatedBinding.value.threadId, nextThreadId);
}
const runtime = yield* runtimeRepository.getByThreadId({ threadId: nextThreadId });
assert.equal(Option.isSome(runtime), true);
if (Option.isSome(runtime)) {
assert.equal(runtime.value.threadId, nextThreadId);
assert.equal(runtime.value.status, "running");
assert.equal(runtime.value.providerName, "codex");
}
const threadIds = yield* directory.listThreadIds();
assert.deepEqual(threadIds, [nextThreadId]);
}));
it("persists runtime fields and merges payload updates", () =>
Effect.gen(function* () {
const directory = yield* ProviderSessionDirectory;
const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository;
const threadId = ThreadId.make("thread-runtime");
yield* directory.upsert({
provider: ProviderDriverKind.make("codex"),
threadId,
status: "starting",
resumeCursor: {
threadId: "provider-thread-runtime",
},
runtimePayload: {
cwd: "/tmp/project",
model: "gpt-5-codex",
},
});
yield* directory.upsert({
provider: ProviderDriverKind.make("codex"),
threadId,
status: "running",
runtimePayload: {
activeTurnId: "turn-1",
},
});
const runtime = yield* runtimeRepository.getByThreadId({ threadId });
assert.equal(Option.isSome(runtime), true);
if (Option.isSome(runtime)) {
assert.equal(runtime.value.threadId, threadId);
assert.equal(runtime.value.status, "running");
assert.deepEqual(runtime.value.resumeCursor, {
threadId: "provider-thread-runtime",
});
assert.deepEqual(runtime.value.runtimePayload, {
cwd: "/tmp/project",
model: "gpt-5-codex",
activeTurnId: "turn-1",
});
}
}));
it("lists persisted bindings with metadata in oldest-first order", () =>
Effect.gen(function* () {
const directory = yield* ProviderSessionDirectory;
const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository;
const olderThreadId = ThreadId.make("thread-runtime-older");
const newerThreadId = ThreadId.make("thread-runtime-newer");
yield* runtimeRepository.upsert({
threadId: newerThreadId,
providerName: "codex",
providerInstanceId: null,
adapterKey: "codex",
runtimeMode: "full-access",
status: "running",
lastSeenAt: "2026-04-14T12:05:00.000Z",
resumeCursor: {
opaque: "resume-newer",
},
runtimePayload: {
cwd: "/tmp/newer",
},
});
yield* runtimeRepository.upsert({
threadId: olderThreadId,
providerName: "claudeAgent",
providerInstanceId: null,
adapterKey: "claudeAgent",
runtimeMode: "approval-required",
status: "starting",
lastSeenAt: "2026-04-14T12:00:00.000Z",
resumeCursor: {
opaque: "resume-older",
},
runtimePayload: {
cwd: "/tmp/older",
},
});
const bindings = yield* directory.listBindings();
assert.deepEqual(bindings, [
{
threadId: olderThreadId,
provider: ProviderDriverKind.make("claudeAgent"),
adapterKey: "claudeAgent",
runtimeMode: "approval-required",
status: "starting",
lastSeenAt: "2026-04-14T12:00:00.000Z",
resumeCursor: {
opaque: "resume-older",
},
runtimePayload: {
cwd: "/tmp/older",
},
},
{
threadId: newerThreadId,
provider: ProviderDriverKind.make("codex"),
adapterKey: "codex",
runtimeMode: "full-access",
status: "running",
lastSeenAt: "2026-04-14T12:05:00.000Z",
resumeCursor: {
opaque: "resume-newer",
},
runtimePayload: {
cwd: "/tmp/newer",
},
},
]);
}));
it("resets adapterKey to the new provider when provider changes without an explicit adapter key", () =>
Effect.gen(function* () {
const directory = yield* ProviderSessionDirectory;
const runtimeRepository = yield* ProviderSessionRuntime.ProviderSessionRuntimeRepository;
const threadId = ThreadId.make("thread-provider-change");
yield* runtimeRepository.upsert({
threadId,
providerName: "claudeAgent",
providerInstanceId: null,
adapterKey: "claudeAgent",
runtimeMode: "full-access",
status: "running",
lastSeenAt: "2026-01-01T00:00:00.000Z",
resumeCursor: null,
runtimePayload: null,
});
yield* directory.upsert({
provider: ProviderDriverKind.make("codex"),
threadId,
});
const runtime = yield* runtimeRepository.getByThreadId({ threadId });
assert.equal(Option.isSome(runtime), true);
if (Option.isSome(runtime)) {
assert.equal(runtime.value.providerName, "codex");
assert.equal(runtime.value.adapterKey, "codex");
}
}));
it("rehydrates persisted mappings across layer restart", () =>
Effect.gen(function* () {
const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-directory-"));
const dbPath = NodePath.join(tempDir, "orchestration.sqlite");
const directoryLayer = makeDirectoryLayer(makeSqlitePersistenceLive(dbPath));
const threadId = ThreadId.make("thread-restart");
yield* Effect.gen(function* () {
const directory = yield* ProviderSessionDirectory;
yield* directory.upsert({
provider: ProviderDriverKind.make("codex"),
threadId,
});
}).pipe(Effect.provide(directoryLayer));
yield* Effect.gen(function* () {
const directory = yield* ProviderSessionDirectory;
const sql = yield* SqlClient.SqlClient;
const provider = yield* directory.getProvider(threadId);
assert.equal(provider, "codex");
const resolvedBinding = yield* directory.getBinding(threadId);
assertSome(resolvedBinding, {
threadId,
provider: ProviderDriverKind.make("codex"),
});
if (Option.isSome(resolvedBinding)) {
assert.equal(resolvedBinding.value.threadId, threadId);
}
const legacyTableRows = yield* sql<{ readonly name: string }>`
SELECT name
FROM sqlite_master
WHERE type = 'table' AND name = 'provider_sessions'
`;
assert.equal(legacyTableRows.length, 0);
}).pipe(Effect.provide(directoryLayer));
NodeFS.rmSync(tempDir, { recursive: true, force: true });
}));
});