execute, agent: thread workdir through Decl and AgentCoreConfig
execute.Decl is now a function (func(workdir string) func() tools.Server) rather than a var, making workdir an explicit dependency rather than an implicit os.Getwd() call. execute.Server stores the workdir and sets cmd.Dir accordingly; falls back to os.Getwd() if empty. AgentCoreConfig gains WorkDir string, threaded into BuildAgentEnv and the system prompt. The /agent switch uses s.workdir so the correct directory is preserved across agent switches. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5afe380437
commit
23913d0d76
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Reference in New Issue