agent: remove $OLLIE mount dependency from core
- Add ListHandlers map to AgentCoreConfig/agent struct; /skills and /tools dispatch through it instead of reading local paths directly - Add ReadPlanStep to AgentCoreConfig; wired by 9p/ directly from sess.plan - Export NextUncheckedStep([]byte) as pure helper - Fix prependOlliePath to use OLLIE_CFG_PATH/scripts/x/ instead of $OLLIE/x/ - Add OLLIE_CFG_PATH to EnsureDefaults and managed env var list
This commit is contained in:
parent
72ae801e3f
commit
8e7dd60a8b
|
|
@ -25,20 +25,10 @@ func (s *agent) handleCommand(ctx context.Context, input string) bool {
|
|||
cmd := parts[0]
|
||||
args := parts[1:]
|
||||
|
||||
listMountDir := func(subdir string) {
|
||||
mount := os.Getenv("OLLIE")
|
||||
if mount == "" {
|
||||
home, _ := os.UserHomeDir()
|
||||
mount = home + "/mnt/ollie"
|
||||
}
|
||||
entries, err := os.ReadDir(mount + "/" + subdir)
|
||||
if err != nil {
|
||||
s.emit(infoEvent(fmt.Sprintf("%s: %v", cmd, err)))
|
||||
return
|
||||
}
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
s.emit(infoEvent(" " + e.Name()))
|
||||
listFromHandler := func(name string) {
|
||||
if h := s.listHandlers[name]; h != nil {
|
||||
for _, item := range h() {
|
||||
s.emit(infoEvent(" " + item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -423,8 +413,8 @@ func (s *agent) handleCommand(ctx context.Context, input string) bool {
|
|||
s.emit(infoEvent("cwd: " + dir))
|
||||
},
|
||||
|
||||
"/skills": func(args []string) { listMountDir("sk") },
|
||||
"/tools": func(args []string) { listMountDir("t") },
|
||||
"/skills": func(args []string) { listFromHandler("skills") },
|
||||
"/tools": func(args []string) { listFromHandler("tools") },
|
||||
|
||||
"/sp": func(args []string) {
|
||||
s.emit(infoEvent(s.runtime.Preamble))
|
||||
|
|
|
|||
|
|
@ -235,6 +235,13 @@ type AgentCoreConfig struct {
|
|||
// MaxSteps overrides the agent JSON maxSteps when non-zero.
|
||||
// 0 means use the value from the agent config (or unlimited if absent).
|
||||
MaxSteps int
|
||||
// ReadPlanStep, if non-nil, is called to get the next unchecked plan step.
|
||||
// When provided, it is used directly instead of reading from the filesystem.
|
||||
ReadPlanStep func() string
|
||||
// ListHandlers provides harness-specific list implementations for slash
|
||||
// commands such as /skills, /tools, /agents. Keyed by command name without
|
||||
// the leading slash. Commands with no entry emit nothing.
|
||||
ListHandlers map[string]func() []string
|
||||
}
|
||||
|
||||
// agent is the Core implementation. It owns all agent and session state
|
||||
|
|
@ -252,6 +259,7 @@ type agent struct {
|
|||
newDispatcher func() tools.Dispatcher
|
||||
newBackend func(string) (backend.Backend, error)
|
||||
readPlanStep func() string
|
||||
listHandlers map[string]func() []string
|
||||
turnError func(ctx context.Context, errType, errMsg string) HookResult // overridable for tests
|
||||
cwd string
|
||||
startupMessages []string
|
||||
|
|
@ -342,6 +350,11 @@ func readNextUnchecked(path string) string {
|
|||
if err != nil || len(data) == 0 {
|
||||
return ""
|
||||
}
|
||||
return NextUncheckedStep(data)
|
||||
}
|
||||
|
||||
// NextUncheckedStep returns the first unchecked step from plan bytes.
|
||||
func NextUncheckedStep(data []byte) string {
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if strings.HasPrefix(trimmed, "- [ ]") {
|
||||
|
|
@ -385,12 +398,9 @@ func NewAgentCore(cfg AgentCoreConfig) Core {
|
|||
var readPlanStep func() string
|
||||
if cfg.SessionID != "" {
|
||||
os.MkdirAll(filepath.Join(ollieTmpDir(), cfg.SessionID), 0700) //nolint:errcheck
|
||||
if mount := os.Getenv("OLLIE"); mount != "" {
|
||||
planPath := filepath.Join(mount, "s", cfg.SessionID, "plan")
|
||||
readPlanStep = func() string {
|
||||
return readNextUnchecked(planPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
if cfg.ReadPlanStep != nil {
|
||||
readPlanStep = cfg.ReadPlanStep
|
||||
}
|
||||
|
||||
log := cfg.Log
|
||||
|
|
@ -413,6 +423,7 @@ func NewAgentCore(cfg AgentCoreConfig) Core {
|
|||
newDispatcher: cfg.NewDispatcher,
|
||||
newBackend: cfg.NewBackend,
|
||||
readPlanStep: readPlanStep,
|
||||
listHandlers: cfg.ListHandlers,
|
||||
state: "idle",
|
||||
bus: pubsub.NewBus(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
// managed is the ordered list of env vars that ollie exposes to frontends.
|
||||
var managed = []string{
|
||||
"OLLIE",
|
||||
"OLLIE_CFG_PATH",
|
||||
"OLLIE_TOOLS_PATH",
|
||||
"OLLIE_AGENTS_PATH",
|
||||
"OLLIE_SKILLS_PATH",
|
||||
|
|
@ -39,6 +40,7 @@ func EnsureDefaults() {
|
|||
}
|
||||
defaults := map[string]string{
|
||||
"OLLIE": filepath.Join(home, "mnt", "ollie"),
|
||||
"OLLIE_CFG_PATH": filepath.Join(home, ".config", "ollie"),
|
||||
"OLLIE_TOOLS_PATH": filepath.Join(home, ".config", "ollie", "tools"),
|
||||
"OLLIE_AGENTS_PATH": filepath.Join(home, ".config", "ollie", "agents"),
|
||||
"OLLIE_SKILLS_PATH": filepath.Join(home, ".config", "ollie", "skills"),
|
||||
|
|
|
|||
|
|
@ -643,11 +643,7 @@ func (e *Server) executeWithStdin(ctx context.Context, code, language string, ti
|
|||
filtered = append(filtered, ev)
|
||||
}
|
||||
}
|
||||
olliePath := e.envExtra["OLLIE"]
|
||||
if olliePath == "" {
|
||||
olliePath = os.Getenv("OLLIE")
|
||||
}
|
||||
cmd.Env = prependOlliePath(filtered, olliePath)
|
||||
cmd.Env = prependOlliePath(filtered, paths.CfgDir())
|
||||
cmd.Env = append(cmd.Env, "OLLIE_TOOLS_PATH="+ToolsPath())
|
||||
for k, v := range e.envExtra {
|
||||
cmd.Env = append(cmd.Env, k+"="+v)
|
||||
|
|
@ -682,13 +678,13 @@ func (e *Server) executeWithStdin(ctx context.Context, code, language string, ti
|
|||
return string(output), nil
|
||||
}
|
||||
|
||||
// prependOlliePath returns env with $OLLIE/x/ prepended to PATH so wrapper
|
||||
// scripts placed there (e.g. ~/.config/ollie/scripts/x/) shadow system binaries.
|
||||
func prependOlliePath(env []string, ollie string) []string {
|
||||
if ollie == "" {
|
||||
// prependOlliePath returns env with $OLLIE_CFG_PATH/scripts/x/ prepended to PATH so wrapper
|
||||
// scripts placed there shadow system binaries.
|
||||
func prependOlliePath(env []string, cfgDir string) []string {
|
||||
if cfgDir == "" {
|
||||
return env
|
||||
}
|
||||
xdir := filepath.Join(ollie, "x")
|
||||
xdir := filepath.Join(cfgDir, "scripts", "x")
|
||||
result := make([]string, 0, len(env))
|
||||
for _, e := range env {
|
||||
if strings.HasPrefix(e, "PATH=") {
|
||||
|
|
|
|||
Reference in New Issue