Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: revert per-turn workspace dial in else-if hasContextFiles
The subsequent-turn branch should not dial the workspace on every
message. The original code correctly reads from persisted DB
content. The actual fix is the ReloadMessages callback which now
re-derives instruction/skills from reloaded messages after
compaction, picking up any context persisted mid-loop (e.g. when
the agent changes).

Removes the instructionCleared flag and three-way switch that
were dialing the workspace unnecessarily.
  • Loading branch information
kylecarbs committed Apr 15, 2026
commit 51308a8c4e1ca3b24f1b1c7aaaa7f2b7d937d8dc
81 changes: 18 additions & 63 deletions coderd/x/chatd/chatd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4549,9 +4549,7 @@ func (p *Server) runChat(
mcpTools []fantasy.AgentTool
mcpCleanup func()
workspaceMCPTools []fantasy.AgentTool
skills []chattool.SkillMeta
instructionCleared bool
)
skills []chattool.SkillMeta )
// Check if instruction files need to be (re-)persisted.
// This happens when no context-file parts exist yet, or when
// the workspace agent has changed (e.g. workspace rebuilt).
Expand Down Expand Up @@ -4622,51 +4620,12 @@ func (p *Server) runChat(
return nil
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Obs fetchWorkspaceContext declares an err error return but never returns a non-nil error. (Test Auditor, Edge Case Analyst, Go Architect P3)

All three return paths yield nil for the error. The fetchErr == nil check in the caller is always true. Not a bug, but the unused error return is a maintenance trap — consider either dropping it or adding a comment explaining the intent.

})
} else if hasContextFiles {
// On subsequent turns, re-fetch context files from the
// workspace so that any changes (e.g. AGENTS.md edits)
// are picked up without requiring a new chat. Falls back
// to persisted parts if the workspace dial fails.
g2.Go(func() error {
_, freshParts, fetchedSkills, workspaceConnOK := p.fetchWorkspaceContext(
ctx,
chat,
workspaceCtx.getWorkspaceAgent,
func(instructionCtx context.Context) (workspacesdk.AgentConn, error) {
if _, _, err := workspaceCtx.workspaceAgentIDForConn(instructionCtx); err != nil {
return nil, xerrors.Errorf("resolve workspace agent for conn: %w", err)
}
return workspaceCtx.getWorkspaceConn(instructionCtx)
},
)
switch {
case len(freshParts) > 0:
// Workspace returned fresh context files.
instruction = formatSystemInstructionsFromParts(freshParts)
skills = selectSkillMetasForInstructionRefresh(
persistedSkills,
fetchedSkills,
uuid.NullUUID{UUID: currentWorkspaceAgentID, Valid: hasCurrentWorkspaceAgent},
uuid.NullUUID{UUID: latestInjectedAgentID, Valid: hasLatestInjectedAgent},
)
case workspaceConnOK:
// Workspace reachable but returned no context
// files (e.g. AGENTS.md was deleted). Honor the
// removal by clearing the instruction.
instruction = ""
instructionCleared = true
skills = fetchedSkills
default:
// Workspace unreachable — e.g. the workspace was
// deleted or the agent is no longer running.
// getWorkspaceAgent returns an error which causes
// fetchWorkspaceContext to return a nil agent with
// workspaceConnOK=false, landing here. The
// persisted context is the best available data.
instruction = instructionFromContextFiles(messages)
skills = persistedSkills
}
return nil
})
// On subsequent turns, extract the instruction text and
// skill index from persisted parts so they can be
// re-injected via InsertSystem after compaction drops
// those messages. No workspace dial needed.
instruction = instructionFromContextFiles(messages)
skills = persistedSkills
}
g2.Go(func() error {
resolvedUserPrompt = p.resolveUserPrompt(ctx, chat.OwnerID)
Expand Down Expand Up @@ -5351,21 +5310,17 @@ func (p *Server) runChat(
if chat.ParentChatID.Valid {
reloadedPrompt = chatprompt.InsertSystem(reloadedPrompt, defaultSubagentInstruction)
}
// Re-derive instruction and skills from the reloaded
// 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. 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 == "" && !instructionCleared {
// 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 != "" {
// Re-derive instruction and skills from the reloaded
// messages so that any context added during the
// chatloop (e.g. via persistInstructionFiles when
// the agent changes) is picked up after compaction.
// The captured instruction takes priority; fall
// back to persisted DB content otherwise.
reloadedInstruction := instruction
if reloadedInstruction == "" {
reloadedInstruction = instructionFromContextFiles(reloadedMsgs)
}
if reloadedInstruction != "" {
reloadedPrompt = chatprompt.InsertSystem(reloadedPrompt, reloadedInstruction)
}
reloadedPrompt = renderPlanPathPrompt(reloadedPrompt, resolvePlanPathBlock(reloadCtx))
Expand Down