session: remove $OLLIE mount dependency

- Wire ReadPlanStep directly from sess.plan (no filesystem read)
- Add ListHandlers to ManagerConfig; passed through to AgentCoreConfig
- Hoist skillTree in main.go; populate ListHandlers for tools+skills
- Add ListHandlers to ManagerConfig
This commit is contained in:
Levi Neely 2026-06-16 12:30:42 +02:00
parent 32e8b4fc10
commit 542834b3e4
2 changed files with 42 additions and 6 deletions

31
main.go
View File

@ -151,16 +151,19 @@ func cmdMount() {
fmt.Fprintf(os.Stderr, "cannot create mount dir: %v\n", err)
os.Exit(1)
}
network := "unix"
if strings.Contains(addr, ":") {
network = "tcp"
}
exe, _ := os.Executable()
cmd := exec.Command(filepath.Join(filepath.Dir(exe), "ollie-9p-mount"),
"-u", os.Getenv("USER"), "-net", "unix", "-addr", addr, mnt)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
"-u", os.Getenv("USER"), "-net", network, "-addr", addr, mnt)
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
if err := cmd.Start(); err != nil {
fmt.Fprintf(os.Stderr, "ollie-9p-mount: %v\n", err)
os.Exit(1)
}
fmt.Printf("mounted %s at %s\n", addr, mnt)
fmt.Printf("mounted %s at %s (pid %d)\n", addr, mnt, cmd.Process.Pid)
}
func isRunning(sockPath string) bool {
@ -232,8 +235,20 @@ func runServer(sockPath, pidPath string) {
agentsDirs := agent.AgentsDirs()
sessionsDir := paths.CfgDir() + "/sessions"
toolTree := fs.NewTree([]string{execute.ToolsPath()}, fs.Perms[fs.PathTools].FileMode, fs.WithIndex(ToolIndex))
skillTree := fs.NewSkillTree()
transcriptStore := fs.NewTree([]string{transcriptDir}, fs.Perms[fs.PathTranscripts].FileMode, fs.WithReadOnly())
listTree := func(t *fs.Tree) func() []string {
return func() []string {
entries, _ := t.List()
names := make([]string, 0, len(entries))
for _, e := range entries {
names = append(names, e.Name())
}
return names
}
}
mgr := session.NewManager(session.ManagerConfig{
AgentsDir: agentsDirs[0],
SessionsDir: sessionsDir,
@ -244,6 +259,10 @@ func runServer(sockPath, pidPath string) {
NoMount: *tcpAddr != "",
ToolTree: toolTree,
InvalidateModels: modelCache.Invalidate,
ListHandlers: map[string]func() []string{
"tools": listTree(toolTree),
"skills": listTree(skillTree),
},
SaveTranscript: func(data []byte) error {
name := time.Now().Format("20060102T150405") + "-chat.md"
e, err := transcriptStore.Open(name)
@ -266,7 +285,7 @@ func runServer(sockPath, pidPath string) {
ToolTree: toolTree,
UtilStore: fs.NewTree([]string{paths.CfgDir() + "/scripts/u"}, fs.Perms[fs.PathUtils].FileMode, fs.WithReadOnly()),
PluginStore: fs.NewTree([]string{execute.PluginsPath()}, fs.Perms[fs.PathPlugins].FileMode, fs.WithReadOnly()),
SkillTree: fs.NewSkillTree(),
SkillTree: skillTree,
SessionMgr: mgr,
TranscriptStore: transcriptStore,
TmpStore: fs.NewTree([]string{tmpDir}, fs.Perms[fs.PathTmp].FileMode),

View File

@ -143,6 +143,9 @@ type ManagerConfig struct {
NoMount bool
// InvalidateModels clears the model cache, forcing a refresh.
InvalidateModels func()
// ListHandlers provides harness-specific list implementations for slash
// commands (/skills, /tools, etc.). Passed through to AgentCoreConfig.
ListHandlers map[string]func() []string
}
// Manager manages session lifecycle and exposes sessions as a Tree.
@ -581,6 +584,7 @@ func (s *Manager) createSession(args []string) error {
}
var core agent.Core
var sessPtr *Session
var allowTools []string
uname := s.nextUname()
if s.cfg.NewCore != nil {
@ -639,6 +643,7 @@ func (s *Manager) createSession(args []string) error {
rt := agent.BuildRuntime(cfg, newDisp(), cwd, []string{"OLLIE_SESSION_ID=" + sessID, "OLLIE_UNAME=" + uname, "OLLIE=" + execute.MountPath(uname)})
// sessPtr is set after NewSession; the ReadPlanStep closure captures it.
core = agent.NewAgentCore(agent.AgentCoreConfig{
Backend: be,
AgentName: agentName,
@ -650,11 +655,23 @@ func (s *Manager) createSession(args []string) error {
Runtime: rt,
NewDispatcher: newDisp,
Log: s.cfg.Sink.NewLogger("core"),
ReadPlanStep: func() string {
if sessPtr == nil {
return ""
}
sessPtr.mu.RLock()
data := make([]byte, len(sessPtr.plan))
copy(data, sessPtr.plan)
sessPtr.mu.RUnlock()
return agent.NextUncheckedStep(data)
},
ListHandlers: s.cfg.ListHandlers,
})
}
ctx, cancel := context.WithCancel(context.Background())
sess := NewSession(sessID, core, ctx, cancel)
sessPtr = sess
sess.AllowTools = allowTools
s.mu.Lock()