From f6f2b2f15a2379791383b19af1e6768d826ea68c Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Wed, 25 Jun 2025 11:52:55 -0700 Subject: [PATCH] POC: user-defined environments Signed-off-by: Andrea Luzzardi --- environment/config.go | 6 +++--- mcpserver/tools.go | 30 +++++++++++++++++------------- repository/repository.go | 7 +++++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/environment/config.go b/environment/config.go index 263359e6..44c4d379 100644 --- a/environment/config.go +++ b/environment/config.go @@ -17,9 +17,9 @@ const ( func DefaultConfig() *EnvironmentConfig { return &EnvironmentConfig{ - BaseImage: defaultImage, - Instructions: "No instructions found. Please look around the filesystem and update me", - Workdir: "/workdir", + BaseImage: defaultImage, + // Instructions: "No instructions found. Please look around the filesystem and update me", + Workdir: "/workdir", } } diff --git a/mcpserver/tools.go b/mcpserver/tools.go index e48feaff..db883688 100644 --- a/mcpserver/tools.go +++ b/mcpserver/tools.go @@ -102,8 +102,8 @@ func wrapToolWithClient(tool *Tool, dag *dagger.Client) *Tool { func init() { registerTool( EnvironmentOpenTool, - EnvironmentCreateTool, - EnvironmentUpdateTool, + EnvironmentListTool, + // EnvironmentUpdateTool, EnvironmentRunCmdTool, @@ -151,8 +151,8 @@ func marshalEnvironment(env *environment.Environment) (string, error) { return string(out), nil } -func marshalEnvironmentInfo(envInfo *environment.EnvironmentInfo) (string, error) { - resp := &EnvironmentResponse{ +func envInfoToResponse(envInfo *environment.EnvironmentInfo) *EnvironmentResponse { + return &EnvironmentResponse{ ID: envInfo.ID, Title: envInfo.State.Title, Instructions: envInfo.Config.Instructions, @@ -164,6 +164,10 @@ func marshalEnvironmentInfo(envInfo *environment.EnvironmentInfo) (string, error LogCommand: fmt.Sprintf("cu log %s", envInfo.ID), Services: nil, // EnvironmentInfo doesn't have "active" services, specifically useful for EndpointMappings } +} + +func marshalEnvironmentInfo(envInfo *environment.EnvironmentInfo) (string, error) { + resp := envInfoToResponse(envInfo) out, err := json.Marshal(resp) if err != nil { return "", fmt.Errorf("failed to marshal response: %w", err) @@ -189,7 +193,7 @@ func EnvironmentInfoToCallResult(envInfo *environment.EnvironmentInfo) (*mcp.Cal var EnvironmentOpenTool = &Tool{ Definition: mcp.NewTool("environment_open", - mcp.WithDescription("Opens an existing environment. Return format is same as environment_create."), + mcp.WithDescription("Opens an existing environment. If unsure, use `environment_list` to list available environments."), mcp.WithString("explanation", mcp.Description("One sentence explanation for why this environment is being opened."), ), @@ -245,7 +249,7 @@ DO NOT manually install toolchains inside the environment, instead explicitly ca return mcp.NewToolResultErrorFromErr("dagger client not found in context", nil), nil } - env, err := repo.Create(ctx, dag, title, request.GetString("explanation", "")) + env, err := repo.Create(ctx, dag, "", title, request.GetString("explanation", "")) if err != nil { return mcp.NewToolResultErrorFromErr("failed to create environment", err), nil } @@ -421,7 +425,7 @@ var EnvironmentRunCmdTool = &Tool{ mcp.Required(), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("command", @@ -514,7 +518,7 @@ var EnvironmentFileReadTool = &Tool{ mcp.Required(), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("target_file", @@ -565,7 +569,7 @@ var EnvironmentFileListTool = &Tool{ mcp.Required(), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("path", @@ -604,7 +608,7 @@ var EnvironmentFileWriteTool = &Tool{ mcp.Required(), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("target_file", @@ -654,7 +658,7 @@ var EnvironmentFileDeleteTool = &Tool{ mcp.Required(), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("target_file", @@ -692,7 +696,7 @@ var EnvironmentCheckpointTool = &Tool{ mcp.Description("One sentence explanation for why this checkpoint is being created."), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("destination", @@ -729,7 +733,7 @@ var EnvironmentAddServiceTool = &Tool{ mcp.Required(), ), mcp.WithString("environment_id", - mcp.Description("The ID of the environment for this command. Must call `environment_create` first."), + mcp.Description("The ID of the environment for this command."), mcp.Required(), ), mcp.WithString("name", diff --git a/repository/repository.go b/repository/repository.go index 45c4fea0..283b847a 100644 --- a/repository/repository.go +++ b/repository/repository.go @@ -118,8 +118,11 @@ func (r *Repository) exists(ctx context.Context, id string) error { // Create creates a new environment with the given description and explanation. // Requires a dagger client for container operations during environment initialization. -func (r *Repository) Create(ctx context.Context, dag *dagger.Client, description, explanation string) (*environment.Environment, error) { - id := petname.Generate(2, "-") +func (r *Repository) Create(ctx context.Context, dag *dagger.Client, id, description, explanation string) (*environment.Environment, error) { + if id == "" { + id = petname.Generate(2, "-") + } + worktree, err := r.initializeWorktree(ctx, id) if err != nil { return nil, err