9p: call Agent() directly for all agent operations

Session pass-throughs are removed. All agent operations go through
sess.Core.Agent().Method() — proper encapsulation boundary.

Session-level: Bus(), Close(), SetEnv(), CWD(), SetCWD(), Interrupt(),
Queue(), InjectSystemEvent(), SetSessionID(), SaveSession().

Agent-level (via .Agent()): Submit(), State(), Reply(), BackendName(),
ModelName(), IsRunning(), CtxSz(), UsageStr(), Context(), etc.
This commit is contained in:
Levi Neely 2026-07-29 21:58:04 +02:00
parent f142601f5f
commit 50601ebf46
8 changed files with 76 additions and 74 deletions

38
dbus.go
View File

@ -137,7 +137,7 @@ func (a *DBusAdapter) startWatcher(id string, sess *mgr.Session) {
// State watcher // State watcher
go func() { go func() {
current := sess.Core.State() current := sess.Core.Agent().State()
for { for {
next, ok := sess.Core.WaitChange(ctx, agent.WatchState, current) next, ok := sess.Core.WaitChange(ctx, agent.WatchState, current)
if !ok { if !ok {
@ -153,7 +153,7 @@ func (a *DBusAdapter) startWatcher(id string, sess *mgr.Session) {
// Agent watcher — emits ConfigChanged when the agent name changes // Agent watcher — emits ConfigChanged when the agent name changes
go func() { go func() {
current := sess.Core.AgentName() current := sess.Core.Agent().Name()
for { for {
next, ok := sess.Core.WaitChange(ctx, "agent", current) next, ok := sess.Core.WaitChange(ctx, "agent", current)
if !ok { if !ok {
@ -275,7 +275,7 @@ func (a *DBusAdapter) ListSessions() ([]string, *dbus.Error) {
continue continue
} }
result = append(result, fmt.Sprintf("%s\t%s\t%s\t%s", result = append(result, fmt.Sprintf("%s\t%s\t%s\t%s",
id, sess.Core.State(), sess.Core.ModelName(), sess.Core.AgentName())) id, sess.Core.Agent().State(), sess.Core.Agent().ModelName(), sess.Core.Agent().Name()))
} }
return result, nil return result, nil
} }
@ -301,7 +301,7 @@ func (a *DBusAdapter) Submit(sessionID, prompt string) (bool, *dbus.Error) {
if sess == nil { if sess == nil {
return false, nil return false, nil
} }
go sess.Core.Submit(sess.Ctx, prompt) go sess.Core.Agent().Submit(sess.Ctx, prompt)
return true, nil return true, nil
} }
@ -314,7 +314,7 @@ func (a *DBusAdapter) ReactTo(sessionID, responseID, emoji string) (bool, *dbus.
if sess == nil { if sess == nil {
return false, nil return false, nil
} }
if err := sess.Core.ReactTo(responseID, emoji); err != nil { if err := sess.Core.Agent().React(responseID, emoji); err != nil {
return false, dbus.MakeFailedError(err) return false, dbus.MakeFailedError(err)
} }
return true, nil return true, nil
@ -334,7 +334,7 @@ func (a *DBusAdapter) GetState(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "", nil return "", nil
} }
return sess.Core.State(), nil return sess.Core.Agent().State(), nil
} }
func (a *DBusAdapter) GetChat(sessionID string, offset int64) (string, int64, *dbus.Error) { func (a *DBusAdapter) GetChat(sessionID string, offset int64) (string, int64, *dbus.Error) {
@ -361,7 +361,7 @@ func (a *DBusAdapter) GetUsage(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "", nil return "", nil
} }
return sess.Core.Usage(), nil return sess.Core.Agent().UsageStr(), nil
} }
func (a *DBusAdapter) GetCost(sessionID string) (string, *dbus.Error) { func (a *DBusAdapter) GetCost(sessionID string) (string, *dbus.Error) {
@ -369,7 +369,7 @@ func (a *DBusAdapter) GetCost(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "", nil return "", nil
} }
return sess.Core.Cost(), nil return sess.Core.Agent().CostStr(), nil
} }
func (a *DBusAdapter) GetConfig(sessionID string) (string, *dbus.Error) { func (a *DBusAdapter) GetConfig(sessionID string) (string, *dbus.Error) {
@ -378,11 +378,11 @@ func (a *DBusAdapter) GetConfig(sessionID string) (string, *dbus.Error) {
return "", nil return "", nil
} }
var sb strings.Builder var sb strings.Builder
fmt.Fprintf(&sb, "model=%s\n", sess.Core.ModelName()) fmt.Fprintf(&sb, "model=%s\n", sess.Core.Agent().ModelName())
fmt.Fprintf(&sb, "backend=%s\n", sess.Core.BackendName()) fmt.Fprintf(&sb, "backend=%s\n", sess.Core.Agent().BackendName())
fmt.Fprintf(&sb, "agent=%s\n", sess.Core.AgentName()) fmt.Fprintf(&sb, "agent=%s\n", sess.Core.Agent().Name())
fmt.Fprintf(&sb, "cwd=%s\n", sess.Core.CWD()) fmt.Fprintf(&sb, "cwd=%s\n", sess.Core.CWD())
fmt.Fprintf(&sb, "state=%s\n", sess.Core.State()) fmt.Fprintf(&sb, "state=%s\n", sess.Core.Agent().State())
return sb.String(), nil return sb.String(), nil
} }
@ -393,7 +393,7 @@ func (a *DBusAdapter) SetConfig(sessionID, key, value string) (bool, *dbus.Error
} }
switch key { switch key {
case "model": case "model":
sess.Core.Submit(sess.Ctx, "/model "+value) sess.Core.Agent().Submit(sess.Ctx, "/model "+value)
case "cwd": case "cwd":
if err := sess.Core.SetCWD(value); err != nil { if err := sess.Core.SetCWD(value); err != nil {
return false, nil return false, nil
@ -409,7 +409,7 @@ func (a *DBusAdapter) GetReactions(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "{}", nil return "{}", nil
} }
data, err := json.Marshal(sess.Core.Reactions()) data, err := json.Marshal(sess.Core.Agent().Reactions())
if err != nil { if err != nil {
return "", dbus.MakeFailedError(err) return "", dbus.MakeFailedError(err)
} }
@ -421,7 +421,7 @@ func (a *DBusAdapter) GetContext(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "", nil return "", nil
} }
msgs := sess.Core.Context() msgs := sess.Core.Agent().Context()
var sb strings.Builder var sb strings.Builder
enc := json.NewEncoder(&sb) enc := json.NewEncoder(&sb)
enc.SetEscapeHTML(false) enc.SetEscapeHTML(false)
@ -655,7 +655,7 @@ func (a *DBusAdapter) GetSystemPrompt(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "", nil return "", nil
} }
return sess.Core.SystemPrompt(), nil return sess.Core.Agent().SystemPrompt(), nil
} }
func (a *DBusAdapter) GetContextSize(sessionID string) (string, *dbus.Error) { func (a *DBusAdapter) GetContextSize(sessionID string) (string, *dbus.Error) {
@ -663,7 +663,7 @@ func (a *DBusAdapter) GetContextSize(sessionID string) (string, *dbus.Error) {
if sess == nil { if sess == nil {
return "", nil return "", nil
} }
return sess.Core.CtxSz(), nil return sess.Core.Agent().CtxSz(), nil
} }
func (a *DBusAdapter) GetPreviousPrompt(sessionID string) (string, *dbus.Error) { func (a *DBusAdapter) GetPreviousPrompt(sessionID string) (string, *dbus.Error) {
@ -682,7 +682,7 @@ func (a *DBusAdapter) Compact(sessionID string) (bool, *dbus.Error) {
if sess == nil { if sess == nil {
return false, nil return false, nil
} }
sess.Core.Submit(sess.Ctx, "/compact") sess.Core.Agent().Submit(sess.Ctx, "/compact")
return true, nil return true, nil
} }
@ -691,7 +691,7 @@ func (a *DBusAdapter) ClearContext(sessionID string) (bool, *dbus.Error) {
if sess == nil { if sess == nil {
return false, nil return false, nil
} }
sess.Core.Submit(sess.Ctx, "/clear") sess.Core.Agent().Submit(sess.Ctx, "/clear")
return true, nil return true, nil
} }

View File

@ -326,7 +326,7 @@ func TestSessionManagerInterruptAll(t *testing.T) {
defer sess.Cancel() defer sess.Cancel()
// Submit in background to make it "running" // Submit in background to make it "running"
go sess.Core.Submit(sess.Ctx, "hello") go sess.Core.Agent().Submit(sess.Ctx, "hello")
time.Sleep(50 * time.Millisecond) // let it enter thinking state time.Sleep(50 * time.Millisecond) // let it enter thinking state
s.AddSession(sess) s.AddSession(sess)
@ -381,7 +381,7 @@ func TestSessionManagerRenameErrors(t *testing.T) {
} }
// running // running
sess := testBlockingSession("r") sess := testBlockingSession("r")
go sess.Core.Submit(sess.Ctx, "hello") go sess.Core.Agent().Submit(sess.Ctx, "hello")
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
s.AddSession(sess) s.AddSession(sess)
if err := s.Tree().Rename("r", "r2"); err == nil { if err := s.Tree().Rename("r", "r2"); err == nil {
@ -566,8 +566,8 @@ func TestSessionFileStoreWritePrompt(t *testing.T) {
testStoreWrite(t, sf, "prompt", []byte("hello agent")) testStoreWrite(t, sf, "prompt", []byte("hello agent"))
// Verify state is back to idle (Submit completed) // Verify state is back to idle (Submit completed)
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
if sess.Core.State() != "idle" { if sess.Core.Agent().State() != "idle" {
t.Errorf("state = %q; want idle after submit", sess.Core.State()) t.Errorf("state = %q; want idle after submit", sess.Core.Agent().State())
} }
} }
@ -577,7 +577,7 @@ func TestSessionFileStoreWriteFifoIn(t *testing.T) {
sf := newTestSessionFileStore(t, sess) sf := newTestSessionFileStore(t, sess)
testStoreWrite(t, sf, "fifo.in", []byte("inject this")) testStoreWrite(t, sf, "fifo.in", []byte("inject this"))
item, ok := sess.Core.PopQueue() item, ok := sess.Core.Agent().PopQueue()
if !ok || item != "inject this" { if !ok || item != "inject this" {
t.Errorf("PopQueue() = %q, %v; want inject this, true", item, ok) t.Errorf("PopQueue() = %q, %v; want inject this, true", item, ok)
} }
@ -606,14 +606,14 @@ func TestSessionFileStoreWriteBackendModelAgent(t *testing.T) {
// With real session + NewBackend func, it switches backend // With real session + NewBackend func, it switches backend
testStoreWrite(t, sf, "cfg", []byte("backend=openai")) testStoreWrite(t, sf, "cfg", []byte("backend=openai"))
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
if sess.Core.BackendName() != "openai" { if sess.Core.Agent().BackendName() != "openai" {
t.Errorf("BackendName() = %q; want openai", sess.Core.BackendName()) t.Errorf("BackendName() = %q; want openai", sess.Core.Agent().BackendName())
} }
testStoreWrite(t, sf, "cfg", []byte("model=gpt-4")) testStoreWrite(t, sf, "cfg", []byte("model=gpt-4"))
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
if sess.Core.ModelName() != "gpt-4" { if sess.Core.Agent().ModelName() != "gpt-4" {
t.Errorf("ModelName() = %q; want gpt-4", sess.Core.ModelName()) t.Errorf("ModelName() = %q; want gpt-4", sess.Core.Agent().ModelName())
} }
} }
@ -622,7 +622,7 @@ func TestSessionFileStoreWriteBackendWhileRunning(t *testing.T) {
defer sess.Cancel() defer sess.Cancel()
// Make session running // Make session running
go sess.Core.Submit(sess.Ctx, "hello") go sess.Core.Agent().Submit(sess.Ctx, "hello")
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
sf := newTestSessionFileStore(t, sess) sf := newTestSessionFileStore(t, sess)
@ -647,7 +647,7 @@ func TestSessionFileStoreWriteParams(t *testing.T) {
sf := newTestSessionFileStore(t, sess) sf := newTestSessionFileStore(t, sess)
testStoreWrite(t, sf, "cfg", []byte("maxTokens=2048")) testStoreWrite(t, sf, "cfg", []byte("maxTokens=2048"))
p := sess.Core.GenerationParams() p := sess.Core.Agent().GenParams()
if p.MaxTokens != 2048 { if p.MaxTokens != 2048 {
t.Errorf("MaxTokens = %d; want 2048", p.MaxTokens) t.Errorf("MaxTokens = %d; want 2048", p.MaxTokens)
} }
@ -657,7 +657,7 @@ func TestSessionFileStoreWriteParamsWhileRunning(t *testing.T) {
sess := testBlockingSession("s1") sess := testBlockingSession("s1")
defer sess.Cancel() defer sess.Cancel()
go sess.Core.Submit(sess.Ctx, "hello") go sess.Core.Agent().Submit(sess.Ctx, "hello")
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
sf := newTestSessionFileStore(t, sess) sf := newTestSessionFileStore(t, sess)
@ -673,7 +673,7 @@ func TestSessionFileStoreHandleCtl(t *testing.T) {
defer sess.Cancel() defer sess.Cancel()
// Make session running for interrupt test // Make session running for interrupt test
go sess.Core.Submit(sess.Ctx, "hello") go sess.Core.Agent().Submit(sess.Ctx, "hello")
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
sf := newTestSessionFileStore(t, sess) sf := newTestSessionFileStore(t, sess)
@ -681,7 +681,7 @@ func TestSessionFileStoreHandleCtl(t *testing.T) {
// stop — interrupts the running session // stop — interrupts the running session
testStoreWrite(t, sf, "ctl", []byte("stop")) testStoreWrite(t, sf, "ctl", []byte("stop"))
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
if sess.Core.IsRunning() { if sess.Core.Agent().IsRunning() {
t.Error("ctl stop should interrupt (session should not be running)") t.Error("ctl stop should interrupt (session should not be running)")
} }
@ -730,7 +730,7 @@ func TestSessionFileStoreBlockingRead(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Submit triggers state change: idle → thinking // Submit triggers state change: idle → thinking
go sess.Core.Submit(sess.Ctx, "trigger") go sess.Core.Agent().Submit(sess.Ctx, "trigger")
select { select {
case v := <-done: case v := <-done:
@ -1067,12 +1067,12 @@ func TestSessionInterrupt(t *testing.T) {
sess := testBlockingSession("s1") sess := testBlockingSession("s1")
defer sess.Cancel() defer sess.Cancel()
go sess.Core.Submit(sess.Ctx, "hello") go sess.Core.Agent().Submit(sess.Ctx, "hello")
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
sess.Interrupt() sess.Interrupt()
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
if sess.Core.IsRunning() { if sess.Core.Agent().IsRunning() {
t.Error("session should not be running after interrupt") t.Error("session should not be running after interrupt")
} }
} }

View File

@ -241,10 +241,10 @@ func (s *Manager) CreateSession(args []string) (string, error) {
s.mu.Unlock() s.mu.Unlock()
// HACK: Load the agent now that the session mount is active. // HACK: Load the agent now that the session mount is active.
core.Submit(ctx, "/agent "+agentName) core.Agent().Submit(ctx, "/agent "+agentName)
s.cfg.Log.Info("new session %s (backend=%s model=%s agent=%s)", s.cfg.Log.Info("new session %s (backend=%s model=%s agent=%s)",
sessID, core.BackendName(), core.ModelName(), core.AgentName()) sessID, core.Agent().BackendName(), core.Agent().ModelName(), core.Agent().Name())
if s.cfg.OnSessionCreated != nil { if s.cfg.OnSessionCreated != nil {
s.cfg.OnSessionCreated(sessID, sess) s.cfg.OnSessionCreated(sessID, sess)
} }
@ -271,7 +271,7 @@ func (s *Manager) renameSession(old, new string) error {
s.mu.Unlock() s.mu.Unlock()
return fmt.Errorf("session already exists: %s", newID) return fmt.Errorf("session already exists: %s", newID)
} }
if sess.Core.IsRunning() { if sess.Core.Agent().IsRunning() {
s.mu.Unlock() s.mu.Unlock()
return fmt.Errorf("cannot rename while agent is running") return fmt.Errorf("cannot rename while agent is running")
} }

View File

@ -286,7 +286,7 @@ func (s *Manager) PeerSubmit(sessID, peerID, prompt string) error {
if !isPeer { if !isPeer {
return fmt.Errorf("%s is not a peer of %s", peerID, sessID) return fmt.Errorf("%s is not a peer of %s", peerID, sessID)
} }
go peer.Core.Submit(peer.Ctx, prompt) go peer.Core.Agent().Submit(peer.Ctx, prompt)
return nil return nil
} }

View File

@ -291,7 +291,7 @@ func (s *Manager) waitIdle(poll, timeout time.Duration) {
allIdle := true allIdle := true
s.mu.RLock() s.mu.RLock()
for _, sess := range s.sessions { for _, sess := range s.sessions {
if sess.Core.State() != "idle" { if sess.Core.Agent().State() != "idle" {
allIdle = false allIdle = false
break break
} }
@ -332,11 +332,11 @@ func (s *Manager) index() []byte {
for _, id := range ids { for _, id := range ids {
sess := s.sessions[id] sess := s.sessions[id]
sess.mu.RLock() sess.mu.RLock()
state := sess.Core.State() state := sess.Core.Agent().State()
cwd := sess.Core.CWD() cwd := sess.Core.CWD()
be := sess.Core.BackendName() be := sess.Core.Agent().BackendName()
model := sess.Core.ModelName() model := sess.Core.Agent().ModelName()
agent := sess.Core.AgentName() agent := sess.Core.Agent().Name()
sess.mu.RUnlock() sess.mu.RUnlock()
fmt.Fprintf(&sb, "%s\t%s\t%s\t%s\t%s\t%s\n", id, state, cwd, be, model, agent) fmt.Fprintf(&sb, "%s\t%s\t%s\t%s\t%s\t%s\n", id, state, cwd, be, model, agent)
} }

View File

@ -3,6 +3,7 @@ package mgr
import ( import (
"context" "context"
"sync" "sync"
"strings"
"time" "time"
"ollie/session" "ollie/session"
@ -53,7 +54,8 @@ func (sess *Session) CachedListModels() string {
sess.modelsMu.Unlock() sess.modelsMu.Unlock()
// Cache miss — fetch and store. // Cache miss — fetch and store.
result := sess.Core.ListModels() models := sess.Core.Agent().ListModels()
result := strings.Join(models, "\n")
sess.modelsMu.Lock() sess.modelsMu.Lock()
sess.modelsCache = result sess.modelsCache = result
sess.modelsCacheAt = time.Now() sess.modelsCacheAt = time.Now()

View File

@ -129,7 +129,7 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) fs.FileSpec {
} }
case "reactions": case "reactions":
fs.Read = func() ([]byte, error) { fs.Read = func() ([]byte, error) {
data, err := json.Marshal(h.sess.Core.Reactions()) data, err := json.Marshal(h.sess.Core.Agent().Reactions())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -151,7 +151,7 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) fs.FileSpec {
} }
case "fifo.out": case "fifo.out":
fs.Read = func() ([]byte, error) { fs.Read = func() ([]byte, error) {
item, ok := h.sess.Core.PopQueue() item, ok := h.sess.Core.Agent().PopQueue()
if !ok { if !ok {
return nil, nil return nil, nil
} }
@ -203,7 +203,7 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) fs.FileSpec {
h.sess.prevPrompt = []byte(input) h.sess.prevPrompt = []byte(input)
h.sess.mu.Unlock() h.sess.mu.Unlock()
go func() { go func() {
h.sess.Core.Submit(h.sess.Ctx, input) h.sess.Core.Agent().Submit(h.sess.Ctx, input)
h.sess.EnsureTrailingNewline() h.sess.EnsureTrailingNewline()
}() }()
return nil return nil
@ -264,7 +264,7 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) fs.FileSpec {
if req.Emoji == "" { if req.Emoji == "" {
return fmt.Errorf("react: emoji is required") return fmt.Errorf("react: emoji is required")
} }
return h.sess.Core.ReactTo(req.ResponseID, req.Emoji) return h.sess.Core.Agent().React(req.ResponseID, req.Emoji)
} }
} }
@ -275,11 +275,11 @@ func (h *sessionHelper) fileSpec(name string, mode os.FileMode) fs.FileSpec {
defer cancel() defer cancel()
context.AfterFunc(h.sess.Ctx, cancel) context.AfterFunc(h.sess.Ctx, cancel)
if base == "" { if base == "" {
base = h.sess.Core.State() base = h.sess.Core.Agent().State()
} }
v, ok := h.sess.Core.WaitChange(ctx, agent.WatchState, base) v, ok := h.sess.Core.WaitChange(ctx, agent.WatchState, base)
if !ok { if !ok {
s := h.sess.Core.State() s := h.sess.Core.Agent().State()
return []byte(s + "\n"), s, nil return []byte(s + "\n"), s, nil
} }
return []byte(v + "\n"), v, nil return []byte(v + "\n"), v, nil
@ -294,18 +294,18 @@ func (h *sessionHelper) content(name string) string {
defer h.sess.mu.RUnlock() defer h.sess.mu.RUnlock()
switch name { switch name {
case "usage": case "usage":
return h.sess.Core.Usage() + "\n" return h.sess.Core.Agent().UsageStr() + "\n"
case "cost": case "cost":
return h.sess.Core.Cost() return h.sess.Core.Agent().CostStr()
case "ctxsz": case "ctxsz":
return h.sess.Core.CtxSz() + "\n" return h.sess.Core.Agent().CtxSz() + "\n"
case "models": case "models":
h.log.Debug("content(models) called") h.log.Debug("content(models) called")
return h.sess.CachedListModels() + "\n" return h.sess.CachedListModels() + "\n"
case "systemprompt": case "systemprompt":
return h.sess.Core.SystemPrompt() return h.sess.Core.Agent().SystemPrompt()
case "state": case "state":
return h.sess.Core.State() + "\n" return h.sess.Core.Agent().State() + "\n"
case "offset": case "offset":
return fmt.Sprintf("%d\n", h.sess.ChatOffset) return fmt.Sprintf("%d\n", h.sess.ChatOffset)
case "env": case "env":
@ -316,7 +316,7 @@ func (h *sessionHelper) content(name string) string {
var sb strings.Builder var sb strings.Builder
enc := json.NewEncoder(&sb) enc := json.NewEncoder(&sb)
enc.SetEscapeHTML(false) enc.SetEscapeHTML(false)
for _, m := range h.sess.Core.Context() { for _, m := range h.sess.Core.Agent().Context() {
enc.Encode(m) enc.Encode(m)
} }
return sb.String() return sb.String()
@ -374,12 +374,12 @@ func (h *sessionHelper) envContent() string {
func (h *sessionHelper) cfgContent() string { func (h *sessionHelper) cfgContent() string {
h.sess.mu.RLock() h.sess.mu.RLock()
defer h.sess.mu.RUnlock() defer h.sess.mu.RUnlock()
p := h.sess.Core.GenerationParams() p := h.sess.Core.Agent().GenParams()
var sb strings.Builder var sb strings.Builder
fmt.Fprintf(&sb, "name=%s\n", h.sess.id) fmt.Fprintf(&sb, "name=%s\n", h.sess.id)
fmt.Fprintf(&sb, "backend=%s\n", h.sess.Core.BackendName()) fmt.Fprintf(&sb, "backend=%s\n", h.sess.Core.Agent().BackendName())
fmt.Fprintf(&sb, "model=%s\n", h.sess.Core.ModelName()) fmt.Fprintf(&sb, "model=%s\n", h.sess.Core.Agent().ModelName())
fmt.Fprintf(&sb, "agent=%s\n", h.sess.Core.AgentName()) fmt.Fprintf(&sb, "agent=%s\n", h.sess.Core.Agent().Name())
fmt.Fprintf(&sb, "cwd=%s\n", h.sess.Core.CWD()) fmt.Fprintf(&sb, "cwd=%s\n", h.sess.Core.CWD())
fmt.Fprintf(&sb, "remote=%s\n", h.sess.remote) fmt.Fprintf(&sb, "remote=%s\n", h.sess.remote)
fmt.Fprintf(&sb, "maxTokens=%d\n", p.MaxTokens) fmt.Fprintf(&sb, "maxTokens=%d\n", p.MaxTokens)
@ -450,12 +450,12 @@ func (h *sessionHelper) cfgContent() string {
} else { } else {
sb.WriteString("verbosity=\n") sb.WriteString("verbosity=\n")
} }
fmt.Fprintf(&sb, "compactionModel=%s\n", h.sess.Core.CompactionModel()) fmt.Fprintf(&sb, "compactionModel=%s\n", h.sess.Core.Agent().CompactionModel())
return sb.String() return sb.String()
} }
func (h *sessionHelper) handleCfg(input string) error { func (h *sessionHelper) handleCfg(input string) error {
p := h.sess.Core.GenerationParams() p := h.sess.Core.Agent().GenParams()
hasParams := false hasParams := false
var deferredBackend, deferredModel string var deferredBackend, deferredModel string
for _, line := range strings.Split(input, "\n") { for _, line := range strings.Split(input, "\n") {
@ -473,7 +473,7 @@ func (h *sessionHelper) handleCfg(input string) error {
if v == "" { if v == "" {
continue continue
} }
if h.sess.Core.IsRunning() { if h.sess.Core.Agent().IsRunning() {
return fmt.Errorf("cannot rename while agent is running") return fmt.Errorf("cannot rename while agent is running")
} }
if err := h.rename(v); err != nil { if err := h.rename(v); err != nil {
@ -483,15 +483,15 @@ func (h *sessionHelper) handleCfg(input string) error {
if v == "" { if v == "" {
continue continue
} }
if h.sess.Core.IsRunning() { if h.sess.Core.Agent().IsRunning() {
return fmt.Errorf("cannot switch %s while agent is running", k) return fmt.Errorf("cannot switch %s while agent is running", k)
} }
h.sess.Core.Submit(h.sess.Ctx, "/agent "+v) h.sess.Core.Agent().Submit(h.sess.Ctx, "/agent "+v)
case "backend", "model": case "backend", "model":
if v == "" { if v == "" {
continue continue
} }
if h.sess.Core.IsRunning() { if h.sess.Core.Agent().IsRunning() {
return fmt.Errorf("cannot switch %s while agent is running", k) return fmt.Errorf("cannot switch %s while agent is running", k)
} }
// Defer backend/model until after the loop so they override // Defer backend/model until after the loop so they override
@ -610,22 +610,22 @@ func (h *sessionHelper) handleCfg(input string) error {
hasParams = true hasParams = true
p.Verbosity = v p.Verbosity = v
case "compactionModel": case "compactionModel":
h.sess.Core.SetCompactionModel(v) h.sess.Core.Agent().SetCompactionModel(v)
// state → read-only, silently ignored // state → read-only, silently ignored
} }
} }
// Apply backend/model after agent= so manual overrides win. // Apply backend/model after agent= so manual overrides win.
if deferredBackend != "" { if deferredBackend != "" {
h.sess.Core.Submit(h.sess.Ctx, "/backend "+deferredBackend) h.sess.Core.Agent().Submit(h.sess.Ctx, "/backend "+deferredBackend)
} }
if deferredModel != "" { if deferredModel != "" {
h.sess.Core.Submit(h.sess.Ctx, "/model "+deferredModel) h.sess.Core.Agent().Submit(h.sess.Ctx, "/model "+deferredModel)
} }
if hasParams { if hasParams {
if h.sess.Core.IsRunning() { if h.sess.Core.Agent().IsRunning() {
return fmt.Errorf("cannot change params while agent is running") return fmt.Errorf("cannot change params while agent is running")
} }
return h.sess.Core.SetGenerationParams(p) h.sess.Core.Agent().SetGenParams(p)
} }
return nil return nil
} }
@ -680,7 +680,7 @@ func (h *sessionHelper) handleCtl(input string) error {
"agents", "agent", "sessions", "cwd", "skills", "agents", "agent", "sessions", "cwd", "skills",
"tools", "context", "usage", "cost", "history", "tools", "context", "usage", "cost", "history",
"irw", "help": "irw", "help":
h.sess.Core.Submit(h.sess.Ctx, "/"+input) h.sess.Core.Agent().Submit(h.sess.Ctx, "/"+input)
default: default:
return fmt.Errorf("unknown ctl command: %s", cmd[0]) return fmt.Errorf("unknown ctl command: %s", cmd[0])
} }

BIN
olliesrv.test Executable file

Binary file not shown.