-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix: re-fetch context files and skills from workspace on each turn #24360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
e94ab99
bc24c34
43269ce
ce9e867
5ae8a21
51308a8
5c8fe6c
c37e0fd
d73491d
d504547
148e739
c517ee9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Invert ReloadMessages fallback priority: prefer captured instruction (fresh from workspace) over stale DB content after compaction - Distinguish reachable-with-no-content from unreachable using workspaceConnOK; honor AGENTS.md deletion by clearing instruction - Remove stale comment fragment from old persistInstructionFiles - Remove empty default clause in switch - Restore DisableChainMode field to its own line
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4626,7 +4626,7 @@ func (p *Server) runChat( | |
| // are picked up without requiring a new chat. Falls back | ||
| // to persisted parts if the workspace dial fails. | ||
| g2.Go(func() error { | ||
| _, freshParts, discoveredSkills, _, fetchErr := p.fetchWorkspaceContext( | ||
| _, freshParts, discoveredSkills, workspaceConnOK, fetchErr := p.fetchWorkspaceContext( | ||
| ctx, | ||
| chat, | ||
| workspaceCtx.getWorkspaceAgent, | ||
|
|
@@ -4637,17 +4637,26 @@ func (p *Server) runChat( | |
| return workspaceCtx.getWorkspaceConn(instructionCtx) | ||
| }, | ||
| ) | ||
| if fetchErr == nil && len(freshParts) > 0 { | ||
| switch { | ||
| case fetchErr == nil && len(freshParts) > 0: | ||
| // Workspace returned fresh context files. | ||
| instruction = formatSystemInstructionsFromParts(freshParts) | ||
| skills = selectSkillMetasForInstructionRefresh( | ||
| persistedSkills, | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2 Comment says "Workspace unreachable" but this branch also fires when the workspace IS reachable with zero parts. (Edge Case Analyst P2, Contract Auditor P2)
Consider using the discarded |
||
| discoveredSkills, | ||
| uuid.NullUUID{UUID: currentWorkspaceAgentID, Valid: hasCurrentWorkspaceAgent}, | ||
| uuid.NullUUID{UUID: latestInjectedAgentID, Valid: hasLatestInjectedAgent}, | ||
| ) | ||
| } else { | ||
| // Workspace unreachable: fall back to persisted | ||
| // context-file parts from the message history. | ||
| case fetchErr == nil && workspaceConnOK: | ||
| // Workspace reachable but returned no context | ||
| // files (e.g. AGENTS.md was deleted). Honor the | ||
| // removal by clearing the instruction. | ||
| instruction = "" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this tested?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The deletion scenario (AGENTS.md removed → instruction cleared) didn't have direct test coverage. Added
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reworked the approach based on Kyle's feedback. The per-turn workspace dial was wrong — the actual problem is that The fix now lives in the
|
||
| skills = discoveredSkills | ||
| default: | ||
| // Workspace unreachable or fetch failed: fall | ||
| // back to persisted context-file parts from the | ||
| // message history. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the workspace was deleted?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a comment explaining: if the workspace was deleted,
|
||
| instruction = instructionFromContextFiles(messages) | ||
| skills = persistedSkills | ||
| } | ||
|
|
@@ -5341,19 +5350,22 @@ func (p *Server) runChat( | |
| // messages so that any context added during the | ||
| // chatloop (e.g. via agent-added context or new | ||
| // persisted instruction files) is picked up after | ||
| // compaction. | ||
| reloadedInstruction := instructionFromContextFiles(reloadedMsgs) | ||
| // compaction. The captured instruction (set at turn | ||
| // start from the workspace) takes priority because | ||
| // it may be fresher than the persisted DB content. | ||
| reloadedInstruction := instruction | ||
| if reloadedInstruction == "" { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1 Compaction resurrects cleared instruction/skills after AGENTS.md deletion (Edge Case Analyst P2, Contract Auditor P3, Go Architect Obs)
The PR’s goal is “pick up workspace changes between turns,” but this edge case defeats that for the deletion scenario when compaction fires within the same turn. Consider tracking a boolean like
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. Added if reloadedInstruction == "" && !instructionCleared {
reloadedInstruction = instructionFromContextFiles(reloadedMsgs)
}This prevents compaction from resurrecting cleared instruction/skills after AGENTS.md deletion.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2 Double injection of instruction after compaction when instruction is acquired mid-turn (Edge Case Analyst, Contract Auditor) When This only manifests when compaction triggers on the same step as a workspace-creating tool call (conversation near context limit), so it's uncommon but not unrealistic for long-running chats. Fix: set
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in a132d45 — added
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch — fixed in a132d45.
|
||
| // Fall back to the captured instruction if the | ||
| // reloaded messages don't contain context files | ||
| // (e.g. they were compacted away). | ||
| reloadedInstruction = instruction | ||
| // No fresh instruction was captured at turn start. | ||
| // Try to recover from persisted context-file parts | ||
| // in the reloaded messages. | ||
| reloadedInstruction = instructionFromContextFiles(reloadedMsgs) | ||
| } | ||
| if reloadedInstruction != "" { | ||
| reloadedPrompt = chatprompt.InsertSystem(reloadedPrompt, reloadedInstruction) | ||
| } | ||
| reloadedPrompt = renderPlanPathPrompt(reloadedPrompt, resolvePlanPathBlock(reloadCtx)) | ||
| reloadedSkills := skillsFromParts(reloadedMsgs) | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit After the fallback on line 5346,
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed to
|
||
| if len(reloadedSkills) == 0 { | ||
| reloadedSkills = skills | ||
| } | ||
|
|
@@ -5371,7 +5383,8 @@ func (p *Server) runChat( | |
| ) | ||
| } | ||
| return reloadedPrompt, nil | ||
| }, DisableChainMode: func() { | ||
| }, | ||
| DisableChainMode: func() { | ||
| chainModeActive = false | ||
| }, | ||
|
|
||
|
|
@@ -5767,7 +5780,6 @@ func contextFileAgentID(messages []database.ChatMessage) (uuid.UUID, bool) { | |
| return lastID, found | ||
| } | ||
|
|
||
| // persistInstructionFiles reads instruction files and discovers | ||
| // fetchWorkspaceContext retrieves fresh instruction files and | ||
| // skills from the workspace agent without persisting. It handles | ||
| // agent connection, context configuration fetching, content | ||
|
|
@@ -5883,10 +5895,8 @@ func (p *Server) persistInstructionFiles( | |
| if part.ContextFileContent != "" { | ||
| hasContent = true | ||
| } | ||
| default: | ||
| } | ||
| } | ||
|
|
||
| directory := agent.ExpandedDirectory | ||
| if directory == "" { | ||
| directory = agent.Directory | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
discoveredSkillsinside the closure shadows the outer-scope variable (Style Reviewer)The
:=creates a closure-localdiscoveredSkillsthat then writes to the outerskills. Renaming tofreshSkillsorfetchedSkillswould reduce cognitive load when verifying which variable is being used.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to
fetchedSkillsinside the closure.