diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66913c716ae..d07586f0437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: run: vp run --filter @t3tools/desktop ensure:electron - name: Check - run: vp check + run: vp check 2>&1 | tee "$RUNNER_TEMP/vp-check.log" - name: Typecheck run: vpr typecheck diff --git a/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts index f528c278215..409fb41519e 100644 --- a/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts +++ b/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts @@ -902,6 +902,11 @@ interface PendingCodexSubagentTurnStarted { readonly startedAt: DateTime.Utc; } +interface PendingCodexRootTurn { + readonly turnInput: ProviderAdapterV2TurnInput; + readonly started: Deferred.Deferred; +} + type PendingCodexRuntimeRequest = | { readonly type: "approval"; @@ -1473,7 +1478,7 @@ export function makeCodexAdapterV2(adapterOptions: CodexAdapterV2Options): Provi }); const events = yield* Queue.unbounded(); const activeTurns = yield* Ref.make(new Map()); - const pendingRootTurns = yield* Ref.make(new Map()); + const pendingRootTurns = yield* Ref.make(new Map()); const turnWaiters = yield* Ref.make(new Map>()); const subagentThreads = yield* Ref.make(new Map()); const pendingSubagentTurns = yield* Ref.make( @@ -3215,11 +3220,12 @@ export function makeCodexAdapterV2(adapterOptions: CodexAdapterV2Options): Provi } const pendingRootTurn = (yield* Ref.get(pendingRootTurns)).get(payload.threadId); if (pendingRootTurn !== undefined) { - yield* registerRootTurn({ - turnInput: pendingRootTurn, + const rootTurn = yield* registerRootTurn({ + turnInput: pendingRootTurn.turnInput, nativeTurnId: payload.turn.id, startedAt: codexTimestamp(payload.turn.startedAt), }); + yield* Deferred.succeed(pendingRootTurn.started, rootTurn); yield* Ref.update(pendingRootTurns, (current) => { const updated = new Map(current); updated.delete(payload.threadId); @@ -4486,20 +4492,21 @@ export function makeCodexAdapterV2(adapterOptions: CodexAdapterV2Options): Provi hasT3Mcp: McpProviderSession.readMcpProviderSession(turnInput.threadId) !== undefined, }); + const turnStarted = yield* Deferred.make(); yield* Ref.update(pendingRootTurns, (current) => { const updated = new Map(current); - updated.set(threadId, turnInput); + updated.set(threadId, { turnInput, started: turnStarted }); return updated; }); const started = yield* client.request("turn/start", turnStartParams); - const nativeTurnId = started.turn.id; - const startedAt = codexTimestamp(started.turn.startedAt); - yield* registerRootTurn({ turnInput, nativeTurnId, startedAt }); - yield* Ref.update(pendingRootTurns, (current) => { - const updated = new Map(current); - updated.delete(threadId); - return updated; - }); + const rootTurn = yield* Deferred.await(turnStarted); + if (started.turn.id !== rootTurn.nativeTurnId) { + yield* Effect.logWarning("orchestration-v2.codex-turn-id-mismatch", { + nativeThreadId: threadId, + responseNativeTurnId: started.turn.id, + notificationNativeTurnId: rootTurn.nativeTurnId, + }); + } }).pipe( Effect.ensuring( Effect.flatMap(getNativeThreadId(turnInput.providerThread), (threadId) => diff --git a/apps/web/src/components/ProjectScriptsControl.tsx b/apps/web/src/components/ProjectScriptsControl.tsx index fb5804be7b7..7d52264b6b5 100644 --- a/apps/web/src/components/ProjectScriptsControl.tsx +++ b/apps/web/src/components/ProjectScriptsControl.tsx @@ -363,7 +363,11 @@ export default function ProjectScriptsControl({