mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 00:03:15 +00:00
fix: preserve centralized agent launch behavior
This commit is contained in:
@@ -216,6 +216,8 @@ export async function submitFolderWorkspaceCreate({
|
||||
tuiCustomization: { agentArgs },
|
||||
launchPlatform,
|
||||
initialSessionOptions: startupPlan?.sessionOptions,
|
||||
...(plan ? { launchPlan: plan } : {}),
|
||||
...(startup ? { terminalStartup: startup } : {}),
|
||||
visibility: 'reveal',
|
||||
launchSource,
|
||||
pendingFirstAgentMessageRename
|
||||
|
||||
@@ -237,6 +237,8 @@ export function useFullCreationExecution(input: FullCreationExecutionInput) {
|
||||
prompt: startupPlan?.draftPrompt ?? submitStartupPrompt,
|
||||
promptDelivery: startupPlan?.draftPrompt ? 'draft' : 'auto-submit',
|
||||
initialSessionOptions: startupPlan?.sessionOptions,
|
||||
launchPlan,
|
||||
...(startup ? { terminalStartup: startup } : {}),
|
||||
visibility: 'reveal',
|
||||
launchSource:
|
||||
telemetrySource === 'onboarding' ? 'onboarding' : 'new_workspace_composer',
|
||||
|
||||
@@ -145,11 +145,13 @@ function launchAgentInNewTabInternal(args: LaunchAgentInNewTabArgs): LaunchAgent
|
||||
const structuredSettlement = launchAgentSession(store, {
|
||||
agent,
|
||||
workspaceId: worktreeId,
|
||||
...(groupId ? { groupId } : {}),
|
||||
prompt: trimmedPrompt,
|
||||
promptDelivery: viewModePromptDelivery,
|
||||
tuiCustomization: { cwd: initialCwd, agentArgs },
|
||||
initialSessionOptions: startupPlan.sessionOptions,
|
||||
onPromptDelivered,
|
||||
launchPlan: plan,
|
||||
visibility: 'reveal',
|
||||
launchSource: launchSource ?? 'tab_bar_quick_launch'
|
||||
}).then((outcome) => {
|
||||
|
||||
@@ -36,9 +36,6 @@ function terminalStartup(
|
||||
...(request.promptDelivery === 'draft' && prepared.trimmedPrompt
|
||||
? { launchDraftText: prepared.trimmedPrompt }
|
||||
: {}),
|
||||
...(prepared.pasteDraftAfterLaunch !== null
|
||||
? { draftPrompt: prepared.pasteDraftAfterLaunch }
|
||||
: {}),
|
||||
...(request.agent === 'command-code' && prepared.hasPrompt
|
||||
? { initialAgentStatus: { agent: request.agent, prompt: prepared.trimmedPrompt } }
|
||||
: {}),
|
||||
@@ -150,28 +147,30 @@ export async function launchTerminalSession(
|
||||
if (request.signal?.aborted) {
|
||||
return { tabId: null }
|
||||
}
|
||||
const prepared = prepareAgentInNewTabLaunch({
|
||||
agent: request.agent,
|
||||
worktreeId: request.workspaceId,
|
||||
...(request.prompt !== undefined ? { prompt: request.prompt } : {}),
|
||||
...(request.promptDelivery ? { promptDelivery: request.promptDelivery } : {}),
|
||||
...(request.tuiCustomization?.agentArgs !== undefined
|
||||
? { agentArgs: request.tuiCustomization.agentArgs }
|
||||
: {}),
|
||||
...(request.tuiCustomization?.cwd !== undefined
|
||||
? { initialCwd: request.tuiCustomization.cwd }
|
||||
: {}),
|
||||
...(request.launchPlatform ? { launchPlatform: request.launchPlatform } : {}),
|
||||
...(request.initialSessionOptions
|
||||
? { initialSessionOptions: request.initialSessionOptions }
|
||||
: {}),
|
||||
launchSource: request.launchSource,
|
||||
...(request.onPromptDelivered ? { onPromptDelivered: request.onPromptDelivered } : {})
|
||||
})
|
||||
if (!prepared) {
|
||||
const prepared = request.terminalStartup
|
||||
? null
|
||||
: prepareAgentInNewTabLaunch({
|
||||
agent: request.agent,
|
||||
worktreeId: request.workspaceId,
|
||||
...(request.prompt !== undefined ? { prompt: request.prompt } : {}),
|
||||
...(request.promptDelivery ? { promptDelivery: request.promptDelivery } : {}),
|
||||
...(request.tuiCustomization?.agentArgs !== undefined
|
||||
? { agentArgs: request.tuiCustomization.agentArgs }
|
||||
: {}),
|
||||
...(request.tuiCustomization?.cwd !== undefined
|
||||
? { initialCwd: request.tuiCustomization.cwd }
|
||||
: {}),
|
||||
...(request.launchPlatform ? { launchPlatform: request.launchPlatform } : {}),
|
||||
...(request.initialSessionOptions
|
||||
? { initialSessionOptions: request.initialSessionOptions }
|
||||
: {}),
|
||||
launchSource: request.launchSource,
|
||||
...(request.onPromptDelivered ? { onPromptDelivered: request.onPromptDelivered } : {})
|
||||
})
|
||||
if (!prepared && !request.terminalStartup) {
|
||||
return { tabId: null, error: new Error('Could not build the agent startup command.') }
|
||||
}
|
||||
const startup = terminalStartup(request, prepared)
|
||||
const startup = request.terminalStartup ?? terminalStartup(request, prepared!)
|
||||
const state = useAppStore.getState()
|
||||
const runtimeEnvironmentId = getRuntimeEnvironmentIdForWorktree(state, request.workspaceId)
|
||||
let tabId: string | null = null
|
||||
@@ -181,6 +180,7 @@ export async function launchTerminalSession(
|
||||
startup,
|
||||
agent: request.agent,
|
||||
cwd: request.tuiCustomization?.cwd,
|
||||
targetGroupId: request.groupId,
|
||||
activate: request.visibility === 'reveal'
|
||||
})
|
||||
tabId = created?.hostTabId ?? null
|
||||
@@ -188,6 +188,7 @@ export async function launchTerminalSession(
|
||||
activateAndRevealWorkspace(request.workspaceId, {
|
||||
revealInSidebar: true,
|
||||
sidebarRevealBehavior: 'auto',
|
||||
...(request.groupId ? { targetGroupId: request.groupId } : {}),
|
||||
providesInitialSurface: true
|
||||
})
|
||||
}
|
||||
@@ -199,6 +200,7 @@ export async function launchTerminalSession(
|
||||
revealInSidebar: true,
|
||||
sidebarRevealBehavior: 'auto',
|
||||
createNewTerminalForStartup: true,
|
||||
...(request.groupId ? { targetGroupId: request.groupId } : {}),
|
||||
startup,
|
||||
providesInitialSurface: true,
|
||||
...(request.tuiCustomization?.cwd ? { initialCwd: request.tuiCustomization.cwd } : {})
|
||||
@@ -212,9 +214,15 @@ export async function launchTerminalSession(
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{ activateCreatedTabs: false, createNewTerminalForStartup: true }
|
||||
{
|
||||
activateCreatedTabs: false,
|
||||
createNewTerminalForStartup: true,
|
||||
...(request.groupId ? { targetGroupId: request.groupId } : {})
|
||||
}
|
||||
)
|
||||
}
|
||||
const promptDeliveryResult = deliverTerminalPrompt(request, prepared, tabId)
|
||||
const promptDeliveryResult = prepared
|
||||
? deliverTerminalPrompt(request, prepared, tabId)
|
||||
: undefined
|
||||
return { tabId, ...(promptDeliveryResult ? { promptDeliveryResult } : {}) }
|
||||
}
|
||||
|
||||
@@ -62,6 +62,53 @@ describe('launchAgentSession', () => {
|
||||
expect(mocks.launchTerminalSession).toHaveBeenCalledWith(request)
|
||||
})
|
||||
|
||||
it('passes the requested split group through terminal fallback launches', async () => {
|
||||
mocks.planAgentSessionLaunch.mockReturnValue({ route: 'terminal-tui' })
|
||||
mocks.launchTerminalSession.mockResolvedValue({ tabId: 'terminal-1' })
|
||||
|
||||
await launchAgentSession({} as never, { ...request, groupId: 'group-1' })
|
||||
|
||||
expect(mocks.launchTerminalSession).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ groupId: 'group-1' })
|
||||
)
|
||||
})
|
||||
|
||||
it('refuses to turn a structured resume into a fresh terminal launch', async () => {
|
||||
mocks.planAgentSessionLaunch.mockReturnValue({ route: 'terminal-tui' })
|
||||
|
||||
await expect(
|
||||
launchAgentSession({} as never, {
|
||||
...request,
|
||||
resumeFrom: { providerSessionId: 'provider-1' }
|
||||
})
|
||||
).resolves.toMatchObject({
|
||||
kind: 'failed',
|
||||
error: expect.any(Error)
|
||||
})
|
||||
expect(mocks.launchTerminalSession).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('honors an explicit no-fallback request when structured support disappears', async () => {
|
||||
mocks.planAgentSessionLaunch.mockReturnValue({ route: 'terminal-tui' })
|
||||
|
||||
await expect(
|
||||
launchAgentSession({} as never, { ...request, terminalFallback: false })
|
||||
).resolves.toMatchObject({ kind: 'failed', error: expect.any(Error) })
|
||||
expect(mocks.launchTerminalSession).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('uses a caller-planned route and targets the created workspace', async () => {
|
||||
const launch = vi.fn().mockResolvedValue({ kind: 'structured', sessionId: 'session-1' })
|
||||
const launchPlan = { route: 'structured-native-chat', launch } as never
|
||||
|
||||
await expect(
|
||||
launchAgentSession({} as never, { ...request, launchPlan })
|
||||
).resolves.toMatchObject({ kind: 'structured', sessionId: 'session-1' })
|
||||
|
||||
expect(mocks.planAgentSessionLaunch).not.toHaveBeenCalled()
|
||||
expect(launch).toHaveBeenCalledWith(expect.anything(), { worktreeId: request.workspaceId })
|
||||
})
|
||||
|
||||
it('activates a folder workspace before selecting its structured chat', async () => {
|
||||
const order: string[] = []
|
||||
mocks.activateAndRevealWorkspace.mockImplementation(() => {
|
||||
@@ -107,6 +154,26 @@ describe('launchAgentSession', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('reports a terminal fallback error instead of accepting the refusal', async () => {
|
||||
const launch = vi.fn(async (hooks) => {
|
||||
await expect(hooks.legacyFallback()).rejects.toThrow('terminal failed')
|
||||
return { kind: 'failed', error: new Error('terminal failed') }
|
||||
})
|
||||
mocks.planAgentSessionLaunch.mockReturnValue({
|
||||
route: 'structured-native-chat',
|
||||
launch
|
||||
})
|
||||
mocks.launchTerminalSession.mockResolvedValue({
|
||||
tabId: null,
|
||||
error: new Error('terminal failed')
|
||||
})
|
||||
|
||||
await expect(launchAgentSession({} as never, request)).resolves.toMatchObject({
|
||||
kind: 'failed',
|
||||
error: expect.any(Error)
|
||||
})
|
||||
})
|
||||
|
||||
it('suppresses generic failure ownership when terminal fallback is disabled', async () => {
|
||||
const launch = vi.fn().mockResolvedValue({ kind: 'failed', error: new Error('refused') })
|
||||
mocks.planAgentSessionLaunch.mockReturnValue({ route: 'structured-native-chat', launch })
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { LaunchSource } from '../../../shared/telemetry-events'
|
||||
import type { TuiAgent } from '../../../shared/tui-agent'
|
||||
import type { SessionOptionValue } from '../../../shared/native-chat-session-options'
|
||||
import { workspaceKindForWorktreeId, type AgentLaunchRouteStore } from './agent-launch-route-input'
|
||||
import { planAgentSessionLaunch } from './agent-session-launch-plan'
|
||||
import { planAgentSessionLaunch, type AgentSessionLaunchPlan } from './agent-session-launch-plan'
|
||||
import type { NativeChatLaunchPromptDelivery } from './native-chat-initial-view-mode'
|
||||
import { activateStructuredAgentSessionById } from './structured-agent-session-tab-activation'
|
||||
import type { StructuredPromptDeliveryResult } from './structured-agent-session-launch-prompt'
|
||||
@@ -13,10 +13,13 @@ import { toRuntimeWorktreeSelector } from '@/runtime/runtime-worktree-selector'
|
||||
import { useAppStore } from '@/store'
|
||||
import { activateAndRevealWorkspace } from './worktree-activation'
|
||||
import { launchTerminalSession } from './launch-agent-session-terminal'
|
||||
import type { WorktreeStartupPayload } from './worktree-startup-payload'
|
||||
|
||||
export type AgentSessionLaunchRequest = {
|
||||
agent: TuiAgent
|
||||
workspaceId: string
|
||||
/** Existing tab group for a quick-launch fallback; terminal creation must stay in that pane. */
|
||||
groupId?: string
|
||||
prompt?: string
|
||||
promptDelivery?: NativeChatLaunchPromptDelivery
|
||||
tuiCustomization?: { cwd?: string | null; agentArgs?: string | null }
|
||||
@@ -28,6 +31,10 @@ export type AgentSessionLaunchRequest = {
|
||||
signal?: AbortSignal
|
||||
launchSource: LaunchSource
|
||||
terminalFallback?: boolean
|
||||
/** A launch decided before the workspace row existed. Reuse it instead of re-planning. */
|
||||
launchPlan?: AgentSessionLaunchPlan
|
||||
/** Startup payload already built by the caller for a terminal refusal fallback. */
|
||||
terminalStartup?: WorktreeStartupPayload
|
||||
pendingFirstAgentMessageRename?: boolean
|
||||
reconcileUnknownLaunch?: boolean
|
||||
}
|
||||
@@ -72,25 +79,40 @@ export async function launchAgentSession(
|
||||
store: AgentLaunchRouteStore,
|
||||
request: AgentSessionLaunchRequest
|
||||
): Promise<AgentSessionLaunchOutcome> {
|
||||
const plan = planAgentSessionLaunch(store, {
|
||||
agent: request.agent,
|
||||
workspace: {
|
||||
kind: workspaceKindForWorktreeId(request.workspaceId),
|
||||
worktreeId: request.workspaceId
|
||||
},
|
||||
...(request.prompt !== undefined ? { prompt: request.prompt } : {}),
|
||||
...(request.promptDelivery ? { promptDelivery: request.promptDelivery } : {}),
|
||||
...(request.tuiCustomization ? { tuiCustomization: request.tuiCustomization } : {}),
|
||||
...(request.initialSessionOptions
|
||||
? { initialSessionOptions: request.initialSessionOptions }
|
||||
: {}),
|
||||
...(request.resumeFrom ? { resumeFrom: request.resumeFrom } : {}),
|
||||
...(request.onPromptDelivered ? { onPromptDelivered: request.onPromptDelivered } : {}),
|
||||
...(request.terminalFallback === false ? { notifyFailure: false } : {}),
|
||||
...(request.reconcileUnknownLaunch !== undefined
|
||||
? { reconcileUnknownLaunch: request.reconcileUnknownLaunch }
|
||||
: {})
|
||||
})
|
||||
const plan =
|
||||
request.launchPlan ??
|
||||
planAgentSessionLaunch(store, {
|
||||
agent: request.agent,
|
||||
workspace: {
|
||||
kind: workspaceKindForWorktreeId(request.workspaceId),
|
||||
worktreeId: request.workspaceId
|
||||
},
|
||||
...(request.prompt !== undefined ? { prompt: request.prompt } : {}),
|
||||
...(request.promptDelivery ? { promptDelivery: request.promptDelivery } : {}),
|
||||
...(request.tuiCustomization ? { tuiCustomization: request.tuiCustomization } : {}),
|
||||
...(request.initialSessionOptions
|
||||
? { initialSessionOptions: request.initialSessionOptions }
|
||||
: {}),
|
||||
...(request.resumeFrom ? { resumeFrom: request.resumeFrom } : {}),
|
||||
...(request.onPromptDelivered ? { onPromptDelivered: request.onPromptDelivered } : {}),
|
||||
...(request.terminalFallback === false ? { notifyFailure: false } : {}),
|
||||
...(request.reconcileUnknownLaunch !== undefined
|
||||
? { reconcileUnknownLaunch: request.reconcileUnknownLaunch }
|
||||
: {})
|
||||
})
|
||||
if (
|
||||
plan.route !== 'structured-native-chat' &&
|
||||
(request.resumeFrom !== undefined || request.terminalFallback === false)
|
||||
) {
|
||||
return {
|
||||
kind: 'failed',
|
||||
error: new Error(
|
||||
request.resumeFrom
|
||||
? 'Resuming an agent session requires structured chat support.'
|
||||
: 'Structured chat launch is unavailable for this workspace.'
|
||||
)
|
||||
}
|
||||
}
|
||||
if (plan.route !== 'structured-native-chat') {
|
||||
try {
|
||||
const terminal = await launchTerminalSession(request)
|
||||
@@ -113,39 +135,45 @@ export async function launchAgentSession(
|
||||
let viaRefusal = false
|
||||
let fallback: TerminalLaunchResult | null = null
|
||||
try {
|
||||
const settlement = await plan.launch({
|
||||
...(request.terminalFallback === false
|
||||
? {}
|
||||
: {
|
||||
legacyFallback: async () => {
|
||||
viaRefusal = true
|
||||
fallback = await launchTerminalSession(request)
|
||||
return {
|
||||
primaryTabId: fallback.tabId,
|
||||
...(fallback.promptDeliveryResult
|
||||
? { promptDeliveryResult: fallback.promptDeliveryResult }
|
||||
: {})
|
||||
const settlement = await plan.launch(
|
||||
{
|
||||
...(request.terminalFallback === false
|
||||
? {}
|
||||
: {
|
||||
legacyFallback: async () => {
|
||||
viaRefusal = true
|
||||
fallback = await launchTerminalSession(request)
|
||||
if (fallback.error) {
|
||||
throw fallback.error
|
||||
}
|
||||
return {
|
||||
primaryTabId: fallback.tabId,
|
||||
...(fallback.promptDeliveryResult
|
||||
? { promptDeliveryResult: fallback.promptDeliveryResult }
|
||||
: {})
|
||||
}
|
||||
}
|
||||
}),
|
||||
...(request.visibility === 'reveal'
|
||||
? {
|
||||
onStructuredReady: (sessionId: string) => {
|
||||
activateAndRevealWorkspace(request.workspaceId, {
|
||||
providesInitialSurface: true
|
||||
})
|
||||
activateStructuredAgentSessionById({ worktreeId: request.workspaceId, sessionId })
|
||||
structuredTabId =
|
||||
useAppStore
|
||||
.getState()
|
||||
.unifiedTabsByWorktree[request.workspaceId]?.find(
|
||||
(tab) => tab.contentType === 'agent-session' && tab.entityId === sessionId
|
||||
)?.id ?? `agent-session:${sessionId}`
|
||||
}
|
||||
}
|
||||
}),
|
||||
...(request.visibility === 'reveal'
|
||||
? {
|
||||
onStructuredReady: (sessionId: string) => {
|
||||
activateAndRevealWorkspace(request.workspaceId, {
|
||||
providesInitialSurface: true
|
||||
})
|
||||
activateStructuredAgentSessionById({ worktreeId: request.workspaceId, sessionId })
|
||||
structuredTabId =
|
||||
useAppStore
|
||||
.getState()
|
||||
.unifiedTabsByWorktree[request.workspaceId]?.find(
|
||||
(tab) => tab.contentType === 'agent-session' && tab.entityId === sessionId
|
||||
)?.id ?? `agent-session:${sessionId}`
|
||||
}
|
||||
}
|
||||
: {}),
|
||||
...(request.signal ? { signal: request.signal } : {})
|
||||
})
|
||||
: {}),
|
||||
...(request.signal ? { signal: request.signal } : {})
|
||||
},
|
||||
request.launchPlan ? { worktreeId: request.workspaceId } : undefined
|
||||
)
|
||||
if (!settlement) {
|
||||
return { kind: 'failed', error: new Error('Structured launch did not settle.') }
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ describe('settleDirectWorkItemStructuredLaunch', () => {
|
||||
prompt: 'Fix the route',
|
||||
promptDelivery: 'draft',
|
||||
visibility: 'reveal',
|
||||
launchSource: 'task_page'
|
||||
launchSource: 'task_page',
|
||||
launchPlan: structuredPlan
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ export async function settleDirectWorkItemStructuredLaunch(args: {
|
||||
...(plan.promptDelivery ? { promptDelivery: plan.promptDelivery } : {}),
|
||||
...(args.agentArgs !== undefined ? { tuiCustomization: { agentArgs: args.agentArgs } } : {}),
|
||||
...(args.launchPlatform ? { launchPlatform: args.launchPlatform } : {}),
|
||||
launchPlan: plan,
|
||||
visibility: 'reveal',
|
||||
launchSource: args.launchSource
|
||||
})
|
||||
@@ -173,7 +174,7 @@ export async function settleDirectWorkItemStructuredLaunch(args: {
|
||||
completed: false,
|
||||
structuredLaunch: false,
|
||||
visibilityUnknown: false,
|
||||
failed: false,
|
||||
failed: settlement.tabId === null,
|
||||
primaryTabId: settlement.tabId
|
||||
}
|
||||
case 'visibility-unknown':
|
||||
|
||||
@@ -280,6 +280,10 @@ export async function launchWorkItemDirect(args: LaunchWorkItemDirectArgs): Prom
|
||||
primaryTabId = structuredResult.primaryTabId
|
||||
}
|
||||
|
||||
if (structuredResult.failed) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (startupPlanFailed) {
|
||||
toast.error(agentLaunchCommandErrorMessage())
|
||||
return false
|
||||
|
||||
@@ -78,6 +78,8 @@ export async function revealOnboardingFolderWithAgentLaunch(args: {
|
||||
await launchAgentSession(useAppStore.getState(), {
|
||||
agent: args.launch.agent,
|
||||
workspaceId: args.worktreeId,
|
||||
...(plan ? { launchPlan: plan } : {}),
|
||||
...(args.launch.fallbackStartup ? { terminalStartup: args.launch.fallbackStartup } : {}),
|
||||
initialSessionOptions: (args.launch.startup ?? args.launch.fallbackStartup)?.sessionOptions,
|
||||
visibility: 'reveal',
|
||||
launchSource: 'onboarding'
|
||||
|
||||
@@ -27,6 +27,7 @@ export async function spawnWebRuntimeAgentSurface(
|
||||
startup?: WorktreeStartupPayload
|
||||
agent?: TuiAgent | null
|
||||
cwd?: string | null
|
||||
targetGroupId?: string
|
||||
activate?: boolean
|
||||
}
|
||||
): Promise<CreatedWebRuntimeSessionTerminal | null> {
|
||||
@@ -109,6 +110,7 @@ export async function spawnWebRuntimeAgentSurface(
|
||||
? { agent: launchAgent }
|
||||
: {}),
|
||||
...(opts?.cwd ? { cwd: opts.cwd } : {}),
|
||||
...(opts?.targetGroupId ? { targetGroupId: opts.targetGroupId } : {}),
|
||||
activate: opts?.activate !== false,
|
||||
selectWorktree: false
|
||||
})
|
||||
|
||||
@@ -61,6 +61,8 @@ export type WorktreeActivationStore = Partial<WorktreeRuntimeOwnerState> & {
|
||||
}
|
||||
|
||||
export type InitialTerminalOptions = {
|
||||
/** Prefer this existing split group when creating an explicit startup terminal. */
|
||||
targetGroupId?: string
|
||||
activateCreatedTabs?: boolean
|
||||
backendStartupTerminalSpawned?: boolean
|
||||
/** Create a preserved fallback startup beside setup/default terminals. */
|
||||
|
||||
@@ -16,6 +16,8 @@ export type WorktreeActivationSurfaceSelection = {
|
||||
}
|
||||
|
||||
export type WorktreeActivationOptions = WorktreeActivationSurfaceSelection & {
|
||||
/** Prefer this existing split group when creating an explicit startup terminal. */
|
||||
targetGroupId?: string
|
||||
startup?: WorktreeStartupPayload
|
||||
initialCwd?: string
|
||||
setup?: WorktreeSetupLaunch
|
||||
|
||||
@@ -51,7 +51,8 @@ export type ActivateAndRevealResult = {
|
||||
function ensureFolderWorkspaceInitialTerminal(
|
||||
folderWorkspace: FolderWorkspace,
|
||||
startup?: WorktreeStartupPayload,
|
||||
providesInitialSurface?: boolean
|
||||
providesInitialSurface?: boolean,
|
||||
targetGroupId?: string
|
||||
): string | null {
|
||||
if (providesInitialSurface === true && startup === undefined) {
|
||||
return null
|
||||
@@ -65,7 +66,10 @@ function ensureFolderWorkspaceInitialTerminal(
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{ reseedEmptiedWorkspace: providesInitialSurface !== true }
|
||||
{
|
||||
reseedEmptiedWorkspace: providesInitialSurface !== true,
|
||||
...(targetGroupId ? { targetGroupId } : {})
|
||||
}
|
||||
)
|
||||
return primaryTabId
|
||||
}
|
||||
@@ -83,6 +87,7 @@ export function activateAndRevealFolderWorkspace(
|
||||
opts?: WorktreeActivationSurfaceSelection & {
|
||||
sidebarRevealBehavior?: PendingSidebarWorktreeReveal['behavior']
|
||||
revealInSidebar?: boolean
|
||||
targetGroupId?: string
|
||||
startup?: WorktreeStartupPayload
|
||||
runtimeEnvironmentId?: string | null
|
||||
executionHostId?: ExecutionHostId
|
||||
@@ -156,7 +161,12 @@ export function activateAndRevealFolderWorkspace(
|
||||
}
|
||||
const primaryTabId = shouldGateAgentActivation
|
||||
? null
|
||||
: ensureFolderWorkspaceInitialTerminal(folderWorkspace, opts?.startup, providesInitialSurface)
|
||||
: ensureFolderWorkspaceInitialTerminal(
|
||||
folderWorkspace,
|
||||
opts?.startup,
|
||||
providesInitialSurface,
|
||||
opts?.targetGroupId
|
||||
)
|
||||
|
||||
if (opts?.revealInSidebar !== false) {
|
||||
state.revealWorktreeInSidebar(
|
||||
@@ -267,6 +277,7 @@ export function activateAndRevealWorktree(
|
||||
opts?.issueCommand,
|
||||
opts?.defaultTabs,
|
||||
{
|
||||
...(opts?.targetGroupId ? { targetGroupId: opts.targetGroupId } : {}),
|
||||
...(opts?.backendStartupTerminalSpawned ? { backendStartupTerminalSpawned: true } : {}),
|
||||
...(opts?.createNewTerminalForStartup ? { createNewTerminalForStartup: true } : {}),
|
||||
...(providesInitialSurface ? { callerProvidesSurface: true } : {}),
|
||||
|
||||
@@ -220,7 +220,8 @@ export async function executeWorktreeCreation(
|
||||
worktreeId: worktree.id,
|
||||
shouldActivateOnCompletion,
|
||||
activation,
|
||||
primaryTabId
|
||||
primaryTabId,
|
||||
fallbackStartupOpt
|
||||
})
|
||||
structuredLaunchAccepted = structuredSession.accepted
|
||||
activation = structuredSession.activation
|
||||
|
||||
@@ -91,7 +91,8 @@ describe('launchStructuredWorktreeSession', () => {
|
||||
launchSource: 'new_workspace_composer',
|
||||
pendingFirstAgentMessageRename: true,
|
||||
reconcileUnknownLaunch: undefined,
|
||||
signal: expect.any(AbortSignal)
|
||||
signal: expect.any(AbortSignal),
|
||||
launchPlan: expect.objectContaining({ route: 'structured-native-chat' })
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { AgentLaunchRoute } from '@/lib/agent-launch-routing'
|
||||
import type { WorktreeCreationRequest } from '@/lib/pending-worktree-creation'
|
||||
import type { WorktreeStartupPayload } from '@/lib/worktree-startup-payload'
|
||||
import { launchAgentSession } from '@/lib/launch-agent-session'
|
||||
import { adoptAgentSessionLaunchVerdict } from '@/lib/agent-session-launch-plan'
|
||||
|
||||
export type WorktreeCreationStructuredSessionResult = {
|
||||
accepted: boolean
|
||||
@@ -42,6 +43,18 @@ export async function launchStructuredWorktreeSession(
|
||||
if (!useAppStore.getState().pendingWorktreeCreations[args.creationId]) {
|
||||
return { ...settled, cancelled: true, activation, primaryTabId }
|
||||
}
|
||||
const launchPlan = adoptAgentSessionLaunchVerdict({
|
||||
route: args.agentLaunchRoute,
|
||||
agent,
|
||||
worktreeId: args.worktreeId,
|
||||
...(args.recoverUnknownLaunch
|
||||
? {}
|
||||
: {
|
||||
prompt: args.request.launchDraftPrompt ?? args.request.quickPrompt,
|
||||
...(args.request.promptDelivery ? { promptDelivery: args.request.promptDelivery } : {})
|
||||
}),
|
||||
...(args.recoverUnknownLaunch ? { reconcileUnknownLaunch: args.recoverUnknownLaunch } : {})
|
||||
})
|
||||
const abandoned = new AbortController()
|
||||
const unsubscribe = useAppStore.subscribe((state) => {
|
||||
if (!state.pendingWorktreeCreations[args.creationId]) {
|
||||
@@ -61,6 +74,8 @@ export async function launchStructuredWorktreeSession(
|
||||
}),
|
||||
visibility: args.shouldActivateOnCompletion ? 'reveal' : 'background',
|
||||
launchSource: args.request.quickTelemetry?.launch_source ?? 'new_workspace_composer',
|
||||
launchPlan,
|
||||
...(args.fallbackStartupOpt ? { terminalStartup: args.fallbackStartupOpt } : {}),
|
||||
pendingFirstAgentMessageRename: args.request.pendingFirstAgentMessageRename,
|
||||
reconcileUnknownLaunch: args.recoverUnknownLaunch,
|
||||
signal: abandoned.signal
|
||||
|
||||
@@ -48,25 +48,30 @@ export function applyDefaultTerminalTabs(
|
||||
: isStartupTab && startup?.telemetry
|
||||
? (agentKindToTuiAgent(startup.telemetry.agent_kind) ?? undefined)
|
||||
: undefined
|
||||
const tab = store.createTab(worktreeId, undefined, undefined, {
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false,
|
||||
...(launchAgent
|
||||
? {
|
||||
launchAgent,
|
||||
...initialAgentTabViewModeProps(store.settings ?? null, {
|
||||
agent: launchAgent,
|
||||
...draftViewModeProps(
|
||||
isStartupTab ? resolveStartupLaunchDraftText(startup) : undefined
|
||||
),
|
||||
nativeChatTranscriptIsLocalReadable: isNativeChatTranscriptLocalReadable(
|
||||
getConnectionId(worktreeId)
|
||||
)
|
||||
})
|
||||
}
|
||||
: {}),
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {})
|
||||
})
|
||||
const tab = store.createTab(
|
||||
worktreeId,
|
||||
index === 0 ? opts?.targetGroupId : undefined,
|
||||
undefined,
|
||||
{
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false,
|
||||
...(launchAgent
|
||||
? {
|
||||
launchAgent,
|
||||
...initialAgentTabViewModeProps(store.settings ?? null, {
|
||||
agent: launchAgent,
|
||||
...draftViewModeProps(
|
||||
isStartupTab ? resolveStartupLaunchDraftText(startup) : undefined
|
||||
),
|
||||
nativeChatTranscriptIsLocalReadable: isNativeChatTranscriptLocalReadable(
|
||||
getConnectionId(worktreeId)
|
||||
)
|
||||
})
|
||||
}
|
||||
: {}),
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {})
|
||||
}
|
||||
)
|
||||
if (index === 0) {
|
||||
firstTabId = tab.id
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ export function ensureWorktreeHasInitialTerminal(
|
||||
(sequencedStartup?.telemetry
|
||||
? (agentKindToTuiAgent(sequencedStartup.telemetry.agent_kind) ?? undefined)
|
||||
: undefined)
|
||||
const terminalTab = store.createTab(worktreeId, undefined, undefined, {
|
||||
const terminalTab = store.createTab(worktreeId, opts?.targetGroupId, undefined, {
|
||||
pendingActivationSpawn: true,
|
||||
...(launchAgent
|
||||
? {
|
||||
|
||||
Reference in New Issue
Block a user