import { assert, it } from "@effect/vitest"; import { ProviderDriverKind, ProviderInstanceId, ProviderSessionId, ThreadId, type OrchestrationV2ThreadProjection, } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import { CodexProviderCapabilitiesV2 } from "./Adapters/CodexAdapterV2.ts"; import type { ProviderAdapterV2Shape } from "./ProviderAdapter.ts"; import * as ProviderAdapterRegistry from "./ProviderAdapterRegistry.ts"; import * as ProviderSwitch from "./ProviderSwitchService.ts"; const driver = ProviderDriverKind.make("codex"); const currentInstanceId = ProviderInstanceId.make("codex_primary"); const currentSessionId = ProviderSessionId.make("session_primary"); const now = DateTime.makeUnsafe("2026-06-20T00:00:00.000Z"); const capabilitiesWithoutModelSwitch = { ...CodexProviderCapabilitiesV2, sessions: { ...CodexProviderCapabilitiesV2.sessions, supportsModelSwitchInSession: false, }, }; function projection(): OrchestrationV2ThreadProjection { return { thread: { id: ThreadId.make("thread_switch_service"), modelSelection: { instanceId: currentInstanceId, model: "gpt-5.1-codex" }, runtimeMode: "full-access", interactionMode: "default", worktreePath: "/repo", }, providerSessions: [ { id: currentSessionId, providerInstanceId: currentInstanceId, status: "ready", cwd: "/repo", capabilities: capabilitiesWithoutModelSwitch, updatedAt: now, }, ], providerThreads: [], } as unknown as OrchestrationV2ThreadProjection; } function testLayer(metadata: Readonly>) { const adapter = (instanceId: ProviderInstanceId): ProviderAdapterV2Shape => ({ instanceId, driver, getCapabilities: () => Effect.succeed(capabilitiesWithoutModelSwitch), planSelectionTransition: () => Effect.succeed({ type: "restart_session" }), openSession: () => Effect.die("ProviderSwitchService tests do not open sessions."), }); const registry = Layer.mock(ProviderAdapterRegistry.ProviderAdapterRegistryV2)({ get: (instanceId) => metadata[instanceId] === undefined ? Effect.fail( new ProviderAdapterRegistry.ProviderAdapterRegistryLookupError({ instanceId }), ) : Effect.succeed(adapter(instanceId)), list: () => Effect.succeed(Object.keys(metadata).map((id) => ProviderInstanceId.make(id))), getMetadata: (instanceId) => { const value = metadata[instanceId]; return value === undefined ? Effect.fail( new ProviderAdapterRegistry.ProviderAdapterRegistryLookupError({ instanceId }), ) : Effect.succeed({ driver, continuationKey: value.continuationKey, enabled: true, capabilities: capabilitiesWithoutModelSwitch, }); }, }); return ProviderSwitch.layer.pipe(Layer.provide(registry)); } it.effect( "restarts and releases the current session for unsupported in-session model changes", () => Effect.gen(function* () { const service = yield* ProviderSwitch.ProviderSwitchServiceV2; const result = yield* service.plan({ projection: projection(), targetModelSelection: { instanceId: currentInstanceId, model: "gpt-5.2-codex" }, }); assert.equal(result.transition.type, "restart_and_resume"); assert.deepEqual(result.releaseProviderSessionIds, [currentSessionId]); }).pipe( Effect.provide( testLayer({ [currentInstanceId]: { continuationKey: "codex:account:primary" } }), ), ), ); it.effect("distinguishes compatible and incompatible instances of the same driver", () => Effect.gen(function* () { const service = yield* ProviderSwitch.ProviderSwitchServiceV2; const compatibleId = ProviderInstanceId.make("codex_compatible"); const incompatibleId = ProviderInstanceId.make("codex_incompatible"); const compatible = yield* service.plan({ projection: projection(), targetModelSelection: { instanceId: compatibleId, model: "gpt-5.1-codex" }, }); const incompatible = yield* service.plan({ projection: projection(), targetModelSelection: { instanceId: incompatibleId, model: "gpt-5.1-codex" }, }); assert.equal(compatible.transition.type, "restart_and_resume"); assert.equal(incompatible.transition.type, "create_with_handoff"); }).pipe( Effect.provide( testLayer({ [currentInstanceId]: { continuationKey: "codex:account:primary" }, codex_compatible: { continuationKey: "codex:account:primary" }, codex_incompatible: { continuationKey: "codex:account:other" }, }), ), ), );