agentHost: resolve Claude customizations for a chat that is not resident - #332055
Open
Ryan Ewen (RyanEwen) wants to merge 1 commit into
Open
agentHost: resolve Claude customizations for a chat that is not resident#332055Ryan Ewen (RyanEwen) wants to merge 1 commit into
Ryan Ewen (RyanEwen) wants to merge 1 commit into
Conversation
Contributor
📬 CODENOTIFYThe following users are being notified based on files changed in this PR: TylerLeonhardtMatched files:
|
Contributor
There was a problem hiding this comment.
Pull request overview
Restores Claude customizations for non-resident chats using a temporary provisional runtime.
Changes:
- Resolves and disposes a transient runtime under session sequencing.
- Adds regression coverage for customization reads and subsequent resume behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
claudeAgent.ts |
Adds non-resident customization resolution. |
claudeAgent.test.ts |
Tests restored customization reads and resume behavior. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
`getChatCustomizations` resolved the chat through its live runtime, so a chat with a backing but no resident runtime reported no customizations at all: no project commands, no skills, no agents, not even the read-only built-ins. That is every session restored into a fresh host process and every session idle eviction released, and it leaves the session without slash commands until its next message. Read through a throwaway runtime built from the chat's exact backing instead. `_createProvisionalChatSession` is split into `_buildProvisionalChatSession`, which only builds, and a wrapper that registers it and re-applies client contributions for the send path. The read uses the build step, which starts no SDK Query and recovers the working directories from the SDK transcript cwd or the persisted overlay, so it reaches the pre-materialize path `getSessionCustomizations` already implements. The throwaway runtime is never registered and is disposed when the read returns. A resident one would make the next send take the chat for a provisional one and materialize it fresh rather than resume it, and it would queue an active-client refresh onto the session sequencer that could only run after the read had finished. Fixes microsoft#332047
Ryan Ewen (RyanEwen)
force-pushed
the
fix/cold-chat-customizations
branch
from
August 21, 2026 23:00
e5bd31c to
96dadb8
Compare
Mohammad javad Dianat (dianatofficial)
left a comment
There was a problem hiding this comment.
Nice improvement. Clean separation of concerns.
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.
Fixes #332047
Problem
ClaudeAgent.getChatCustomizationsresolves the chat through its live runtime:_findChatByUrimaps the chat to its backing'ssdkSessionIdand looks that up in_chatEntriesBySdkId, which holds only liveClaudeAgentSessionwrappers. Two ordinary states have a backing and no wrapper:_releaseChatdisposes the live session on idle eviction and keeps the backing on purpose: "_chatBackingsretains the backing across release so the chat resolves uniformly on the next cold resume-on-send".materializeChatre-attaches the backing for a session restored into a fresh process, and registers no wrapper.In both, the read returns
[], so the session reports no project commands, no skills, no agents, no rules, not even the read-only built-ins, until its next message.AgentHostSkillCompletionProviderresolves/completions through this call, so the session's slash commands are gone;AgentService._doRestoreSessionseeds state only when the resolved set is non-empty; andAgentSideEffects._publishSessionCustomizationsskips its dispatch when the resolved set already matches state, so nothing republishes later either.An empty list is not the intended pre-materialize behaviour.
ClaudeAgentSession.getSessionCustomizationssupports a session with no SDK Query and documents it: "Pre-materialize there is no Query, so the full disk set is shown". A non-resident chat simply never reaches it.CopilotAgent.getChatCustomizationsresolves fromresolveAgentChatContext(context, chat).configurationResourceand handles the "Provisional (pre-send) or pre-resume" case explicitly, andCodexAgent.getChatCustomizationsresolves through_resolveConversationSession.ClaudeAgentis the only provider keyed on a live runtime, and the only one that ignored itscontextargument.Change
Read through a throwaway runtime built from the chat's exact backing.
_createProvisionalChatSessionis split into_buildProvisionalChatSession, which only builds, and a wrapper that registers it and re-applies client contributions for the send path. The read uses the build step, which starts no SDK Query and recovers the working directories from the SDK transcriptcwdor the persisted overlay.That runtime is never registered and is disposed when the read returns, so the read mutates no provider state. A resident one would make
_ensureResolvedChatSessiontake the chat for a provisional one on the next send and materialize it fresh, andisResume: falsestarts the SDK withsessionIdrather thanresume, so a chat that has a transcript would silently begin a new conversation. The second test locks that. It would also queue an active-client refresh onto the session sequencer that could only run once the read had finished.A failure reports no customizations rather than throwing, so a chat whose working directory cannot be recovered degrades to today's behaviour. The live-runtime path is unchanged.
Not covered: the client-pushed plugin tier, which a chat with no resident runtime still omits. Adopting it means running the plugin sync on every read, and reads happen per completion keystroke.
How to test
.claude/commands/*.md, and send a message./without sending anything.The project's commands and the built-in skills are offered. On
main, only/renameis.Verified end to end in a dev container on 1.1.3: before the change the restored session's completions returned 1 item, after it they return 18 (5 project commands plus 13 built-in skills).
Unit coverage adds two tests to
claudeAgent.test.ts: one that the read returns the pre-materialize set for a chat released from memory, and one that the read leaves no resident runtime behind and that the following send still resumes the existing conversation.AI disclosure: this pull request and the related code were written with the assistance of AI.