fix structured session TUI handoff recovery

This commit is contained in:
Brennan Benson
2026-08-13 11:22:13 -07:00
parent 114eee22dd
commit ecdd5c8dd9
18 changed files with 370 additions and 82 deletions
+77
View File
@@ -0,0 +1,77 @@
import {
getAgentResumeArgv,
type AgentProviderSessionMetadata,
type ResumableTuiAgent
} from './agent-session-resume'
import type { SessionOptionValue } from './native-chat-session-options'
import { buildSleepingAgentLaunchConfig } from './sleeping-agent-launch-config'
import { resolveAgentLaunchCommand } from './tui-agent-launch-command'
import type { AgentStartupPlan } from './tui-agent-startup'
import {
quoteStartupArg,
resolveStartupShell,
type AgentStartupShell
} from './tui-agent-startup-shell'
import { TUI_AGENT_CONFIG } from './tui-agent-config'
import type { TuiAgent } from './types'
export function buildAgentResumeStartupPlan(args: {
agent: ResumableTuiAgent
providerSession: AgentProviderSessionMetadata
cmdOverrides: Partial<Record<TuiAgent, string>>
platform: NodeJS.Platform
shell?: AgentStartupShell
agentArgs?: string | null
agentEnv?: Record<string, string> | null
agentCommand?: string | null
ompResumeFilePath?: string | null
sessionOptions?: Record<string, SessionOptionValue>
sessionOptionsOverrideAgentArgs?: boolean
isRemote?: boolean
}): AgentStartupPlan | null {
const argv = getAgentResumeArgv(args.agent, args.providerSession, args.ompResumeFilePath)
if (!argv) {
return null
}
const shell = resolveStartupShell(args.platform, args.shell)
const resolvedAgentCommand = args.agentCommand?.trim()
const baseCommand = resolvedAgentCommand
? ({
ok: true,
command: resolvedAgentCommand,
commandWithoutSessionOptions: resolvedAgentCommand,
appliedSessionOptions: {}
} as const)
: resolveAgentLaunchCommand({
agent: args.agent,
cmdOverrides: args.cmdOverrides,
platform: args.platform,
shell,
agentArgs: args.agentArgs,
sessionOptions: args.sessionOptions,
sessionOptionsOverrideAgentArgs: args.sessionOptionsOverrideAgentArgs,
isRemote: args.isRemote
})
if (!baseCommand.ok) {
return null
}
const launchConfig = buildSleepingAgentLaunchConfig({
...args,
agentCommand: baseCommand.commandWithoutSessionOptions
})
const resumeArgs = argv
.slice(1)
.map((arg) => quoteStartupArg(arg, shell))
.join(' ')
const launchCommand = resumeArgs ? `${baseCommand.command} ${resumeArgs}` : baseCommand.command
const applied = baseCommand.appliedSessionOptions
return {
agent: args.agent,
launchCommand,
expectedProcess: TUI_AGENT_CONFIG[args.agent].expectedProcess,
followupPrompt: null,
launchConfig,
...(Object.keys(applied).length > 0 ? { sessionOptions: { ...applied } } : {}),
...(args.agentEnv ? { env: { ...args.agentEnv } } : {})
}
}
@@ -140,15 +140,22 @@ describe('tui agent startup session options', () => {
expect(plan?.sessionOptions).toEqual({ model: 'opus', effort: 'high' })
})
it('never injects session options into resume commands', () => {
it('applies explicit session options to resume commands', () => {
const plan = buildAgentResumeStartupPlan({
agent: 'codex',
providerSession: { key: 'session_id', id: 'thread-1' },
cmdOverrides: {},
platform: 'linux',
sessionOptions: { model: 'gpt-5.5', effort: 'high' }
agentArgs: '-m gpt-5.6-sol -c model_reasoning_effort=medium',
sessionOptions: { model: 'gpt-5.5', effort: 'high' },
sessionOptionsOverrideAgentArgs: true
})
expect(plan?.launchCommand).toBe("codex 'resume' 'thread-1'")
expect(plan?.sessionOptions).toBeUndefined()
expect(plan?.launchCommand).toBe(
"codex '-m' 'gpt-5.5' '-c' 'model_reasoning_effort=high' 'resume' 'thread-1'"
)
expect(plan?.launchConfig.agentCommand).toBe(
"codex '-m' 'gpt-5.6-sol' '-c' 'model_reasoning_effort=medium'"
)
expect(plan?.sessionOptions).toEqual({ model: 'gpt-5.5', effort: 'high' })
})
})
+3 -59
View File
@@ -1,10 +1,5 @@
import { isShellProcess } from './agent-detection'
import {
getAgentResumeArgv,
type AgentProviderSessionMetadata,
type ResumableTuiAgent,
type SleepingAgentLaunchConfig
} from './agent-session-resume'
import type { SleepingAgentLaunchConfig } from './agent-session-resume'
import {
clearEnvCommand,
commandSeparator,
@@ -21,6 +16,8 @@ import type { TuiAgent } from './types'
import type { SessionOptionValue } from './native-chat-session-options'
import { resolveAgentLaunchCommand } from './tui-agent-launch-command'
export { buildAgentResumeStartupPlan } from './tui-agent-resume-startup'
export type AgentStartupPlan = {
agent: TuiAgent
launchCommand: string
@@ -184,59 +181,6 @@ export function buildAgentStartupPlan(args: {
}
}
export function buildAgentResumeStartupPlan(args: {
agent: ResumableTuiAgent
providerSession: AgentProviderSessionMetadata
cmdOverrides: Partial<Record<TuiAgent, string>>
platform: NodeJS.Platform
shell?: AgentStartupShell
agentArgs?: string | null
agentEnv?: Record<string, string> | null
agentCommand?: string | null
ompResumeFilePath?: string | null
sessionOptions?: Record<string, SessionOptionValue>
/** Why: see buildAgentStartupPlan — remote launches use the plain `orca` shim. */
isRemote?: boolean
}): AgentStartupPlan | null {
const argv = getAgentResumeArgv(args.agent, args.providerSession, args.ompResumeFilePath)
if (!argv) {
return null
}
const shell = resolveStartupShell(args.platform, args.shell)
const config = TUI_AGENT_CONFIG[args.agent]
const resolvedAgentCommand = args.agentCommand?.trim()
const baseCommand = resolvedAgentCommand
? ({ ok: true, command: resolvedAgentCommand } as const)
: resolveAgentLaunchCommand({
agent: args.agent,
cmdOverrides: args.cmdOverrides,
platform: args.platform,
shell,
agentArgs: args.agentArgs,
isRemote: args.isRemote
})
if (!baseCommand.ok) {
return null
}
const launchConfig = buildSleepingAgentLaunchConfig({
...args,
agentCommand: baseCommand.command
})
const resumeArgs = argv
.slice(1)
.map((arg) => quoteStartupArg(arg, shell))
.join(' ')
const launchCommand = resumeArgs ? `${baseCommand.command} ${resumeArgs}` : baseCommand.command
return {
agent: args.agent,
launchCommand,
expectedProcess: config.expectedProcess,
followupPrompt: null,
launchConfig,
...(args.agentEnv ? { env: { ...args.agentEnv } } : {})
}
}
export type AgentDraftLaunchPlan = {
agent: TuiAgent
launchCommand: string