MCPcopy Index your code
hub / github.com/coder/coder / StartWorkspace

Function StartWorkspace

coderd/x/chatd/chattool/startworkspace.go:45–214  ·  view source on GitHub ↗

StartWorkspace returns a tool that starts a stopped workspace associated with the current chat. The tool is idempotent: if the workspace is already running or building, it returns immediately. db must not be nil and chatID must not be uuid.Nil.

(db database.Store, chatID uuid.UUID, options StartWorkspaceOptions)

Source from the content-addressed store, hash-verified

43// workspace is already running or building, it returns immediately.
44// db must not be nil and chatID must not be uuid.Nil.
45func StartWorkspace(db database.Store, chatID uuid.UUID, options StartWorkspaceOptions) fantasy.AgentTool {
46 return fantasy.NewAgentTool(
47 "start_workspace",
48 "Start the chat's workspace if it is currently stopped. "+
49 "This tool is idempotent — if the workspace is already "+
50 "running, it returns immediately. Use create_workspace "+
51 "first if no workspace exists yet. Provide parameter "+
52 "values (from read_template) only if necessary or "+
53 "explicitly requested by the user.",
54 func(ctx context.Context, args startWorkspaceArgs, _ fantasy.ToolCall) (fantasy.ToolResponse, error) {
55 if options.StartFn == nil {
56 return fantasy.NewTextErrorResponse("workspace starter is not configured"), nil
57 }
58
59 // Serialize with create_workspace and stop_workspace to prevent races.
60 if options.WorkspaceMu != nil {
61 options.WorkspaceMu.Lock()
62 defer options.WorkspaceMu.Unlock()
63 }
64
65 chat, err := db.GetChatByID(ctx, chatID)
66 if err != nil {
67 return fantasy.NewTextErrorResponse(
68 xerrors.Errorf("load chat: %w", err).Error(),
69 ), nil
70 }
71 if !chat.WorkspaceID.Valid {
72 return fantasy.NewTextErrorResponse(
73 "chat has no workspace; use create_workspace first",
74 ), nil
75 }
76
77 ws, err := db.GetWorkspaceByID(ctx, chat.WorkspaceID.UUID)
78 if err != nil {
79 return fantasy.NewTextErrorResponse(
80 xerrors.Errorf("load workspace: %w", err).Error(),
81 ), nil
82 }
83 if ws.Deleted {
84 return fantasy.NewTextErrorResponse(
85 "workspace was deleted; use create_workspace to make a new one",
86 ), nil
87 }
88
89 build, job, err := latestWorkspaceBuildAndJob(ctx, db, ws.ID)
90 if err != nil {
91 return fantasy.NewTextErrorResponse(err.Error()), nil
92 }
93
94 // If a build is already in progress, wait for it.
95 switch job.JobStatus {
96 case database.ProvisionerJobStatusPending,
97 database.ProvisionerJobStatusRunning:
98 // Publish the build ID to the frontend so it
99 // can start streaming logs immediately.
100 publishBuildBinding(ctx, db, options.Logger, chatID, ws.ID, build.ID, options.OnChatUpdated)
101 if err := waitForBuild(ctx, db, build.ID); err != nil {
102 // newBuildError returns via toolResponse (IsError: false)

Callers 2

appendRootChatToolsMethod · 0.92
TestStartWorkspaceFunction · 0.92

Calls 15

IsResponderFunction · 0.92
publishBuildBindingFunction · 0.85
buildFailureToolResponseFunction · 0.85
waitForAgentAndRespondFunction · 0.85
toolResponseFunction · 0.85
asOwnerFunction · 0.85
responseErrorResultFunction · 0.85
waitForBuildFunction · 0.70
GetChatByIDMethod · 0.65
GetWorkspaceByIDMethod · 0.65
ResponseMethod · 0.65

Tested by 1

TestStartWorkspaceFunction · 0.74