update kde submodule; session/fs changes
This commit is contained in:
parent
3febb30de8
commit
0cefd03e9a
|
|
@ -13,6 +13,7 @@ import (
|
|||
"ollie/backend"
|
||||
"ollie/elevate"
|
||||
"ollie/fsedsl"
|
||||
"ollie/paths"
|
||||
"ollie/session"
|
||||
"ollie/toolsrv"
|
||||
)
|
||||
|
|
@ -240,6 +241,10 @@ func readSessionIdx(_ HandlerCtx) ([]byte, error) {
|
|||
return session.BuildIndex(), nil
|
||||
}
|
||||
|
||||
func readAgentIdx(ctx HandlerCtx) ([]byte, error) {
|
||||
return session.BuildAgentIndex(ctx.Session.Core), nil
|
||||
}
|
||||
|
||||
func requestSessionNew(_ HandlerCtx, data []byte) ([]byte, error) {
|
||||
args := strings.Fields(string(data))
|
||||
name := ""
|
||||
|
|
@ -586,7 +591,7 @@ func readAgentCfg(ctx HandlerCtx) ([]byte, error) {
|
|||
fmt.Fprintf(&sb, "id=%s\n", ctx.Agent.ID())
|
||||
fmt.Fprintf(&sb, "profile=%s\n", ctx.Agent.Profile())
|
||||
fmt.Fprintf(&sb, "displayName=%s\n", ctx.Agent.Name())
|
||||
fmt.Fprintf(&sb, "cwd=%s\n", ctx.Session.Core.CWD())
|
||||
fmt.Fprintf(&sb, "cwd=%s\n", ctx.Agent.Cwd())
|
||||
fmt.Fprintf(&sb, "remote=%s\n", ctx.AgentLog.remote)
|
||||
fmt.Fprintf(&sb, "maxTokens=%d\n", p.MaxTokens)
|
||||
fmt.Fprintf(&sb, "temperature=%v\n", p.Temperature)
|
||||
|
|
@ -658,7 +663,7 @@ func writeAgentCtl(ctx HandlerCtx, data []byte) error {
|
|||
}
|
||||
|
||||
func readAgentCwd(ctx HandlerCtx) ([]byte, error) {
|
||||
return []byte(ctx.Session.Core.CWD() + "\n"), nil
|
||||
return []byte(ctx.Agent.Cwd() + "\n"), nil
|
||||
}
|
||||
|
||||
func writeAgentCwd(ctx HandlerCtx, data []byte) error {
|
||||
|
|
@ -666,7 +671,12 @@ func writeAgentCwd(ctx HandlerCtx, data []byte) error {
|
|||
if input == "" {
|
||||
return nil
|
||||
}
|
||||
return ctx.Session.Core.SetCWD(input)
|
||||
input = paths.ExpandHome(input)
|
||||
if _, err := os.Stat(input); err != nil {
|
||||
return fmt.Errorf("cwd: %w", err)
|
||||
}
|
||||
ctx.Agent.SetCWD(input)
|
||||
return nil
|
||||
}
|
||||
|
||||
func readAgentUsage(ctx HandlerCtx) ([]byte, error) {
|
||||
|
|
|
|||
|
|
@ -233,6 +233,11 @@ var treeSpec = DirNode("/",
|
|||
Request(requestAgentNew),
|
||||
),
|
||||
|
||||
FileNode("idx", 0444,
|
||||
Doc("Agent index. Format: name<tab>id<tab>cwd<tab>backend<tab>model per line."),
|
||||
Read(readAgentIdx),
|
||||
),
|
||||
|
||||
Each("{aname}", agentBindings,
|
||||
Doc("Agent directory. Addressable by name or immutable ID."),
|
||||
|
||||
|
|
|
|||
2
kde
2
kde
|
|
@ -1 +1 @@
|
|||
Subproject commit 2c7b5e6fc54b0eb78244650e6049a7b5e77a38b9
|
||||
Subproject commit 73e262ffafe3cc32012e35e9f142261bd7707794
|
||||
|
|
@ -33,6 +33,7 @@ type PersistedAgent struct {
|
|||
Profile string `json:"profile"`
|
||||
Backend string `json:"backend"`
|
||||
Model string `json:"model"`
|
||||
CWD string `json:"cwd"`
|
||||
Messages []backend.Message `json:"messages"`
|
||||
TaskState *agent.TaskState `json:"taskState,omitempty"`
|
||||
// Usage tracking
|
||||
|
|
@ -65,7 +66,6 @@ func PersistSession(name string) error {
|
|||
ps := PersistedSession{
|
||||
ID: sess.ID(),
|
||||
Name: sess.Name(),
|
||||
CWD: sess.CWD(),
|
||||
Remote: sess.Remote(),
|
||||
Paused: sess.IsPaused(),
|
||||
}
|
||||
|
|
@ -77,6 +77,7 @@ func PersistSession(name string) error {
|
|||
Profile: ag.Profile(),
|
||||
Backend: ag.BackendName(),
|
||||
Model: ag.ModelName(),
|
||||
CWD: ag.Cwd(),
|
||||
Messages: ag.Messages(),
|
||||
TaskState: ag.TaskState(),
|
||||
}
|
||||
|
|
@ -192,51 +193,66 @@ func restoreSessionFromFile(path string) (*RestoredSession, error) {
|
|||
}
|
||||
|
||||
func restoreMultiAgentSession(ps *PersistedSession) (*RestoredSession, error) {
|
||||
cwd := ps.CWD
|
||||
if cwd == "" {
|
||||
cwd, _ = os.Getwd()
|
||||
}
|
||||
|
||||
// For paused sessions, skip tool server setup entirely.
|
||||
// It will be set up on Resume().
|
||||
var infra *SessionInfra
|
||||
if !ps.Paused {
|
||||
var err error
|
||||
infra, err = SetupToolServer(ToolServerConfig{
|
||||
Ctx: serverCtx,
|
||||
CWD: cwd,
|
||||
RemoteTarget: ps.Remote,
|
||||
Yolo: pkgYolo,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create empty session
|
||||
// Create empty session first
|
||||
ctx, cancel := context.WithCancel(serverCtx)
|
||||
sess := NewEmpty(ps.ID, ctx, cancel)
|
||||
sess.SetName(ps.Name)
|
||||
sess.SetRemote(ps.Remote)
|
||||
if infra != nil {
|
||||
sess.SetProc(infra.Proc)
|
||||
sess.SetKeeper(infra.Keeper)
|
||||
sess.SetToolsConn(infra.ToolsConn)
|
||||
}
|
||||
if ps.Paused {
|
||||
sess.SetPaused(true)
|
||||
}
|
||||
|
||||
var restoredAgents []RestoredAgent
|
||||
|
||||
// Build prompt env (works without live infra)
|
||||
promptEnv := agent.PromptEnv(cwd)
|
||||
if infra != nil {
|
||||
promptEnv = infra.PromptEnv
|
||||
}
|
||||
|
||||
// Restore each agent
|
||||
// Restore each agent with its own CWD
|
||||
for _, pa := range ps.Agents {
|
||||
// Get agent's CWD (fall back to session CWD for backwards compat, then pwd)
|
||||
cwd := pa.CWD
|
||||
if cwd == "" {
|
||||
cwd = ps.CWD
|
||||
}
|
||||
if cwd == "" {
|
||||
cwd, _ = os.Getwd()
|
||||
}
|
||||
|
||||
// For paused sessions, skip tool server setup
|
||||
var infra *SessionInfra
|
||||
if !ps.Paused {
|
||||
var err error
|
||||
// Reuse existing infra if available (from earlier agents)
|
||||
var reuseFrom *InfraConfig
|
||||
if sess.Proc() != nil {
|
||||
reuseFrom = &InfraConfig{
|
||||
Proc: sess.Proc(),
|
||||
Keeper: sess.Keeper(),
|
||||
ToolsConn: sess.ToolsConn(),
|
||||
}
|
||||
}
|
||||
infra, err = SetupToolServer(ToolServerConfig{
|
||||
Ctx: serverCtx,
|
||||
CWD: cwd,
|
||||
RemoteTarget: ps.Remote,
|
||||
Yolo: pkgYolo,
|
||||
ReuseFrom: reuseFrom,
|
||||
})
|
||||
if err != nil {
|
||||
pkgLog.Error("restore agent %s: setup tool server: %v", pa.ID, err)
|
||||
continue
|
||||
}
|
||||
// Store infra on session (first agent sets it up)
|
||||
if sess.Proc() == nil {
|
||||
sess.SetProc(infra.Proc)
|
||||
sess.SetKeeper(infra.Keeper)
|
||||
sess.SetToolsConn(infra.ToolsConn)
|
||||
}
|
||||
}
|
||||
|
||||
// Build prompt env
|
||||
promptEnv := agent.PromptEnv(cwd)
|
||||
if infra != nil {
|
||||
promptEnv = infra.PromptEnv
|
||||
}
|
||||
|
||||
cfg := LoadAgentConfig(pkgAgentsDir, pa.Profile, nil)
|
||||
|
||||
be, err := backend.NewWithName(pa.Backend)
|
||||
|
|
@ -311,8 +327,8 @@ func restoreMultiAgentSession(ps *PersistedSession) (*RestoredSession, error) {
|
|||
Register(sess.Name(), sess)
|
||||
|
||||
toolCount := 0
|
||||
if infra != nil && infra.ToolsConn != nil {
|
||||
if infos, err := infra.ToolsConn.ListTools(); err == nil {
|
||||
if sess.ToolsConn() != nil {
|
||||
if infos, err := sess.ToolsConn().ListTools(); err == nil {
|
||||
toolCount = len(infos)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,10 +242,12 @@ func BuildIndex() []byte {
|
|||
for _, e := range entries {
|
||||
sess := e.sess
|
||||
connected := sess.IsConnected()
|
||||
cwd := sess.CWD()
|
||||
var be, model string
|
||||
var cwd, be, model string
|
||||
var agentList []string
|
||||
for _, ag := range sess.Agents() {
|
||||
if cwd == "" {
|
||||
cwd = ag.Cwd()
|
||||
}
|
||||
if be == "" {
|
||||
be = ag.BackendName()
|
||||
model = ag.ModelName()
|
||||
|
|
@ -259,6 +261,17 @@ func BuildIndex() []byte {
|
|||
return []byte(sb.String())
|
||||
}
|
||||
|
||||
// BuildAgentIndex builds the agent index for a session.
|
||||
// Format: name<tab>id<tab>cwd<tab>backend<tab>model per line.
|
||||
func BuildAgentIndex(sess *Session) []byte {
|
||||
var sb strings.Builder
|
||||
for _, ag := range sess.Agents() {
|
||||
fmt.Fprintf(&sb, "%s\t%s\t%s\t%s\t%s\n",
|
||||
ag.Name(), ag.ID(), ag.Cwd(), ag.BackendName(), ag.ModelName())
|
||||
}
|
||||
return []byte(sb.String())
|
||||
}
|
||||
|
||||
// CreateEmpty creates an empty session (no agent).
|
||||
// If remote is non-empty, spawns a remote tool server via SSH.
|
||||
func CreateEmpty(name, remote string) (*Session, error) {
|
||||
|
|
@ -324,7 +337,7 @@ func CreateAgent(sessName string, args []string) (*agent.Agent, error) {
|
|||
|
||||
// Parse args
|
||||
profile := "default"
|
||||
var agentName, backendName, modelName, remoteTarget string
|
||||
var agentName, backendName, modelName, remoteTarget, cwdOverride string
|
||||
for _, arg := range args {
|
||||
if k, v, ok := strings.Cut(arg, "="); ok {
|
||||
switch k {
|
||||
|
|
@ -336,6 +349,8 @@ func CreateAgent(sessName string, args []string) (*agent.Agent, error) {
|
|||
modelName = v
|
||||
case "remote":
|
||||
remoteTarget = v
|
||||
case "cwd":
|
||||
cwdOverride = v
|
||||
}
|
||||
} else if profile == "default" {
|
||||
profile = arg
|
||||
|
|
@ -346,7 +361,10 @@ func CreateAgent(sessName string, args []string) (*agent.Agent, error) {
|
|||
|
||||
uname := NextUname()
|
||||
sessID := sess.ID()
|
||||
cwd := sess.CWD()
|
||||
if cwdOverride == "" {
|
||||
return nil, fmt.Errorf("cwd= is required when creating an agent")
|
||||
}
|
||||
cwd := cwdOverride
|
||||
|
||||
// Set up tool server - reuse existing session infrastructure
|
||||
infra, err := SetupToolServer(ToolServerConfig{
|
||||
|
|
@ -377,14 +395,22 @@ func CreateAgent(sessName string, args []string) (*agent.Agent, error) {
|
|||
env = append(env, infra.PromptEnv...)
|
||||
rt := agent.BuildRuntime(cfg, infra.ToolsConn, cwd, env, layers.SystemPrompt, layers.EnvBlock)
|
||||
|
||||
// Apply backend/model overrides to runtime
|
||||
if backendName != "" {
|
||||
if be, err := backend.NewWithName(backendName); err == nil {
|
||||
rt.Backend = be
|
||||
}
|
||||
// Create backend - use override if provided, otherwise use config or env default
|
||||
beName := backendName
|
||||
if beName == "" {
|
||||
beName = rt.CfgBackend
|
||||
}
|
||||
be, err := backend.NewWithName(beName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create backend: %w", err)
|
||||
}
|
||||
rt.Backend = be
|
||||
|
||||
// Apply model override if provided
|
||||
if modelName != "" {
|
||||
rt.Backend.SetModel(modelName)
|
||||
} else if rt.CfgModel != "" {
|
||||
rt.Backend.SetModel(rt.CfgModel)
|
||||
}
|
||||
|
||||
// Create agent
|
||||
|
|
|
|||
|
|
@ -272,18 +272,6 @@ func (a *Session) SetEnv(key, value string) {
|
|||
}
|
||||
}
|
||||
|
||||
// CWD returns the current working directory for tool execution
|
||||
// (from the first agent).
|
||||
func (a *Session) CWD() string {
|
||||
if len(a.agents) > 0 {
|
||||
if c := a.agents[0].Cwd(); c != "" {
|
||||
return c
|
||||
}
|
||||
}
|
||||
wd, _ := os.Getwd()
|
||||
return wd
|
||||
}
|
||||
|
||||
// Remote returns the remote target (e.g., SSH host) if any.
|
||||
func (a *Session) Remote() string {
|
||||
return a.remote
|
||||
|
|
@ -294,20 +282,6 @@ func (a *Session) SetRemote(remote string) {
|
|||
a.remote = remote
|
||||
}
|
||||
|
||||
// SetCWD validates and sets the working directory on all agents.
|
||||
func (a *Session) SetCWD(dir string) error {
|
||||
dir = paths.ExpandHome(dir)
|
||||
if dir != "" {
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
return fmt.Errorf("cwd: %w", err)
|
||||
}
|
||||
}
|
||||
for _, ag := range a.agents {
|
||||
ag.SetCWD(dir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSessionID renames the session.
|
||||
func (a *Session) SetSessionID(newID string) error {
|
||||
oldID := a.id
|
||||
|
|
@ -555,23 +529,41 @@ func (a *Session) Resume() error {
|
|||
}
|
||||
a.toolsConn = conn
|
||||
} else {
|
||||
// Session was restored paused without infra - set up now.
|
||||
cwd := a.CWD()
|
||||
infra, err := SetupToolServer(ToolServerConfig{
|
||||
Ctx: ctx,
|
||||
CWD: cwd,
|
||||
RemoteTarget: a.remote,
|
||||
Yolo: pkgYolo,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("resume setup failed: %w", err)
|
||||
}
|
||||
a.proc = infra.Proc
|
||||
a.keeper = infra.Keeper
|
||||
a.toolsConn = infra.ToolsConn
|
||||
|
||||
// Update agents with the new tool server connection.
|
||||
for _, ag := range a.agents {
|
||||
// Session was restored paused without infra - set up per-agent.
|
||||
for i, ag := range a.agents {
|
||||
cwd := ag.Cwd()
|
||||
if cwd == "" {
|
||||
cwd, _ = os.Getwd()
|
||||
}
|
||||
|
||||
// First agent spawns the tool server, others reuse
|
||||
var reuseFrom *InfraConfig
|
||||
if a.proc != nil {
|
||||
reuseFrom = &InfraConfig{
|
||||
Proc: a.proc,
|
||||
Keeper: a.keeper,
|
||||
ToolsConn: a.toolsConn,
|
||||
}
|
||||
}
|
||||
|
||||
infra, err := SetupToolServer(ToolServerConfig{
|
||||
Ctx: ctx,
|
||||
CWD: cwd,
|
||||
RemoteTarget: a.remote,
|
||||
Yolo: pkgYolo,
|
||||
ReuseFrom: reuseFrom,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("resume setup for agent %s failed: %w", ag.ID(), err)
|
||||
}
|
||||
|
||||
// First agent sets session infra
|
||||
if i == 0 {
|
||||
a.proc = infra.Proc
|
||||
a.keeper = infra.Keeper
|
||||
a.toolsConn = infra.ToolsConn
|
||||
}
|
||||
|
||||
ag.SetToolServer(infra.NewToolServer, infra.ToolsConn)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue