Support runtime backend switching via ctl
This commit is contained in:
parent
5a8f7e394e
commit
19971be343
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
|
@ -39,17 +40,17 @@ type Agent struct {
|
||||||
resultCache resultCache
|
resultCache resultCache
|
||||||
|
|
||||||
// Execution state — owned by the agent, protected by stateMu.
|
// Execution state — owned by the agent, protected by stateMu.
|
||||||
state string // "idle", "thinking", "calling: <tool>"
|
state string // "idle", "thinking", "calling: <tool>"
|
||||||
reply string // last assistant response
|
reply string // last assistant response
|
||||||
getCwd func() string // returns session working directory
|
getCwd func() string // returns session working directory
|
||||||
id string // agent identity (unique principal)
|
id string // agent identity (unique principal)
|
||||||
parentID string // immutable ID of the agent that spawned this agent
|
parentID string // immutable ID of the agent that spawned this agent
|
||||||
depth int // sub-agent depth (0=top-level, 1=sub-agent, 2=sub-sub-agent)
|
depth int // sub-agent depth (0=top-level, 1=sub-agent, 2=sub-sub-agent)
|
||||||
activeChildren atomic.Int32 // number of currently-running child sub-agents
|
activeChildren atomic.Int32 // number of currently-running child sub-agents
|
||||||
peers map[string]struct{} // peer agent names (same session)
|
peers map[string]struct{} // peer agent names (same session)
|
||||||
peerMu sync.RWMutex
|
peerMu sync.RWMutex
|
||||||
fifo Fifo // prompt queue
|
fifo Fifo // prompt queue
|
||||||
Feed Feed // streaming input gate (change-detecting)
|
Feed Feed // streaming input gate (change-detecting)
|
||||||
toolCallCount atomic.Int64
|
toolCallCount atomic.Int64
|
||||||
pendingInject atomic.Pointer[string]
|
pendingInject atomic.Pointer[string]
|
||||||
submitMu sync.Mutex // serializes Submit calls (commands + turns)
|
submitMu sync.Mutex // serializes Submit calls (commands + turns)
|
||||||
|
|
@ -298,6 +299,31 @@ func (ag *Agent) ModelName() string {
|
||||||
return ag.runtime.Backend.Model()
|
return ag.runtime.Backend.Model()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SwitchBackend replaces the active backend by name. The new backend is fully
|
||||||
|
// constructed before the runtime is changed, so a failed switch leaves the
|
||||||
|
// current backend usable. Backend changes are only safe between turns.
|
||||||
|
func (ag *Agent) SwitchBackend(name string) error {
|
||||||
|
name = strings.TrimSpace(name)
|
||||||
|
if name == "" {
|
||||||
|
return fmt.Errorf("backend requires a name")
|
||||||
|
}
|
||||||
|
if ag.IsRunning() {
|
||||||
|
return fmt.Errorf("cannot switch backend while agent is running")
|
||||||
|
}
|
||||||
|
if ag.newBackend == nil {
|
||||||
|
return fmt.Errorf("backend switching unavailable")
|
||||||
|
}
|
||||||
|
be, err := ag.newBackend(name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("backend %q: %w", name, err)
|
||||||
|
}
|
||||||
|
ag.runtime.Backend = be
|
||||||
|
ag.save()
|
||||||
|
ag.flush()
|
||||||
|
ag.notifyChange()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// State returns the agent's current execution state.
|
// State returns the agent's current execution state.
|
||||||
func (ag *Agent) State() string {
|
func (ag *Agent) State() string {
|
||||||
ag.stateMu.RLock()
|
ag.stateMu.RLock()
|
||||||
|
|
|
||||||
|
|
@ -1083,7 +1083,11 @@ func buildAgentChildren(a *agent.Agent, s *session.Session) []virtfs.FsNodeDecl
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("backend switching not supported via ctl; use cfg")
|
name := strings.Join(args, " ")
|
||||||
|
if err := a.SwitchBackend(name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return []byte(name + "\n"), nil
|
||||||
},
|
},
|
||||||
"name": func(args []string) ([]byte, error) {
|
"name": func(args []string) ([]byte, error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue