Files
picoclaw/pkg/agent/agent_event.go
T
lxowalle b3a7b7ad64 feat: agent self evolution (#2847)
* feat: add agent self-evolution

* fix ci

* delete unused doc

* fix lint

* fix evolution review issues
2026-05-11 16:13:27 +08:00

123 lines
3.1 KiB
Go

// PicoClaw - Ultra-lightweight personal AI agent
package agent
import (
"fmt"
runtimeevents "github.com/sipeed/picoclaw/pkg/events"
)
func (al *AgentLoop) newTurnEventScope(agentID, sessionKey string, turnCtx *TurnContext) turnEventScope {
seq := al.turnSeq.Add(1)
return turnEventScope{
agentID: agentID,
sessionKey: sessionKey,
turnID: fmt.Sprintf("%s-turn-%d", agentID, seq),
context: cloneTurnContext(turnCtx),
}
}
func (ts turnEventScope) meta(iteration int, source, tracePath string) HookMeta {
return HookMeta{
AgentID: ts.agentID,
TurnID: ts.turnID,
SessionKey: ts.sessionKey,
Iteration: iteration,
Source: source,
TracePath: tracePath,
turnContext: cloneTurnContext(ts.context),
}
}
func (al *AgentLoop) emitEvent(kind runtimeevents.Kind, meta HookMeta, payload any) {
clonedMeta := cloneHookMeta(meta)
eventCtx := cloneTurnContext(clonedMeta.turnContext)
evt := runtimeevents.Event{
Kind: kind,
Source: runtimeevents.Source{Component: "agent", Name: clonedMeta.AgentID},
Scope: runtimeScopeFromHookMeta(clonedMeta, eventCtx),
Correlation: runtimeCorrelationFromHookMeta(clonedMeta),
Severity: runtimeSeverityForAgentEvent(kind, payload),
Payload: payload,
Attrs: runtimeAttrsFromHookMeta(clonedMeta),
}
if al == nil {
return
}
deliveredToEvolution := false
if kind == runtimeevents.KindAgentTurnEnd {
evolution := al.currentEvolutionBridge()
if evolution != nil {
deliveredToEvolution = evolution.handleRuntimeTurnEnd(evt)
}
}
if deliveredToEvolution {
if evt.Attrs == nil {
evt.Attrs = make(map[string]any, 1)
}
evt.Attrs[evolutionDirectDeliveryAttr] = true
}
al.publishRuntimeEvent(evt)
}
func (al *AgentLoop) currentEvolutionBridge() *evolutionBridge {
if al == nil {
return nil
}
al.mu.RLock()
defer al.mu.RUnlock()
return al.evolution
}
func (al *AgentLoop) isCurrentEvolutionBridge(bridge *evolutionBridge) bool {
if al == nil || bridge == nil {
return false
}
al.mu.RLock()
defer al.mu.RUnlock()
return al.evolution == bridge
}
// MountHook registers an in-process hook on the agent loop.
func (al *AgentLoop) MountHook(reg HookRegistration) error {
if al == nil || al.hooks == nil {
return fmt.Errorf("hook manager is not initialized")
}
return al.hooks.Mount(reg)
}
// UnmountHook removes a previously registered in-process hook.
func (al *AgentLoop) UnmountHook(name string) {
if al == nil || al.hooks == nil {
return
}
al.hooks.Unmount(name)
}
// RuntimeEvents returns the root runtime event channel.
func (al *AgentLoop) RuntimeEvents() runtimeevents.EventChannel {
if al == nil || al.runtimeEvents == nil {
return nil
}
return al.runtimeEvents.Channel()
}
// RuntimeEventStats returns runtime event bus counters.
func (al *AgentLoop) RuntimeEventStats() runtimeevents.Stats {
if al == nil || al.runtimeEvents == nil {
return runtimeevents.Stats{Closed: true}
}
return al.runtimeEvents.Stats()
}
// RuntimeEventBus returns the runtime event bus used by the agent loop.
func (al *AgentLoop) RuntimeEventBus() runtimeevents.Bus {
if al == nil {
return nil
}
return al.runtimeEvents
}