| 1 | import { |
| 2 | type OrchestrationV2ThreadProjection, |
| 3 | type OrchestrationV2ThreadShell, |
| 4 | ProjectId, |
| 5 | type ProviderInteractionMode, |
| 6 | ProviderInstanceId, |
| 7 | RunId, |
| 8 | type RuntimeMode, |
| 9 | type ThreadId, |
| 10 | } from "@t3tools/contracts"; |
| 11 | import * as DateTime from "effect/DateTime"; |
| 12 | import * as Effect from "effect/Effect"; |
| 13 | import * as Layer from "effect/Layer"; |
| 14 | |
| 15 | import * as ThreadManagement from "../orchestration-v2/ThreadManagementService.ts"; |
| 16 | |
| 17 | const EPOCH = DateTime.makeUnsafe("2026-01-01T00:00:00.000Z"); |
| 18 | |
| 19 | /** |
| 20 | * A thread in the middle of a turn on the `codex` instance: the shape the |
| 21 | * access gate reads for a thread caller, and for the threads a caller targets. |
| 22 | */ |
| 23 | export const liveThreadShell = ( |
| 24 | id: ThreadId, |
| 25 | modes: { |
| 26 | readonly runtimeMode?: RuntimeMode; |
| 27 | readonly interactionMode?: ProviderInteractionMode; |
| 28 | readonly activeRunId?: RunId | null; |
| 29 | } = {}, |
| 30 | ): OrchestrationV2ThreadShell => { |
| 31 | const providerInstanceId = ProviderInstanceId.make("codex"); |
| 32 | return { |
| 33 | id, |
| 34 | projectId: ProjectId.make("project:mcp-test"), |
| 35 | title: id, |
| 36 | providerInstanceId, |
| 37 | modelSelection: { instanceId: providerInstanceId, model: "gpt-5" }, |
| 38 | runtimeMode: modes.runtimeMode ?? "full-access", |
| 39 | interactionMode: modes.interactionMode ?? "default", |
| 40 | branch: null, |
| 41 | worktreePath: null, |
| 42 | createdBy: "user", |
| 43 | creationSource: "web", |
| 44 | activeProviderThreadId: null, |
| 45 | lineage: { rootThreadId: id, parentThreadId: null, relationshipToParent: null }, |
| 46 | forkedFrom: null, |
| 47 | latestRunId: null, |
| 48 | activeRunId: modes.activeRunId === undefined ? RunId.make("run:mcp-test") : modes.activeRunId, |
| 49 | status: "running", |
| 50 | pendingRuntimeRequest: null, |
| 51 | latestVisibleMessage: null, |
| 52 | latestUserMessageAt: null, |
| 53 | hasActionableProposedPlan: false, |
| 54 | itemCount: 0, |
| 55 | visibleItemCount: 0, |
| 56 | createdAt: EPOCH, |
| 57 | updatedAt: EPOCH, |
| 58 | archivedAt: null, |
| 59 | settledOverride: null, |
| 60 | settledAt: null, |
| 61 | lastVisitedAt: null, |
| 62 | deletedAt: null, |
| 63 | }; |
| 64 | }; |
| 65 | |
| 66 | /** |
| 67 | * `ThreadManagementService` that answers only the access gate's lookups, |
| 68 | * every thread a live full-access one. For tests of a tool rather than of who |
| 69 | * may call it. |
| 70 | */ |
| 71 | export const liveThreadsLayer = Layer.mock(ThreadManagement.ThreadManagementService)({ |
| 72 | getThreadShell: (threadId) => Effect.succeed(liveThreadShell(threadId)), |
| 73 | }); |
| 74 | |
| 75 | /** |
| 76 | * The thread of `shell` with no runs, messages or other records: what a |
| 77 | * caller looks like once its turn has ended. |
| 78 | */ |
| 79 | export const idleThreadProjection = ( |
| 80 | shell: OrchestrationV2ThreadShell, |
| 81 | ): OrchestrationV2ThreadProjection => { |
| 82 | const { |
| 83 | status: _status, |
| 84 | activeRunId: _activeRunId, |
| 85 | latestRunId: _latestRunId, |
| 86 | pendingRuntimeRequest: _pendingRuntimeRequest, |
| 87 | latestVisibleMessage: _latestVisibleMessage, |
| 88 | latestUserMessageAt: _latestUserMessageAt, |
| 89 | hasActionableProposedPlan: _hasActionableProposedPlan, |
| 90 | itemCount: _itemCount, |
| 91 | visibleItemCount: _visibleItemCount, |
| 92 | lastVisitedAt, |
| 93 | ...thread |
| 94 | } = shell; |
| 95 | return { |
| 96 | thread: { ...thread, lastVisitedAt: lastVisitedAt ?? null }, |
| 97 | runs: [], |
| 98 | attempts: [], |
| 99 | nodes: [], |
| 100 | subagents: [], |
| 101 | providerSessions: [], |
| 102 | providerThreads: [], |
| 103 | providerTurns: [], |
| 104 | runtimeRequests: [], |
| 105 | messages: [], |
| 106 | plans: [], |
| 107 | turnItems: [], |
| 108 | checkpointScopes: [], |
| 109 | checkpoints: [], |
| 110 | contextHandoffs: [], |
| 111 | contextTransfers: [], |
| 112 | visibleTurnItems: [], |
| 113 | updatedAt: shell.updatedAt, |
| 114 | }; |
| 115 | }; |