Skip to content

automations: capture and retain client customizations for runs - #338777

Closed
Connor Peet (connor4312) wants to merge 1 commit into
mainfrom
connor4312/automation-customization-captures
Closed

Connor Peet (connor4312) wants to merge 1 commit into
mainfrom
connor4312/automation-customization-captures

Conversation

@connor4312

Copy link
Copy Markdown
Member

Summary

Adopt the imported AHP automation-customization contract so scheduled runs can use enabled client plugins without requiring the originating client to remain connected.

  • Reuse harness- and workspace-scoped active-client synchronization for immutable snapshots during automation creation and retargeting. Ordinary edits preserve existing snapshots.
  • Capture enabled plugins into host-owned copies, preserving disabled MCP-child exclusions without a live client enablement overlay.
  • Prepare captures before Copilot, Claude, and Codex runs start, including mapping selected custom agents into captured directories.
  • Persist revision holder IDs for automation definitions and retained runs. Register holders before saving automation state, release obsolete holders after successful persistence, and reconcile only after successfully loading authoritative automation storage.
  • Use atomic cache-manifest writes and preserve captures across restarts, definition edits/deletion, and session unloading. Permanent session deletion releases run holders.

Includes the imported AHP update to 0d9ec389 and documentation of capture and retention semantics.

Validation

  • npm run compile-client
  • npm run typecheck-client
  • Targeted cache, automation lifecycle, AgentService, and provider unit tests: 1,421 passing, 17 pending
  • Real Codex captured-automation integration tests: 2 passing, including execution after deleting the source plugin directory
  • Client snapshot/store and active-client scope suites validated earlier in this session: 154 passing
  • Targeted ESLint, git diff --check, and repository pre-commit hygiene

Regression coverage includes startup GC before automation recovery, independent holders, failed persistence, unavailable automation storage, write-ahead ordering, overlapping registrations, and cache-loss adoption.

Reuse workspace-scoped client synchronization to capture enabled plugins for offline automation runs across Copilot, Claude, and Codex. Preserve snapshots on ordinary edits and recapture when retargeting.

Persist revision holders in the plugin cache with write-ahead registration and authoritative reconciliation so definitions and retained run sessions survive restart and garbage collection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings September 29, 2026 21:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Production capability advertisement and several snapshot, deduplication, mapping, and holder-lifecycle paths remain incorrect.

Review effort: Balanced
Findings: 5 Medium severity

Open (5)
What changed in this PR

Adds durable client-customization snapshots so automation runs can execute independently of the originating client.

Changes:

  • Captures active-client plugins and selected-agent mappings.
  • Retains captures through automation/run holder lifecycles.
  • Integrates captures across providers, protocol state, tests, and documentation.
File Description
syncedCustomizationBundler.test.ts Tests immutable bundle snapshots.
agentHostUntitledProvisionalSessionService.test.ts Updates scope test fixture.
agentHostClientTools.test.ts Tests snapshot resolution races and recovery.
agentHostChatContribution.test.ts Updates customization scope fixture.
syncedCustomizationBundler.ts Adds immutable virtual-plugin snapshots.
agentHostActiveClientService.ts Exposes resolved customization snapshots.
AgentService.ts Adds capture and holder RPC methods.
protocolServerHandler.ts Handles new customization RPCs.
agentPluginManager.ts Implements capture storage and retention.
agentHostAutomationService.ts Manages automation/run capture lifecycles.
agentService.ts Prepares captured customizations before runs.
copilotAgent.ts Supplies captures to Copilot sessions.
copilotSdkSession.ts Applies captured custom-agent mappings.
claudeAgentSession.ts Supplies captures to Claude sessions.
codexClientCustomizations.ts Supplies captures to Codex sessions.
automation.d.ts Adds customization capture API types.
state.ts Extends automation protocol state.
commands.ts Adds capture and holder commands.
clientState.ts Registers new command handlers.
channels-changeset/​reducer.ts Updates generated protocol reducer.
channels-root/​reducer.ts Updates generated protocol reducer.
agentHostAutomationStore.ts Captures client state during mutations.
AUTOMATIONS.md Documents capture and retention semantics.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

this._armRunTimeout(running.resource);
const configuration = this._configurationTelemetry(definition.session);
const session = await this._execution.createSession(template, running);
const session = await this._execution.createSession(resolveCapturedAutomationAgentSelection(template, customizations), running, customizations);
Comment on lines +6704 to 6708
const sessionHostCustomizations = this._hostCustomizations().filter((customization): customization is PluginCustomization =>
customization.type === CustomizationType.Plugin
&& this._parent.pluginManager.getCapturedPluginDir(customization.uri) !== undefined
);
const clientCustomizations = this._flattenClientCustomizations();
Comment on lines +430 to +432
const capture = this._targetChanged(currentDescriptor.target, descriptor.target)
? await this._captureCustomizations(descriptor)
: undefined;
Comment on lines +532 to +533
if (!this._connection.initializeResult.get()?.automations?.customizations) {
return undefined;
Comment on lines +359 to +362
const destinationBySource = new ResourceMap<URI>();
const addEntry = (file: ISyncableFile, sourceUri: URI, destUri: URI, hashKey: string): void => {
entries.push({ sourceUri, destUri, hashKey });
destinationBySource.set(sourceUri, destUri);
@benvillalobos

Copy link
Copy Markdown
Member

I'm thinking we should display some kind of label letting users know customizations are going to be copied over, or have some checkbox / switch showing whether to copy all customizations over.

Also, how might a user delete these remote copies?

@connor4312

Copy link
Copy Markdown
Member Author

#338990

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants