Async terminal for CLI in chat panel#312178
Conversation
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a proposed chat sessions API for extensions to inject system-initiated “notification-style” turns into chat sessions they own, and wires it up for Copilot CLI sessions so async SDK/terminal completions can surface as new chat bubbles.
Changes:
- Add
vscode.chat.sendSystemInitiatedRequest(...)proposed API + options type. - Implement ext host ↔ main thread plumbing to enqueue a steering, system-initiated chat request with a label.
- Update Copilot CLI chat sessions to forward SDK
system.notificationevents into the chat panel and keep SDK sessions alive long enough for async completions to arrive.
Show a summary per file
| File | Description |
|---|---|
| src/vscode-dts/vscode.proposed.chatSessionsProvider.d.ts | Adds proposed API surface for system-initiated chat requests. |
| src/vs/workbench/api/common/extHostChatSessions.ts | Validates ownership + forwards requests to main thread via RPC. |
| src/vs/workbench/api/common/extHost.protocol.ts | Extends main-thread chat sessions shape with $sendSystemInitiatedRequest. |
| src/vs/workbench/api/common/extHost.api.impl.ts | Exposes chat.sendSystemInitiatedRequest to extensions under proposed API gate. |
| src/vs/workbench/api/browser/mainThreadChatSessions.ts | Receives RPC and enqueues a steering system-initiated request in IChatService. |
| extensions/copilot/src/extension/chatSessions/vscode-node/copilotCLIChatSessions.ts | Forwards CLI SDK system notifications into chat via the new API; passes through isSystemInitiated. |
| extensions/copilot/src/extension/chatSessions/copilotcli/node/test/testHelpers.ts | Updates mock SDK session helper with an on(...) method to match usage. |
| extensions/copilot/src/extension/chatSessions/copilotcli/node/test/copilotcliSession.spec.ts | Extends test mock with getBackgroundTasks() to satisfy new logging/inspection. |
| extensions/copilot/src/extension/chatSessions/copilotcli/node/copilotcliSessionService.ts | Emits onDidReceiveSystemNotification and adds a post-turn keep-alive ref window. |
| extensions/copilot/src/extension/chatSessions/copilotcli/node/copilotcliSession.ts | Translates SDK system.notification to a typed event; adds system-initiated request handling path. |
Copilot's findings
Comments suppressed due to low confidence (1)
extensions/copilot/src/extension/chatSessions/copilotcli/node/copilotcliSession.ts:357
- There is new behavior for
request.isSystemInitiatedthat changes how requests are handled (skipping_sdkSession.send()and waiting for the nextassistant.turn_end). The existing unit tests forCopilotCLISessiondon't cover theisSystemInitiatedpath; please add a test that asserts the SDKsend()is not called and that the handler resolves onassistant.turn_end/ cancellation.
}
if (isAlreadyBusyWithAnotherRequest) {
return this._handleRequestSteering(input, attachments, model, previousRequestSnapshot, token);
} else {
return this._handleRequestImpl(request, input, attachments, model, token, /*isSystemInitiated*/ false);
}
});
- Files reviewed: 9/10 changed files
- Comments generated: 5
|
@DonJayamanne @rebornix @mattbierner Don't think vscode/src/vscode-dts/vscode.proposed.chatSessionsProvider.d.ts Lines 446 to 453 in ad4cb84 I think the biggest thing against VS. (This PR with new proposed api): The approach from the PR we'd have no stalling shimmer, but would have new compact "system" bubble appear for async output such as
|
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
…path Co-authored-by: Copilot <copilot@github.com>
|
@roblourens @TylerLeonhardt Screen.Recording.2026-04-23.at.2.22.09.PM.movHere is equivalent in Copilot CLI. We could improve to better distinguish the async terminal output but it seems like CLI themselves are not doing explicit labeling either. Maybe the color of the decorations are meant to signify something? /cc @justschen For chat ui |
Co-authored-by: Copilot <copilot@github.com>
| // task list only includes *detached* shells and background agents, not | ||
| // plain `mode: "async"` shells (they're tracked internally by | ||
| // `shellContext.currentExecutions`). A status-based window matches the | ||
| // existing `sessionTerminators` 5-minute lifetime and covers every |
There was a problem hiding this comment.
@DonJayamanne @roblourens I'm not so sure about this 5-minute lifetime thing. I can see it was existing previously but don't have context over what specific thing it was meant for, maybe we can do something better here for async terminals and keeping session alive.
There was a problem hiding this comment.
Can we try to use getBackgroundTaskProgress and refreshBackgroundTasks in conjuction with getBackgroundTasks (methods in the SDK)
If the current API isn't going to work, then I think we'll need new API from CLI.
Please try the above, perhaps try Opus 4.7, we might be able to make use of these (specially refreshBackgroundTasks).
I don't think we shoudl have any timeout be it 5minutes or 1 minute or 15 iminutes, at the end of the day, they'll all be wrong in one case or another.
There was a problem hiding this comment.
I think we may need a new API to get this working since it seems like both getBackgroundTaskProgress and refreshBackgroundTasks excludes non-detached shells, meaning for async runs like sleep some time and get back, it wouldn't be tracked via the two getBackgroundTaskProgress and refreshBackgroundTasks.
There was a problem hiding this comment.
Replied offline with possible solutions.
|
Base:
|
Co-authored-by: Copilot <copilot@github.com>
| const disposables = new DisposableStore(); | ||
| try { | ||
| await new Promise<void>(resolve => { | ||
| const off = this._sdkSession.on('assistant.turn_end', () => resolve()); |
There was a problem hiding this comment.
what happens if the next turn also starts an async terminal call?
There was a problem hiding this comment.
There was a problem hiding this comment.
Figured out what's happening: 283a8ee for description but we'd need something more proper to make sure the confirmation gets passed appropriately
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>



Resolves: #309290
*WIP almost there
Both route with/without controller api should work.