Add Aspire editor assistance language model tools - #19414
Add Aspire editor assistance language model tools#19414Adam Ratzman (adamint) wants to merge 38 commits into
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e3c8fa3a-d5fd-427d-baa5-3d0c1334a513
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e3c8fa3a-d5fd-427d-baa5-3d0c1334a513
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 19414Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 19414" |
There was a problem hiding this comment.
Pull request overview
Adds five privacy-bounded VS Code language-model tools for inspecting Aspire debug state, explaining launch failures, and opening relevant UI.
Changes:
- Adds editor-state snapshots, safe AppHost resolution, failure journaling, and telemetry.
- Adds confirmation-gated Dashboard and Output handoffs.
- Extends debugger metadata and comprehensive unit/E2E coverage.
Show a summary per file
| File | Description |
|---|---|
extension/telemetry.json |
Defines new telemetry events. |
extension/src/views/AspireAppHostTreeProvider.ts |
Reuses Dashboard URL validation. |
extension/src/utils/telemetryRegistry.ts |
Types new telemetry schemas. |
extension/src/utils/appHostIdentity.ts |
Adds opaque lexical identities. |
extension/src/types/extensionApi.ts |
Extends E2E invocation controls. |
extension/src/testing/e2eStateFileBridge.ts |
Supports testing all LM tools. |
extension/src/testing/e2eStateFileBridge.production.ts |
Updates production bridge signature. |
extension/src/test/telemetryInventory.test.ts |
Adjusts telemetry inventory test. |
extension/src/test/strings.test.ts |
Verifies localized confirmations. |
extension/src/test/rustDebugger.test.ts |
Tests typed Rust build failures. |
extension/src/test/launchFailureTelemetry.test.ts |
Tests sanitized failure telemetry. |
extension/src/test/dotnetDebugger.test.ts |
Tests typed .NET build failures. |
extension/src/test/dcpTypes.test.ts |
Tests safe launch-path extraction. |
extension/src/test/AspireExtensionContext.test.ts |
Tests assistance-state lifecycle. |
extension/src/test/aspireDebugConfigurationProvider.test.ts |
Tests discovery-failure journaling. |
extension/src/test/appHostLifecycleTools.test.ts |
Updates lifecycle-tool coverage. |
extension/src/test/appHostDataRepository.test.ts |
Tests one-shot resource queries. |
extension/src/test/adapterTracker.test.ts |
Tests AppHost termination attribution. |
extension/src/test-e2e/packageSurface.e2e.test.ts |
Verifies packaged tool contributions. |
extension/src/test-e2e/appHostLifecycleTools.e2e.test.ts |
Exercises assistance tools end-to-end. |
extension/src/services/launchFailureJournal.ts |
Implements bounded failure journal. |
extension/src/services/editorAssistanceWindowState.ts |
Resets activation-scoped state. |
extension/src/services/AppHostLaunchService.ts |
Exposes safe session state and journaling. |
extension/src/services/appHostLaunchReservations.ts |
Reports pending external runs. |
extension/src/services/appHostLaunchContracts.ts |
Defines safe session snapshots. |
extension/src/server/interactionService.ts |
Reuses Dashboard-launch helpers. |
extension/src/loc/strings.ts |
Adds localized confirmation strings. |
extension/src/lm/safeAppHostTargetResolver.ts |
Resolves trusted workspace AppHosts. |
extension/src/lm/languageModelToolUi.ts |
Escapes confirmation Markdown. |
extension/src/lm/editorUiHandoffService.ts |
Handles Dashboard and Output UI. |
extension/src/lm/editorStateSnapshotService.ts |
Produces bounded session summaries. |
extension/src/lm/editorAssistanceToolContracts.ts |
Defines tool contracts and validation. |
extension/src/lm/editorAssistanceToolAdapters.ts |
Registers the five tools. |
extension/src/lm/editorAssistanceTelemetry.ts |
Emits bounded result telemetry. |
extension/src/lm/appHostLifecycleToolService.ts |
Shares safe target resolution. |
extension/src/lm/appHostLifecycleTools.ts |
Updates lifecycle exports. |
extension/src/lm/appHostLifecycleToolContracts.ts |
Extends lifecycle service contracts. |
extension/src/lm/appHostLifecycleToolAdapters.ts |
Shares UI escaping and E2E access. |
extension/src/extension.ts |
Wires editor-assistance services. |
extension/src/debugger/languages/rust.ts |
Uses typed build failures. |
extension/src/debugger/languages/dotnet.ts |
Uses typed build failures. |
extension/src/debugger/debuggerExtensions.ts |
Captures structured resource identity. |
extension/src/debugger/AspireDebugConfigurationProviderInternal.ts |
Tracks recorded discovery failures. |
extension/src/debugger/AspireDebugConfigurationProvider.ts |
Journals terminal launch failures. |
extension/src/debugger/appHostBuildFailureError.ts |
Defines build-failure boundary type. |
extension/src/debugger/adapterTracker.ts |
Tracks explicit AppHost termination. |
extension/src/dcp/types.ts |
Extracts safe target/executable paths. |
extension/src/data/AppHostDataRepository.ts |
Exposes cancellable resource snapshots. |
extension/src/AspireExtensionContext.ts |
Exposes safe editor session projections. |
extension/package.nls.json |
Adds localized manifest strings. |
extension/package.json |
Contributes and activates new tools. |
extension/loc/xlf/aspire-vscode.xlf |
Updates localization catalog. |
Review details
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 58/59 changed files
- Comments generated: 2
- Review effort level: Balanced
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
|
Copilot review |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Bind confirmed AppHost operations and launch attribution to canonical target identities, and preserve disabled resource commands in followed CLI snapshots. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
|
Copilot review |
There was a problem hiding this comment.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/data/AppHostDataRepository.ts:632
- These describe streams are keyed only by their lexical launch path, but
compareAppHostIdentityre-resolves that path against the current filesystem. If a symlink used to launch AppHost A is retargeted to AppHost B, the still-running A stream now compares as B and its cached resources are returned to B's status request. This can affirm a resource that does not exist in the selected AppHost. Capture the opaque target identity when each stream starts and require that stored identity to match the request instead of re-resolving the stream key.
private _getAppHostResources(appHostPath: string): ResourceJson[] {
const matchingStreams = Array.from(this._describeStreams.entries())
.filter(([currentAppHostPath]) => compareAppHostIdentity(currentAppHostPath, appHostPath) === 'same');
return matchingStreams.length === 1
? Array.from(matchingStreams[0][1].resources.values())
: [];
- Files reviewed: 70/71 changed files
- Comments generated: 1
- Review effort level: Balanced
Resolve Dashboard ownership globally by CLI process identity so a retargeted AppHost path cannot turn an editor-owned row into an ownerless handoff. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
|
Copilot review |
There was a problem hiding this comment.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
extension/src/data/appHostPsPoller.ts:359
- Every follow line received during an authoritative snapshot sets the pending flag, and completion immediately starts another
aspire psprocess at line 349. With a continuously activeps --followstream, each snapshot overlaps at least one update, so reconciliation becomes a back-to-back process loop instead of periodic polling. Debounce the retry until activity is quiet (or rely on the existing interval) rather than scheduling it immediately for every replayed delta.
this._authoritativeSnapshotPending = true;
extension/src/dcp/types.ts:165
- For a direct Node/Bun launch,
runtime_executableis optional and the debugger intentionally defaults to the runtime (node.ts:34-40). Returning no executable identity here means an active legacy/default-runtime session cannot match a resource whose snapshot reportsexecutable.pathasnodeorbun, so the status tool incorrectly returnsnotDebugging. Use the runtime type as the default identity when this field is absent.
if (isJavaScriptRuntimeLaunchConfiguration(configuration)) {
const runtimeExecutable = getNonEmptyPath(configuration.runtime_executable);
return runtimeExecutable === undefined ? [] : [runtimeExecutable];
- Files reviewed: 70/71 changed files
- Comments generated: 1
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Bound confirmation state by outstanding invocations, preserve fail-closed tombstones for overlapping or unresolved preparations, and disable handoff if the concurrent preparation limit is exceeded. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
|
Copilot review |
There was a problem hiding this comment.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
extension/src/lm/editorUiHandoffService.ts:121
- This reports
openedeven when the notification was not shown.showDashboardLaunchNotificationcatches a synchronousshowInformationMessagefailure (and asynchronous rejection), logs it, and returnsvoid, so this tool cannot distinguish that failure from a successful presentation. Have the shared helper return/await a success result and return the boundederroroutcome when presentation fails.
if (resolvedBehavior.behavior === 'notification') {
showDashboardLaunchNotification({
baseUrl: dashboardUrl,
source: resolvedBehavior.source,
});
return { outcome: 'opened', presentation: 'notification' };
- Files reviewed: 70/71 changed files
- Comments generated: 1
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2b9501ad-f5ba-4bc8-a7c2-ccdfaf15061c
|
Copilot review |
Description
Copilot can start and stop an Aspire AppHost, but it could not safely answer the editor-owned
questions that usually come next: is this AppHost already debugging, which Aspire sessions are
active, where is the Dashboard, what happened during the last failed launch, and how do I get the
Aspire Output view in front of the user?
This adds five narrow VS Code language-model tools:
aspire_debug_session_statusaspire_list_debug_sessionstruncatedmarker when neededaspire_open_dashboardopenedand one bounded presentation bucketaspire_open_outputopenedaspire_explain_launch_failureThese are editor-assistance tools, not lifecycle or diagnostic tools. They do not start, stop, or
restart AppHosts/resources, scrape terminal output, summarize logs, return Dashboard URLs, or add a
second MCP implementation.
One editor-assistance subsystem
The tools are thin adapters over four shared services:
SafeAppHostTargetResolverresolves only AppHosts already discovered through the Aspireworkspace registry. It supports multi-root workspaces, returns absolute paths only inside the
extension, and exposes workspace-relative display paths to tool results and confirmation copy.
EditorStateSnapshotServiceprojects editor-owned Aspire run/debug sessions into bounded AppHostand resource summaries. Full, active-only, and exact-AppHost queries now share one projection
pipeline.
EditorUiHandoffServiceuses the existing Dashboard launcher/browser policy and Aspire Outputchannel. It does not duplicate browser selection, Dashboard ownership, or CLI resource-state logic.
LaunchFailureJournalstores only normalized launch-failure categories in memory for the lifetimeof the extension window.
Aspire CLI remains the control plane for AppHost/resource discovery and running-state refresh.
Trust, identity, and confirmation
Language-model input is treated as untrusted.
when: "isWorkspaceTrusted".filesystem.
retargeting changes identity, while an atomic save or checkout of the same AppHost does not.
user accepts. A model cannot confirm one AppHost and swap the selector before the UI operation.
retired, overlapping or unresolved preparations retain fail-closed invocation slots, and
exceeding the concurrent preparation limit disables the handoff for that extension activation.
PID both match the fresh repository row. Ownerless external CLI rows fail closed because they do
not carry a launch-time identity that remains trustworthy after symlink retargeting or file
replacement.
show(true), so the Output view opens withoutstealing focus from the active editor.
Bounded session results
aspire_debug_session_statusreturns only:runningstartingstoppingnotDebuggingmultipleSessionsWith
resourceName, lookup is scoped to the exact resolved AppHost and refreshed through CLI-backedresource state. Missing or duplicate exact names fail closed. The result does not include the
resource snapshot or resource properties.
aspire_list_debug_sessionsreports only editor-owned active AppHost summaries. Each item containsthe safe AppHost display path plus bounded
state,controller, andmodevalues. Results aresorted, capped at 20, and marked
truncatedwhen more active AppHosts exist.Launch-failure journal
Launch failures are captured where they occur during discovery, validation, CLI launch, build, DCP
startup, debug-session startup, and Dashboard opening. The original error is normalized immediately
and discarded.
Each record contains only:
The journal is memory-only, keeps at most five failures per AppHost and 50 globally, and expires
records after approximately 30 minutes. Launch-attempt fallback suppression is correlated to the
exact internal launch token so one launch cannot hide another launch's failure.
aspire_explain_launch_failuremaps the latest unexpired record to bounded action identifiers suchas
fixBuildErrors,installAspireCli,freeRequiredPort, orretryLaunch. It does not manufacturedetailed guidance when the normalized category is
unknown.Privacy boundary
Tool results, telemetry, journal records, and persisted E2E evidence do not contain:
The packaged Extension Host tests recursively inspect the persisted editor-assistance artifact for
these values rather than checking only individual result fields.
Telemetry
Two typed events were added:
aspire/vscode/editorassistance/resultaspire/vscode/launchfailure/recordedThey accept only bounded dimensions:
AppHost paths, resource names, caller-supplied extension IDs, URLs, and raw errors are not accepted.
Tests inspect the exact telemetry payloads and classifications in
telemetry.json.Edge-case coverage
disconnect(false)does not hide startup failureThe scenarios that need a synthetic clock, more than 20 concurrent sessions, duplicate internal
resource snapshots, or symlink retargeting stay in focused unit tests. The user-facing paths run
through a packaged VSIX in a real VS Code Extension Host and call
vscode.lm.invokeTool.Screenshots / recordings
Dashboard confirmation:
Output confirmation:
These are real VS Code confirmation dialogs captured during the packaged Extension Host run. There
is no meaningful "before" screenshot because the change adds language-model tool entry points rather
than changing an existing visible view.
Validation
Final head:
46dad7cec0cf9991f52ac9048164d4a745d30ed1yarn compile-tests,yarn compile, andyarn lintDescribeCommandTests— 34/34 passingThe tree-actions failure on the previous head exposed a CLI follow-mode bug: the
includeDisabledCommandsvalue was passed positionally as the environment-value flag. The call nowuses the named argument, preserving environment-value behavior and including disabled commands in
the streamed snapshot. The command-level regression test and packaged tree-actions scenario both
cover this path.
No dependency versions, lockfiles, or MCP contributions changed.
Checklist
<remarks />and<code />elements on your triple slash comments?