mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
test(events): prefer runtime hook observation
Use RuntimeEventObserver for the normal in-process hook observer path and make the process-hook helper assert hook.runtime_event notifications. Validation: go test ./pkg/agent; make lint
This commit is contained in:
@@ -356,14 +356,11 @@ func runProcessHookHelper() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if msg.ID == 0 {
|
if msg.ID == 0 {
|
||||||
if (msg.Method == "hook.event" || msg.Method == "hook.runtime_event") && eventLog != "" {
|
if msg.Method == "hook.runtime_event" && eventLog != "" {
|
||||||
var evt map[string]any
|
var evt map[string]any
|
||||||
if err := json.Unmarshal(msg.Params, &evt); err == nil {
|
if err := json.Unmarshal(msg.Params, &evt); err == nil {
|
||||||
if kind, ok := evt["kind"].(string); ok {
|
if kind, ok := evt["kind"].(string); ok {
|
||||||
_ = os.WriteFile(eventLog, []byte(kind+"\n"), 0o644)
|
_ = os.WriteFile(eventLog, []byte(kind+"\n"), 0o644)
|
||||||
} else if rawKind, ok := evt["Kind"].(float64); ok {
|
|
||||||
kind := EventKind(rawKind)
|
|
||||||
_ = os.WriteFile(eventLog, []byte(kind.String()+"\n"), 0o644)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-14
@@ -112,14 +112,14 @@ func (p *llmHookTestProvider) GetDefaultModel() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type llmObserverHook struct {
|
type llmObserverHook struct {
|
||||||
eventCh chan Event
|
eventCh chan runtimeevents.Event
|
||||||
lastInbound *bus.InboundContext
|
lastInbound *bus.InboundContext
|
||||||
lastRoute *routing.ResolvedRoute
|
lastRoute *routing.ResolvedRoute
|
||||||
lastScope *session.SessionScope
|
lastScope *session.SessionScope
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *llmObserverHook) OnEvent(ctx context.Context, evt Event) error {
|
func (h *llmObserverHook) OnRuntimeEvent(ctx context.Context, evt runtimeevents.Event) error {
|
||||||
if evt.Kind == EventKindTurnEnd {
|
if evt.Kind == runtimeevents.KindAgentTurnEnd {
|
||||||
select {
|
select {
|
||||||
case h.eventCh <- evt:
|
case h.eventCh <- evt:
|
||||||
default:
|
default:
|
||||||
@@ -443,7 +443,7 @@ func TestAgentLoop_Hooks_ObserverAndLLMInterceptor(t *testing.T) {
|
|||||||
al, agent, cleanup := newHookTestLoop(t, provider)
|
al, agent, cleanup := newHookTestLoop(t, provider)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
hook := &llmObserverHook{eventCh: make(chan Event, 1)}
|
hook := &llmObserverHook{eventCh: make(chan runtimeevents.Event, 1)}
|
||||||
if err := al.MountHook(NamedHook("llm-observer", hook)); err != nil {
|
if err := al.MountHook(NamedHook("llm-observer", hook)); err != nil {
|
||||||
t.Fatalf("MountHook failed: %v", err)
|
t.Fatalf("MountHook failed: %v", err)
|
||||||
}
|
}
|
||||||
@@ -507,17 +507,15 @@ func TestAgentLoop_Hooks_ObserverAndLLMInterceptor(t *testing.T) {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case evt := <-hook.eventCh:
|
case evt := <-hook.eventCh:
|
||||||
if evt.Kind != EventKindTurnEnd {
|
if evt.Kind != runtimeevents.KindAgentTurnEnd {
|
||||||
t.Fatalf("expected turn end event, got %v", evt.Kind)
|
t.Fatalf("expected turn end event, got %v", evt.Kind)
|
||||||
}
|
}
|
||||||
if evt.Context == nil || evt.Context.Inbound == nil {
|
if evt.Scope.AgentID != "main" ||
|
||||||
t.Fatal("expected observer event to carry inbound context")
|
evt.Scope.SessionKey != "session-1" ||
|
||||||
}
|
evt.Scope.Channel != "cli" ||
|
||||||
if evt.Context.Route == nil || evt.Context.Route.AgentID != "main" {
|
evt.Scope.ChatID != "direct" ||
|
||||||
t.Fatalf("expected observer event to carry route context, got %+v", evt.Context.Route)
|
evt.Scope.SenderID != "hook-user" {
|
||||||
}
|
t.Fatalf("runtime observer scope = %+v", evt.Scope)
|
||||||
if evt.Context.Scope == nil || evt.Context.Scope.Values["sender"] != "hook-user" {
|
|
||||||
t.Fatalf("expected observer event to carry session scope, got %+v", evt.Context.Scope)
|
|
||||||
}
|
}
|
||||||
case <-time.After(2 * time.Second):
|
case <-time.After(2 * time.Second):
|
||||||
t.Fatal("timed out waiting for hook observer event")
|
t.Fatal("timed out waiting for hook observer event")
|
||||||
@@ -589,7 +587,7 @@ func TestAgentLoop_BtwCommand_UsesLLMHooks(t *testing.T) {
|
|||||||
defer cleanup()
|
defer cleanup()
|
||||||
useTestSideQuestionProvider(al, provider)
|
useTestSideQuestionProvider(al, provider)
|
||||||
|
|
||||||
hook := &llmObserverHook{eventCh: make(chan Event, 1)}
|
hook := &llmObserverHook{eventCh: make(chan runtimeevents.Event, 1)}
|
||||||
if err := al.MountHook(NamedHook("llm-observer", hook)); err != nil {
|
if err := al.MountHook(NamedHook("llm-observer", hook)); err != nil {
|
||||||
t.Fatalf("MountHook failed: %v", err)
|
t.Fatalf("MountHook failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func TestSpawnSubTurn(t *testing.T) {
|
|||||||
agent: al.registry.GetDefaultAgent(),
|
agent: al.registry.GetDefaultAgent(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to real EventBus to capture events
|
// Subscribe to runtime events to capture sub-turn lifecycle.
|
||||||
collector, collectCleanup := newEventCollector(t, al)
|
collector, collectCleanup := newEventCollector(t, al)
|
||||||
defer collectCleanup()
|
defer collectCleanup()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user