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:
Hoshina
2026-04-26 16:28:41 +08:00
parent dc80e8f5f2
commit 6e8a81bfbf
3 changed files with 14 additions and 19 deletions
+1 -4
View File
@@ -356,14 +356,11 @@ func runProcessHookHelper() error {
}
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
if err := json.Unmarshal(msg.Params, &evt); err == nil {
if kind, ok := evt["kind"].(string); ok {
_ = 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
View File
@@ -112,14 +112,14 @@ func (p *llmHookTestProvider) GetDefaultModel() string {
}
type llmObserverHook struct {
eventCh chan Event
eventCh chan runtimeevents.Event
lastInbound *bus.InboundContext
lastRoute *routing.ResolvedRoute
lastScope *session.SessionScope
}
func (h *llmObserverHook) OnEvent(ctx context.Context, evt Event) error {
if evt.Kind == EventKindTurnEnd {
func (h *llmObserverHook) OnRuntimeEvent(ctx context.Context, evt runtimeevents.Event) error {
if evt.Kind == runtimeevents.KindAgentTurnEnd {
select {
case h.eventCh <- evt:
default:
@@ -443,7 +443,7 @@ func TestAgentLoop_Hooks_ObserverAndLLMInterceptor(t *testing.T) {
al, agent, cleanup := newHookTestLoop(t, provider)
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 {
t.Fatalf("MountHook failed: %v", err)
}
@@ -507,17 +507,15 @@ func TestAgentLoop_Hooks_ObserverAndLLMInterceptor(t *testing.T) {
select {
case evt := <-hook.eventCh:
if evt.Kind != EventKindTurnEnd {
if evt.Kind != runtimeevents.KindAgentTurnEnd {
t.Fatalf("expected turn end event, got %v", evt.Kind)
}
if evt.Context == nil || evt.Context.Inbound == nil {
t.Fatal("expected observer event to carry inbound context")
}
if evt.Context.Route == nil || evt.Context.Route.AgentID != "main" {
t.Fatalf("expected observer event to carry route context, got %+v", evt.Context.Route)
}
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)
if evt.Scope.AgentID != "main" ||
evt.Scope.SessionKey != "session-1" ||
evt.Scope.Channel != "cli" ||
evt.Scope.ChatID != "direct" ||
evt.Scope.SenderID != "hook-user" {
t.Fatalf("runtime observer scope = %+v", evt.Scope)
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for hook observer event")
@@ -589,7 +587,7 @@ func TestAgentLoop_BtwCommand_UsesLLMHooks(t *testing.T) {
defer cleanup()
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 {
t.Fatalf("MountHook failed: %v", err)
}
+1 -1
View File
@@ -140,7 +140,7 @@ func TestSpawnSubTurn(t *testing.T) {
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)
defer collectCleanup()