Aquarium-as-sessions for Agent Host new-chat#316656
Draft
osortega wants to merge 3 commits into
Draft
Conversation
Turns the decorative aquarium in the Agents window's new-chat view into a
live 1:1 visualization of running Agent Host sessions, gated behind a
hidden developer-only setting so the experience never ships to users by
default.
Behavior is activated only when ALL THREE of the following are true (the
"triple-gate"):
1. `sessions.developerJoy.enabled` (existing public experimental key) is `true`.
2. `sessions.developerJoy.aquariumAsSessions` (NEW hidden, intentionally
unregistered, key) is `true`. To opt in, hand-edit `settings.json`:
```json
{
"sessions.developerJoy.enabled": true,
"sessions.developerJoy.aquariumAsSessions": true
}
```
The key is NOT in the configuration schema; it won't appear in Settings
UI, IntelliSense, or default-settings exports. A schema-guard unit
test (`aquariumConfiguration.test.ts`) asserts this invariant.
3. The selected workspace OR the active session matches
`ANY_AGENT_HOST_PROVIDER_RE` (`local-agent-host` + `agenthost-*`).
If any of the three flips false, the original decorative aquarium and
always-visible chat input behavior is restored — live, no reload.
When the gate is on:
* Chat input + workspace picker are hidden behind a transparent
click-catcher hotspot. Click, tab into, or activate the hotspot to
reveal the input. Dismiss is hybrid: auto-dismiss 250 ms after submit
success (0 ms when motion-reduced), outside-click (skipping menus and
popups), and Esc on an empty input.
* The aquarium renders one fish per running agent-host session. Fish
color tracks status (in-progress / needs-input / completed / error).
Fish appear and fade out as sessions come and go, with a soft cap of
20 evicting oldest-terminal first.
* Each fish occasionally emits a chat bubble with that session's current
`description` activity text — truncated, dwell-gated, hover-locked.
Max 6 visible bubbles.
* Submitting a chat records a submit-intent (5 s window). The first
session-fish added during that window spawns small (~18 px) and
ease-out-cubic tweens to full size (~56 px) over 18 s. Reduced-motion
spawns at half-grown with no tween.
* Two telemetry events fire (`aquarium.populationMode`,
`aquarium.chatInput`) so we can see adoption + which dismiss triggers
are used. Owner is provisionally `osortega`; confirm before moving the
PR out of draft.
Architecture: the engine in `aquariumOverlay.ts` is split into a host +
swappable `IAquariumPopulationDriver`. The default `RandomPopulationDriver`
preserves today's 50-fish crowd; the new `SessionPopulationDriver` is
attached on demand via `IMountedToggleHandle.setDriverFactory`. The chat
widget gates the swap behind the triple-gate evaluation and reacts to
configuration + workspace-picker + active-session changes.
Files added:
src/vs/sessions/contrib/aquarium/browser/aquariumSubmitIntentService.ts
src/vs/sessions/contrib/aquarium/browser/bubble.ts
src/vs/sessions/contrib/aquarium/browser/sessionPopulationDriver.ts
src/vs/sessions/contrib/aquarium/test/browser/aquariumConfiguration.test.ts
Files modified:
src/vs/sessions/contrib/aquarium/browser/aquarium.contribution.ts
src/vs/sessions/contrib/aquarium/browser/aquariumOverlay.ts
src/vs/sessions/contrib/aquarium/browser/fish.ts
src/vs/sessions/contrib/aquarium/browser/media/aquarium.css
src/vs/sessions/contrib/chat/browser/media/chatWidget.css
src/vs/sessions/contrib/chat/browser/newChatInput.ts
src/vs/sessions/contrib/chat/browser/newChatViewPane.ts
Validation: tsgo type-check, eslint, and layer-check all clean.
Schema-guard test runs in CI.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a hidden developer-gated mode that turns the Agents window aquarium into a live visualization of Agent Host sessions, with collapsed new-chat input behavior and session activity bubbles.
Changes:
- Adds aquarium-as-sessions gating, input reveal/dismiss behavior, and telemetry in the new-chat view.
- Refactors aquarium population into swappable drivers and adds session-backed fish, growth, status colors, and bubbles.
- Adds a hidden-setting schema guard test plus CSS for collapsed hotspot, fish variants, and bubbles.
Show a summary per file
| File | Description |
|---|---|
src/vs/sessions/contrib/chat/browser/newChatViewPane.ts |
Adds aquarium-mode controller, driver switching, dismiss/reveal handling, submit intent recording, and telemetry. |
src/vs/sessions/contrib/chat/browser/newChatInput.ts |
Adds an input-empty accessor for Esc dismiss logic. |
src/vs/sessions/contrib/chat/browser/media/chatWidget.css |
Styles the collapsed-mode hotspot. |
src/vs/sessions/contrib/aquarium/test/browser/aquariumConfiguration.test.ts |
Verifies the hidden aquarium setting is not registered. |
src/vs/sessions/contrib/aquarium/browser/sessionPopulationDriver.ts |
Adds session-to-fish population, status mapping, cap eviction, growth, and bubbles. |
src/vs/sessions/contrib/aquarium/browser/media/aquarium.css |
Adds bubble, status variant, and reduced-motion styling. |
src/vs/sessions/contrib/aquarium/browser/fish.ts |
Adds fish resizing and status-variant support. |
src/vs/sessions/contrib/aquarium/browser/bubble.ts |
Adds disposable activity bubble behavior. |
src/vs/sessions/contrib/aquarium/browser/aquariumSubmitIntentService.ts |
Adds submit-intent tracking service. |
src/vs/sessions/contrib/aquarium/browser/aquariumOverlay.ts |
Splits aquarium engine from population drivers and adds bubble hosting. |
src/vs/sessions/contrib/aquarium/browser/aquarium.contribution.ts |
Registers the submit-intent service and documents the hidden key. |
Copilot's findings
Comments suppressed due to low confidence (2)
src/vs/sessions/contrib/chat/browser/newChatViewPane.ts:262
- The hotspot only handles click activation. Tabbing to the button focuses it but does not reveal the input, which breaks the intended keyboard/focus path for showing the composer.
store.add(dom.addDisposableListener(button, dom.EventType.CLICK, () => {
if (this._aquariumModeActive) {
this._setRevealed(true, chatWidgetContainer, /*focus*/ true, 'click');
}
}));
src/vs/sessions/contrib/aquarium/browser/sessionPopulationDriver.ts:84
- Incremental additions use the raw
onDidChangeSessionsevent, whilegetSessions()is deduplicated byISessionsManagementService. When duplicate local/remote agent-host sessions arrive after attach, this adds fish thatgetSessions()would filter out, breaking the intended 1:1 mapping to visible sessions.
for (const added of e.added) {
if (this._isAgentHost(added)) {
this._addSession(added);
- Files reviewed: 11/11 changed files
- Comments generated: 9
Comment on lines
+213
to
+216
| // On entering aquarium mode (or first eval) start collapsed. | ||
| if (!wasActive) { | ||
| this._setRevealed(false, chatWidgetContainer, /*focus*/ false, 'scopeChanged'); | ||
| } |
| const bubble = new Bubble(doc, bubbleLayer, trimmed, () => { | ||
| bubblesByFishId.delete(fishId); | ||
| }); | ||
| bubblesByFishId.set(fishId, bubble); |
| color: var(--vscode-editorHoverWidget-foreground, #d4d4d4); | ||
| border: 1px solid var(--vscode-editorHoverWidget-border, rgba(255, 255, 255, 0.1)); | ||
| box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25); | ||
| pointer-events: none; |
| export const BUBBLE_DEFAULT_DWELL_MS = 3500; | ||
|
|
||
| /** CSS-driven fade-out duration. Must match the `.agents-aquarium-bubble.fade-out` rule. */ | ||
| export const BUBBLE_FADE_OUT_MS = 300; |
| } | ||
|
|
||
| isInputEmpty(): boolean { | ||
| return !this._editor?.getModel()?.getValue(); |
Comment on lines
+459
to
+461
| // session is registered. The service is a no-op when the | ||
| // sessions-aware aquarium isn't active. | ||
| this.aquariumSubmitIntentService.recordIntent(); |
|
|
||
| // Outside-click → dismiss. Use capture phase so we see clicks before | ||
| // they're consumed elsewhere. Skip clicks inside picker popups. | ||
| store.add(dom.addDisposableListener(targetWindow.document, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => { |
Comment on lines
+175
to
+179
| private _isAquariumModeActive(): boolean { | ||
| if (this.configurationService.getValue<boolean>(SESSIONS_DEVELOPER_JOY_ENABLED_SETTING) !== true) { | ||
| return false; | ||
| } | ||
| if (!isAquariumAsSessionsEnabled(this.configurationService)) { |
| * Activity bubbles and submit-grow tweens are layered on top in later phases | ||
| * (this driver only deals with population + status). | ||
| */ | ||
| export class SessionPopulationDriver extends Disposable implements IAquariumPopulationDriver { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Turns the decorative aquarium in the Agents window's new-chat view into a live 1:1 visualization of running Agent Host sessions, gated behind a hidden developer-only setting so the experience never ships to users by default.
Triple-gate
Behavior activates only when all three are true:
sessions.developerJoy.enabled(existing public experimental key) istrue.sessions.developerJoy.aquariumAsSessions(NEW, hidden, intentionally unregistered) istrue.ANY_AGENT_HOST_PROVIDER_RE(local-agent-host+agenthost-*).To opt in, hand-edit
settings.json:{ "sessions.developerJoy.enabled": true, "sessions.developerJoy.aquariumAsSessions": true }The
aquariumAsSessionskey is deliberately not in anyregisterConfigurationblock, so it never appears in Settings UI, IntelliSense forsettings.json, default-settings exports, or our docs. A schema-guard unit test (aquariumConfiguration.test.ts) asserts this invariant so we can't accidentally promote it to public.If any of the three flips false, the original decorative aquarium and always-visible chat input behavior is restored — live, no reload.
Behavior when the gate is on
aria-labeland focus-visible outline. Click, tab into, or activate the hotspot to reveal the input + workspace picker..monaco-list,.monaco-action-bar,.context-view,.monaco-menu,.monaco-hover,.monaco-quick-input-widgetso menus/popups don't false-dismiss.SessionPopulationDrivermirrorsISessionsManagementService.getSessions()filtered byANY_AGENT_HOST_PROVIDER_RE. Fish color tracks status (in-progress / needs-input / completed / error) viasetStatusVariant. Soft cap of 20 evicts oldest-terminal first.session.descriptionactivity text — truncated, dwell-gated, hover-locked, max 6 visible.Architecture
aquariumOverlay.ts's engine is split into a host + swappableIAquariumPopulationDriver. The defaultRandomPopulationDriverpreserves today's 50-fish crowd. The newSessionPopulationDriveris attached on demand viaIMountedToggleHandle.setDriverFactory(...), called fromNewChatWidgetwhenever the triple-gate evaluation flips.NewChatWidgetadds a small collapse-mode controller (_setupAquariumModeController,_recomputeAquariumMode,_setRevealed,_installHotspot,_installAquariumDismissHandlers,_scheduleAquariumAutoDismiss) that reacts toconfigurationService.onDidChangeConfiguration,_workspacePicker.onDidSelectWorkspace, and anautorunonactiveSession.AquariumSubmitIntentServiceis a tiny singleton withrecordIntent()/consumeIntent()and a 5 s window.NewChatWidget._sendrecords the intent before awaitingsendAndCreateChat;SessionPopulationDriver._addSessionconsumes it the moment the new agent-host session is registered.Telemetry
Two events:
aquarium.populationModemode: 'random' | 'sessions'aquarium.chatInputaction: 'reveal' | 'dismiss',trigger: 'click' | 'submit' | 'outside' | 'esc' | 'scopeChanged'Owner is provisionally
osortega— please confirm this is your registered GitHub handle for telemetry classifications before moving out of draft.Files
Added (4):
aquariumSubmitIntentService.ts— intent bus singleton with 5 s window.bubble.ts—Bubbleclass (text truncation, dwell, hover-lock, fade-out, idempotent dispose).sessionPopulationDriver.ts— 1:1 driver, per-session status autoruns, soft cap.aquariumConfiguration.test.ts— schema-guard test asserting the hidden key is NOT in the registered schema.Modified (7):
aquariumOverlay.ts— engine/population split (IAquariumHost,IAquariumPopulationDriver,IFishHandle,IAddFishOptions,IMountToggleOptions),setDriverFactoryswap, bubble layer + positioning, hidden-gate constant + reader.fish.ts—setTargetSize(easeOutCubic tween),setStatusVariant,_speciesColor;sizeno longerreadonly.aquarium.contribution.ts— registersIAquariumSubmitIntentServicesingleton; inline note that the hidden key is intentionally not registered.newChatViewPane.ts— full collapse-mode controller, hotspot, hybrid dismiss, scope-reactive driver swap, telemetry.newChatInput.ts— smallisInputEmpty()accessor for the Esc handler.aquarium.css+chatWidget.css— bubble layer, status variants, reduced-motion bubble transition, hotspot styling, focus-visible outline.Accessibility
<button>witharia-label, natively focusable,:focus-visibleoutline.water,bubbleLayer,bubble, fish containers) allaria-hidden="true"(decorative).aquarium.css.How to try this
settings.json.local-agent-hostworkspace (or connect to anagenthost-*remote tunnel). The chat input collapses; the aquarium reveals._activityto update → its fish should occasionally pop a bubble of the text.sessions.developerJoy.aquariumAsSessionstofalse→ behavior reverts immediately to the legacy decorative aquarium with the chat input always visible.Validation
npm run compile-check-ts-native— clean.npx eslinton all 11 changed/new files — clean.npm run valid-layers-check— clean.out/directory which the local worktree doesn't have).Follow-ups before going non-draft
owner: 'osortega'is the right value for the GDPR classifications.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com