package agent import "context" // WatchField names supported by Agent.WaitChange. const ( WatchState = "state" WatchFeed = "feed" ) // State returns the agent's current execution state. func (ag *Agent) State() string { ag.stateMu.RLock() s := ag.state ag.stateMu.RUnlock() return s } // SetState sets the agent's execution state and notifies waiters. func (ag *Agent) SetState(state string) { ag.stateMu.Lock() ag.state = state ag.stateMu.Unlock() ag.notifyChange() if ag.onStateChange != nil { ag.onStateChange(ag.id, state) } } // Reply returns the agent's last assistant response. func (ag *Agent) Reply() string { ag.stateMu.RLock() r := ag.reply ag.stateMu.RUnlock() return r } // SetOnStateChange sets a callback invoked whenever agent state changes. func (ag *Agent) SetOnStateChange(fn func(agentID, state string)) { ag.onStateChange = fn } // setReply sets the agent's last response. func (ag *Agent) setReply(reply string) { ag.stateMu.Lock() ag.reply = reply ag.stateMu.Unlock() } // notifyChange wakes all goroutines waiting on state changes. func (ag *Agent) notifyChange() { ag.signalMu.Lock() close(ag.signalCh) ag.signalCh = make(chan struct{}) ag.signalMu.Unlock() } // SignalCh returns the current signal channel (closed on any change). func (ag *Agent) SignalCh() <-chan struct{} { ag.signalMu.Lock() ch := ag.signalCh ag.signalMu.Unlock() return ch } // WaitChange blocks until the agent's state differs from current. // Returns the new value and true, or ("", false) if ctx is cancelled. func (ag *Agent) WaitChange(ctx context.Context, field, current string) (string, bool) { for { // Snapshot the signal channel before reading state. ag.signalMu.Lock() ch := ag.signalCh ag.signalMu.Unlock() var val string switch field { case WatchState: val = ag.State() case WatchFeed: val = ag.Feed.Hash() if val == "" { val = current // no data yet — block } default: return "", false } if val != current { return val, true } // Wait for either a state change or context cancellation. select { case <-ch: // Changed — loop to re-check. case <-ctx.Done(): return "", false } } } // emit sends an event to the agent's output handler. func (ag *Agent) emit(ev Event) { if ag.output != nil { ag.output(ev) } }