mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add propose_plan tool for markdown plan proposals (#23452)
Adds a `propose_plan` tool that presents a workspace markdown file as a dedicated plan card in the agent UI. The workflow is: the agent uses `write_file`/`edit_files` to build a plan file (e.g. `/home/coder/PLAN.md`), then calls `propose_plan(path)` to present it. The backend reads the file via `ReadFile` and the frontend renders it as an expanded markdown preview card. **Backend** (`coderd/x/chatd/chattool/proposeplan.go`): new tool registered as root-chat-only. Validates `.md` suffix, requires an absolute path, reads raw file content from the workspace agent. Includes 1 MiB size cap. **Frontend** (`site/src/components/ai-elements/tool/`): dedicated `ProposePlanTool` component with `ToolCollapsible` + `ScrollArea` + `Response` markdown renderer, expanded by default. Custom icon (`ClipboardListIcon`) and filename-based label. **System prompt** (`coderd/x/chatd/prompt.go`): added `<planning>` section guiding the agent to research → write plan file → iterate → call `propose_plan`.
This commit is contained in:
@@ -3334,6 +3334,7 @@ func (p *Server) runChat(
|
||||
// create workspaces or spawn further subagents — they should
|
||||
// focus on completing their delegated task.
|
||||
if !chat.ParentChatID.Valid {
|
||||
// Workspace provisioning tools.
|
||||
tools = append(tools,
|
||||
chattool.ListTemplates(chattool.ListTemplatesOptions{
|
||||
DB: p.db,
|
||||
@@ -3361,6 +3362,37 @@ func (p *Server) runChat(
|
||||
WorkspaceMu: &workspaceMu,
|
||||
}),
|
||||
)
|
||||
// Plan presentation tool.
|
||||
tools = append(tools, chattool.ProposePlan(chattool.ProposePlanOptions{
|
||||
GetWorkspaceConn: workspaceCtx.getWorkspaceConn,
|
||||
StoreFile: func(ctx context.Context, name string, mediaType string, data []byte) (uuid.UUID, error) {
|
||||
workspaceCtx.chatStateMu.Lock()
|
||||
chatSnapshot := *workspaceCtx.currentChat
|
||||
workspaceCtx.chatStateMu.Unlock()
|
||||
|
||||
if !chatSnapshot.WorkspaceID.Valid {
|
||||
return uuid.Nil, xerrors.New("chat has no workspace")
|
||||
}
|
||||
|
||||
ws, err := p.db.GetWorkspaceByID(ctx, chatSnapshot.WorkspaceID.UUID)
|
||||
if err != nil {
|
||||
return uuid.Nil, xerrors.Errorf("resolve workspace: %w", err)
|
||||
}
|
||||
|
||||
row, err := p.db.InsertChatFile(ctx, database.InsertChatFileParams{
|
||||
OwnerID: chatSnapshot.OwnerID,
|
||||
OrganizationID: ws.OrganizationID,
|
||||
Name: name,
|
||||
Mimetype: mediaType,
|
||||
Data: data,
|
||||
})
|
||||
if err != nil {
|
||||
return uuid.Nil, xerrors.Errorf("insert chat file: %w", err)
|
||||
}
|
||||
|
||||
return row.ID, nil
|
||||
},
|
||||
}))
|
||||
tools = append(tools, p.subagentTools(ctx, func() database.Chat {
|
||||
return chat
|
||||
})...)
|
||||
|
||||
Reference in New Issue
Block a user