diff --git a/src/main/codex/codex-structured-session-adapter.test.ts b/src/main/codex/codex-structured-session-adapter.test.ts index 5e218c1f31f..a6015525b98 100644 --- a/src/main/codex/codex-structured-session-adapter.test.ts +++ b/src/main/codex/codex-structured-session-adapter.test.ts @@ -188,11 +188,11 @@ describe('CodexStructuredSessionAdapter.acquire', () => { expect(codex.connections[0].calls[0]).toEqual({ method: 'thread/resume', - params: expect.objectContaining({ + params: { threadId: 'thread-proven', cwd: '/work/repo', path: '/rollouts/thread-proven.jsonl' - }) + } }) expect(acquisition.link.origin).toBe('resumed') expect(acquisition.link.handle).toEqual({ provider: 'codex', threadId: 'thread-proven' }) diff --git a/src/main/runtime/orca-runtime-resolve-recovered-structured-tui-transcript.ts b/src/main/runtime/orca-runtime-resolve-recovered-structured-tui-transcript.ts index ab724b469dc..5efca97641a 100644 --- a/src/main/runtime/orca-runtime-resolve-recovered-structured-tui-transcript.ts +++ b/src/main/runtime/orca-runtime-resolve-recovered-structured-tui-transcript.ts @@ -9,6 +9,7 @@ import type { AgentStatusIpcPayload } from '../../shared/agent-status-types' import { getLocalProjectWorktreeGitOptions } from '../project-runtime-git-options' import { getRuntimeFileTargetExecutionHostId } from './orca-runtime-files' import type { AgentSessionAttachParams } from '../native-chat/agent-session-wire/structured-agent-session-attach' +import type { AgentSessionWireRefusal } from '../../shared/agent-session-wire' import { getSystemCodexHomePath } from '../codex/codex-home-paths' import { resolveTuiAgentLaunchEnv } from '../../shared/tui-agent-launch-defaults' import { hasPersistedStructuredAgentSessionStore as hasPersistedStructuredAgentSessionStoreOnDisk } from './structured-agent-session-runtime' @@ -112,17 +113,30 @@ export class OrcaRuntimeWithResolveRecoveredStructuredTuiTranscript extends Orca envelope: { sessionId: string; clientOperationId: string } worktree: string agent: 'codex' + initialOptions?: { model: string; effort?: string } }): Promise { - return this.resolveStructuredAgentSessionIntent(input, async ({ workspacePath, launchEnv }) => { - // A create has no process yet, so the current selection is what it must follow. - const preparedHome = await this.prepareCodexStructuredLaunchFn?.({ workspacePath, launchEnv }) - const configuredHome = launchEnv.CODEX_HOME - return ( - preparedHome?.trim() || - (this.prepareCodexStructuredLaunchFn ? getSystemCodexHomePath() : configuredHome?.trim()) || - getSystemCodexHomePath() - ) - }) + const resolved = await this.resolveStructuredAgentSessionIntent( + input, + async ({ workspacePath, launchEnv }) => { + // A create has no process yet, so the current selection is what it must follow. + const preparedHome = await this.prepareCodexStructuredLaunchFn?.({ + workspacePath, + launchEnv + }) + const configuredHome = launchEnv.CODEX_HOME + return ( + preparedHome?.trim() || + (this.prepareCodexStructuredLaunchFn + ? getSystemCodexHomePath() + : configuredHome?.trim()) || + getSystemCodexHomePath() + ) + } + ) + if ('ok' in resolved) { + throw new Error(resolved.refusal.code) + } + return resolved } protected async resolveStructuredAgentSessionIntent( @@ -130,15 +144,24 @@ export class OrcaRuntimeWithResolveRecoveredStructuredTuiTranscript extends Orca envelope: { sessionId: string; clientOperationId: string } worktree: string agent: 'codex' + initialOptions?: { model: string; effort?: string } }, resolveAccountHomePath: (context: { workspacePath: string launchEnv: NodeJS.ProcessEnv }) => string | Promise - ): Promise { + ): Promise { const support = await this.getStructuredAgentSessionCreateSupport(input.worktree, input.agent) if (!support.supported) { - throw new Error('structured_agent_session_unsupported') + const reason = support.reason ?? 'agent' + return { + ok: false, + refusal: { + code: 'structured_agent_session_unsupported', + message: `Structured Codex sessions are unsupported for ${reason} execution.`, + acquisitionState: 'not-acquired' + } + } } const settings = this.requireStore().getSettings() const launchEnv = resolveTuiAgentLaunchEnv(input.agent, settings.agentDefaultEnv) @@ -158,7 +181,8 @@ export class OrcaRuntimeWithResolveRecoveredStructuredTuiTranscript extends Orca variable: 'CODEX_HOME', path: await resolveAccountHomePath({ workspacePath, launchEnv }) }, - runtimeKind: 'native' + runtimeKind: 'native', + ...(input.initialOptions ? { initialOptions: input.initialOptions } : {}) } } diff --git a/src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx b/src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx index 7a02829a05a..583ca5f9340 100644 --- a/src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx +++ b/src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx @@ -22,6 +22,7 @@ import { useStructuredAgentSession } from './use-structured-agent-session' import { translate } from '@/i18n/i18n' import { NativeChatOrchestrationPausedNotice } from './NativeChatOrchestrationPausedNotice' import { useNativeChatPasteBridge } from './use-native-chat-paste-bridge' +import { useNativeChatLaunchDraftSignal } from './use-native-chat-launch-draft-adoption' function encodeQuestionAnswer(questionId: string, answer: string): string { return `${encodeURIComponent(questionId)}:${encodeURIComponent(answer)}`