-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(web-shell): support daemon session branching #5613
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3394,14 +3394,14 @@ export function createAcpSessionBridge(opts: BridgeOptions): AcpSessionBridge { | |||||
|
|
||||||
| let restored; | ||||||
| try { | ||||||
| restored = await restoreSession('resume', { | ||||||
| restored = await restoreSession('load', { | ||||||
| sessionId: result.newSessionId, | ||||||
| workspaceCwd: boundWorkspace, | ||||||
| clientId: context?.clientId, | ||||||
| }); | ||||||
| } catch (restoreErr) { | ||||||
| writeStderrLine( | ||||||
| `qwen serve: branchSession resume failed for ${result.newSessionId}, attempting cleanup...`, | ||||||
| `qwen serve: branchSession load failed for ${result.newSessionId}, attempting cleanup...`, | ||||||
| ); | ||||||
| try { | ||||||
| await ci.connection.extMethod( | ||||||
|
|
@@ -3429,8 +3429,9 @@ export function createAcpSessionBridge(opts: BridgeOptions): AcpSessionBridge { | |||||
| data: eventData, | ||||||
| ...(originatorClientId ? { originatorClientId } : {}), | ||||||
| }; | ||||||
| entry.events.publish(branchEnvelope); | ||||||
| broadcastWorkspaceEvent(branchEnvelope, sessionId); | ||||||
| // The branch announcement belongs to the new session only. Publishing | ||||||
| // it on the source session would persist in that session's replay ring. | ||||||
| newEntry?.events.publish(branchEnvelope); | ||||||
|
|
||||||
| return { | ||||||
| ...restored, | ||||||
|
|
@@ -4350,6 +4351,81 @@ export function createAcpSessionBridge(opts: BridgeOptions): AcpSessionBridge { | |||||
| }; | ||||||
| }, | ||||||
|
|
||||||
| async launchSessionForkAgent(sessionId, directive, context) { | ||||||
| const entry = byId.get(sessionId); | ||||||
| if (!entry) throw new SessionNotFoundError(sessionId); | ||||||
| const info = channelInfoForEntry(entry); | ||||||
| if (!info || info.isDying) throw new SessionNotFoundError(sessionId); | ||||||
| resolveTrustedClientId(entry, context?.clientId); | ||||||
|
|
||||||
| const trimmed = directive.trim(); | ||||||
| if (!trimmed) { | ||||||
| throw new Error('Fork directive is required'); | ||||||
| } | ||||||
| if (entry.pendingPromptCount > 0 || entry.promptActive) { | ||||||
| throw new SessionBusyError( | ||||||
| sessionId, | ||||||
| 'Cannot fork while a response or tool call is in progress', | ||||||
| ); | ||||||
| } | ||||||
| return entry.promptQueue.then(async () => { | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] This means a
Suggested change
…and after the closing entry.promptQueue = forkResult.then(() => undefined, () => undefined);
return forkResult;— qwen3.7-max via Qwen Code /review |
||||||
| if (entry.pendingPromptCount > 0 || entry.promptActive) { | ||||||
| throw new SessionBusyError( | ||||||
| sessionId, | ||||||
| 'Cannot fork while a response or tool call is in progress', | ||||||
| ); | ||||||
| } | ||||||
|
|
||||||
| opts.onDiagnosticLine?.( | ||||||
| `qwen serve: launchSessionForkAgent requested for session=${sessionId}`, | ||||||
| 'info', | ||||||
| ); | ||||||
|
|
||||||
| let response: { | ||||||
| description?: string; | ||||||
| launched?: boolean; | ||||||
| }; | ||||||
| try { | ||||||
| response = (await Promise.race([ | ||||||
| withTimeout( | ||||||
| entry.connection.extMethod( | ||||||
| SERVE_CONTROL_EXT_METHODS.sessionForkAgent, | ||||||
| { | ||||||
| sessionId, | ||||||
| directive: trimmed, | ||||||
| }, | ||||||
| ), | ||||||
| initTimeoutMs, | ||||||
| SERVE_CONTROL_EXT_METHODS.sessionForkAgent, | ||||||
| ), | ||||||
| getTransportClosedReject(entry), | ||||||
| ])) as { | ||||||
| description?: string; | ||||||
| launched?: boolean; | ||||||
| }; | ||||||
| } catch (error) { | ||||||
| opts.onDiagnosticLine?.( | ||||||
| `qwen serve: launchSessionForkAgent failed for session=${sessionId}: ${ | ||||||
| error instanceof Error ? error.message : String(error) | ||||||
| }`, | ||||||
| 'warn', | ||||||
| ); | ||||||
| throw error; | ||||||
| } | ||||||
|
|
||||||
| const result = { | ||||||
| sessionId: entry.sessionId, | ||||||
| description: response.description ?? trimmed.slice(0, 60), | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The fallback description Consider importing or replicating the collapse helper:
Suggested change
— qwen3.7-max via Qwen Code /review |
||||||
| launched: response.launched === true, | ||||||
| }; | ||||||
| opts.onDiagnosticLine?.( | ||||||
| `qwen serve: launchSessionForkAgent completed for session=${sessionId} launched=${result.launched}`, | ||||||
| 'info', | ||||||
| ); | ||||||
| return result; | ||||||
| }); | ||||||
| }, | ||||||
|
|
||||||
| async executeShellCommand( | ||||||
| sessionId, | ||||||
| command, | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.