feat(tasks): phase 2 — entity.touched events + task→entity involves edges

As the agent runs a task, record which entities each tool call references:
write an idempotent task —involves→ entity relationship and publish one
entity.touched event per entity (correlation_id = session, data {slug,tool}).
Extracted from tool ARGS only — never results — so a bulk fleet query can't
drag every entity into the task graph; bulk/no-slug tools stay silent.

Emitted from the nomos agent loop rather than the shared MCP wrapper, which
has no session id. The involves edges make a task's graph neighborhood its
involved-entity set (queryable via get_relations) — the substrate for the
knowledge loop; the events are the live pulse the context panel consumes in
phase 6.

Verified end-to-end on the local stack: a chat referencing lxc:caddy/lxc:gitea
produced entity.touched on the browser SSE stream with slug+tool+correlation,
and exactly one involves edge per entity despite repeated touches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 12:35:27 +02:00
parent 72e9fe534e
commit 3dba2e550a
2 changed files with 85 additions and 0 deletions

View File

@@ -392,6 +392,11 @@ func (a *agent) chatWith(ctx context.Context, sessionID, message, systemInject s
a.store.linkExecution(ctx, execID, sessionID)
}
// Record which entities this task touched (task —involves→ entity)
// and pulse them on the live context panel. Args only — never
// results — so a bulk query doesn't drag the whole fleet in.
a.store.recordTouched(ctx, sessionID, tc.Function.Name, args)
emit(agentEvent{
Type: "tool_result",
Data: map[string]any{"name": tc.Function.Name, "result": result, "id": tc.ID},