diff --git a/internal/acp/agent.go b/internal/acp/agent.go index f3687f0efb3cd7e74193a3ace5ce44bddc47d108..c2178a99842980fe91d272fe32e98f583f04c540 100644 --- a/internal/acp/agent.go +++ b/internal/acp/agent.go @@ -2,14 +2,17 @@ package acp import ( "context" + "errors" "fmt" "log/slog" "strings" + "charm.land/fantasy" "github.com/charmbracelet/crush/internal/app" "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/csync" "github.com/charmbracelet/crush/internal/message" + "github.com/charmbracelet/crush/internal/permission" "github.com/coder/acp-go-sdk" ) @@ -185,12 +188,23 @@ func (a *Agent) Prompt(ctx context.Context, params acp.PromptRequest) (acp.Promp } // Run the agent. - _, err := a.app.AgentCoordinator.Run(ctx, string(params.SessionId), prompt) + result, err := a.app.AgentCoordinator.Run(ctx, string(params.SessionId), prompt) if err != nil { - if ctx.Err() != nil { + // Permission denial is a normal user choice, not an error. + if errors.Is(err, permission.ErrorPermissionDenied) { + return acp.PromptResponse{StopReason: acp.StopReasonRefusal}, nil + } + // Context cancellation means the user cancelled the request. + if errors.Is(err, context.Canceled) { return acp.PromptResponse{StopReason: acp.StopReasonCancelled}, nil } - return acp.PromptResponse{}, err + // Other errors are actual errors. + return acp.PromptResponse{StopReason: acp.StopReasonEndTurn}, err + } + + // Map the agent's finish reason to an ACP stop reason. + if result != nil && result.Response.FinishReason == fantasy.FinishReasonLength { + return acp.PromptResponse{StopReason: acp.StopReasonMaxTokens}, nil } return acp.PromptResponse{StopReason: acp.StopReasonEndTurn}, nil