diff --git a/pkg/agent/core.go b/pkg/agent/core.go index c16a3bf..ddbcbd6 100644 --- a/pkg/agent/core.go +++ b/pkg/agent/core.go @@ -119,14 +119,16 @@ func buildFirstPrompt(input string) string { } // systemPrompt builds the full system prompt for a given tool set. -func systemPrompt(allTools []backend.Tool) string { - cwd, _ := os.Getwd() +func systemPrompt(allTools []backend.Tool, workdir string) string { + if workdir == "" { + workdir, _ = os.Getwd() + } now := time.Now().Format("2006-01-02 15:04:05 MST") names := make([]string, len(allTools)) for i, t := range allTools { names[i] = t.Name } - return systemPromptBase + "\n\nWorking directory: " + cwd + + return systemPromptBase + "\n\nWorking directory: " + workdir + "\nCurrent time: " + now + "\nAvailable tools: " + strings.Join(names, ", ") } @@ -144,9 +146,10 @@ type AgentEnv struct { } // BuildAgentEnv constructs an AgentEnv from a pre-configured Dispatcher and -// optional agent config. The caller is responsible for registering all servers -// on d before calling this. -func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher) AgentEnv { +// optional agent config. workdir sets the working directory reported in the +// system prompt; if empty, the process working directory is used. +// The caller is responsible for registering all servers on d before calling this. +func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher, workdir string) AgentEnv { var messages []string if cfg != nil { @@ -193,9 +196,9 @@ func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher) AgentEnv { } } - sp := systemPrompt(allTools) + sp := systemPrompt(allTools, workdir) if agentPrompt != "" { - sp = systemPrompt(allTools) + "\n\n" + agentPrompt + sp = systemPrompt(allTools, workdir) + "\n\n" + agentPrompt } overhead := len(sp) @@ -281,6 +284,7 @@ type AgentCoreConfig struct { AgentsDir string SessionsDir string SessionID string + WorkDir string // working directory for tool execution and system prompt Session *Session Env AgentEnv NewDispatcher func() tools.Dispatcher @@ -298,6 +302,7 @@ type agentCore struct { sessionID string dispatcher tools.Dispatcher newDispatcher func() tools.Dispatcher + workdir string ctxOverhead int currentAction atomic.Pointer[actionHandle] } @@ -325,6 +330,7 @@ func NewAgentCore(cfg AgentCoreConfig) Core { agentsDir: cfg.AgentsDir, sessionsDir: cfg.SessionsDir, sessionID: cfg.SessionID, + workdir: cfg.WorkDir, dispatcher: cfg.Env.dispatcher, newDispatcher: cfg.NewDispatcher, ctxOverhead: cfg.Env.CtxOverhead, @@ -500,7 +506,7 @@ func (s *agentCore) handleCommand(ctx context.Context, input string, handler Eve s.dispatcher.Close() } d := s.newDispatcher() - env := BuildAgentEnv(cfg, d) + env := BuildAgentEnv(cfg, d, s.workdir) s.dispatcher = env.dispatcher s.hooks = env.Hooks s.loopcfg.systemPrompt = env.systemPrompt diff --git a/pkg/tools/execute/executor.go b/pkg/tools/execute/executor.go index 1157c0e..97ea93f 100644 --- a/pkg/tools/execute/executor.go +++ b/pkg/tools/execute/executor.go @@ -24,6 +24,10 @@ type Server struct { // If it returns false, the operation is denied. Confirm func(string) bool + // workdir is the working directory for sandboxed commands. If empty, + // the process working directory is used. + workdir string + // rate limiting state (per-Server) rateLimitMu sync.Mutex validationFailures int @@ -31,8 +35,8 @@ type Server struct { blockedUntil time.Time } -// New creates a new Server. -func New() *Server { return &Server{} } +// New creates a new Server with the given working directory. +func New(workdir string) *Server { return &Server{workdir: workdir} } var dangerousPatterns = []*regexp.Regexp{ regexp.MustCompile(`rm\s+(-[a-z]*r[a-z]*\s+)*-[a-z]*f[a-z]*\s*/(home|var|usr|etc|boot|root|bin|sbin|lib|opt|srv)?`), @@ -158,7 +162,10 @@ func (e *Server) Execute(ctx context.Context, code, language string, timeout int return "", err } - workDir, _ := os.Getwd() + workDir := e.workdir + if workDir == "" { + workDir, _ = os.Getwd() + } ctx, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second) defer cancel() diff --git a/pkg/tools/execute/server.go b/pkg/tools/execute/server.go index abcc793..62e4193 100644 --- a/pkg/tools/execute/server.go +++ b/pkg/tools/execute/server.go @@ -7,8 +7,10 @@ import ( "ollie/pkg/tools" ) -// Decl is the default factory for an execute Server. Reassign to override. -var Decl func() tools.Server = func() tools.Server { return New() } +// Decl returns a factory for an execute Server with the given working directory. +func Decl(workdir string) func() tools.Server { + return func() tools.Server { return New(workdir) } +} // ListTools implements tools.Server. func (e *Server) ListTools() ([]tools.ToolInfo, error) {