mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
1cf0354f72
> This PR was authored by Mux on behalf of Mike. ## Summary - add persistent plan mode for chats and the chat-specific plan file flow - add structured planning tools such as `ask_user_question` and `propose_plan` - keep `write_file` and `edit_files` constrained to the chat-specific plan file during plan turns - allow shell exploration in plan mode, including subagents, via `execute` and `process_output` - block implementation-oriented, provider-native, MCP, dynamic, and computer-use tools during plan turns - update the chat UI, tests, and docs for the new planning flow
55 lines
1.3 KiB
Go
55 lines
1.3 KiB
Go
package chattool
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/codersdk/workspacesdk"
|
|
)
|
|
|
|
func ensurePlanPathResolvesToItself(
|
|
ctx context.Context,
|
|
conn workspacesdk.AgentConn,
|
|
planPath string,
|
|
) error {
|
|
if conn == nil {
|
|
return xerrors.New("workspace connection is required")
|
|
}
|
|
|
|
normalizedPlanPath := normalizeWorkspacePath(planPath)
|
|
resolvedPath, err := conn.ResolvePath(ctx, planPath)
|
|
if err != nil {
|
|
if resolvePathUnsupported(err) {
|
|
// Older workspace agents do not expose /resolve-path yet. Keep
|
|
// plan turns working during rolling upgrades, even though they
|
|
// cannot enforce the symlink guard until the agent is upgraded.
|
|
return nil
|
|
}
|
|
return xerrors.Errorf("resolve plan path: %w", err)
|
|
}
|
|
resolvedPath = normalizeWorkspacePath(resolvedPath)
|
|
if resolvedPath != normalizedPlanPath {
|
|
return xerrors.New(symlinkedPlanPathMessage(normalizedPlanPath, resolvedPath))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resolvePathUnsupported(err error) bool {
|
|
var statusErr interface{ StatusCode() int }
|
|
return xerrors.As(err, &statusErr) && statusErr.StatusCode() == http.StatusNotFound
|
|
}
|
|
|
|
func normalizeWorkspacePath(pathString string) string {
|
|
pathString = strings.TrimSpace(pathString)
|
|
if pathString == "" {
|
|
return ""
|
|
}
|
|
return path.Clean(filepath.ToSlash(pathString))
|
|
}
|