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: fetch context files when workspace is first attached mid-turn
When create_workspace runs mid-turn, the instruction setup at
runChat's top has already executed with no workspace. The
onChatUpdated callback now calls persistInstructionFiles when
instruction is empty and a workspace just appeared, so context
files (AGENTS.md, skills) are available for the rest of the turn.

The persisted marker ensures subsequent turns read from DB
without re-dialing the workspace.
  • Loading branch information
kylecarbs committed Apr 15, 2026
commit 5c8fe6c5bccd7e0ce299ab3237051326ea210e25
98 changes: 63 additions & 35 deletions coderd/x/chatd/chatd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4543,14 +4543,14 @@ func (p *Server) runChat(
// Connect to MCP servers in parallel with instruction
// resolution. ConnectAll only depends on mcpConfigs and
// mcpTokens which are available after g.Wait() above.
var (
instruction string
resolvedUserPrompt string
mcpTools []fantasy.AgentTool
mcpCleanup func()
workspaceMCPTools []fantasy.AgentTool
skills []chattool.SkillMeta )
// Check if instruction files need to be (re-)persisted.
var (
instruction string
resolvedUserPrompt string
mcpTools []fantasy.AgentTool
mcpCleanup func()
workspaceMCPTools []fantasy.AgentTool
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).
needsInstructionPersist := false
Expand Down Expand Up @@ -5070,33 +5070,61 @@ func (p *Server) runChat(
// focus on completing their delegated task.
if !chat.ParentChatID.Valid {
// Workspace provisioning tools.
onChatUpdated := func(updatedChat database.Chat) {
workspaceCtx.selectWorkspace(updatedChat)
// Notify the frontend immediately so it can
// start streaming build logs before the tool
// completes.
p.publishChatPubsubEvent(updatedChat, codersdk.ChatWatchEventKindStatusChange, nil)
}
tools = append(tools,
chattool.ListTemplates(chat.OrganizationID, p.db, chattool.ListTemplatesOptions{
OwnerID: chat.OwnerID,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),
chattool.ReadTemplate(chat.OrganizationID, p.db, chattool.ReadTemplateOptions{
OwnerID: chat.OwnerID,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),
chattool.CreateWorkspace(chat.OrganizationID, p.db, chattool.CreateWorkspaceOptions{
OwnerID: chat.OwnerID,
ChatID: chat.ID,
CreateFn: p.createWorkspaceFn,
AgentConnFn: chattool.AgentConnFunc(p.agentConnFn),
AgentInactiveDisconnectTimeout: p.agentInactiveDisconnectTimeout,
WorkspaceMu: &workspaceMu,
OnChatUpdated: onChatUpdated,
Logger: p.logger,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),
onChatUpdated := func(updatedChat database.Chat) {
workspaceCtx.selectWorkspace(updatedChat)
// Notify the frontend immediately so it can
// start streaming build logs before the tool
// completes.
p.publishChatPubsubEvent(updatedChat, codersdk.ChatWatchEventKindStatusChange, nil)

// When a workspace is first attached mid-turn
// (e.g. via create_workspace), fetch and persist
// instruction files immediately so the LLM has
// AGENTS.md context for the remainder of this
// turn. The persisted marker prevents redundant
// fetches on subsequent turns.
if instruction == "" && updatedChat.WorkspaceID.Valid {
newInstruction, discoveredSkills, persistErr := p.persistInstructionFiles(
ctx,
updatedChat,
modelConfig.ID,
workspaceCtx.getWorkspaceAgent,
workspaceCtx.getWorkspaceConn,
)
if persistErr != nil {
p.logger.Warn(ctx, "failed to persist instruction files on workspace attach",
slog.F("chat_id", updatedChat.ID),
slog.Error(persistErr),
)
} else {
instruction = newInstruction
if len(discoveredSkills) > 0 {
skills = discoveredSkills
}
}
}
}
tools = append(tools,
chattool.ListTemplates(chat.OrganizationID, p.db, chattool.ListTemplatesOptions{
OwnerID: chat.OwnerID,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),
chattool.ReadTemplate(chat.OrganizationID, p.db, chattool.ReadTemplateOptions{
OwnerID: chat.OwnerID,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),
chattool.CreateWorkspace(chat.OrganizationID, p.db, chattool.CreateWorkspaceOptions{
OwnerID: chat.OwnerID,
ChatID: chat.ID,
CreateFn: p.createWorkspaceFn,
AgentConnFn: chattool.AgentConnFunc(p.agentConnFn),
AgentInactiveDisconnectTimeout: p.agentInactiveDisconnectTimeout,
WorkspaceMu: &workspaceMu,
OnChatUpdated: onChatUpdated,
Logger: p.logger,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),


chattool.StartWorkspace(chattool.StartWorkspaceOptions{
DB: p.db,
Expand Down