Raxol.Agent.ThreadLogRouter (Raxol Agent v2.6.0)

Copy Markdown View Source

Telemetry handler that routes agent-side events ([:raxol, :agent, :policy, :*] and [:raxol, :agent, :sandbox, :denied]) into a Raxol.Agent.ThreadLog adapter as durable audit entries.

How it works

attach/3 calls :telemetry.attach_many/4 for the agent-side event family, passing the ThreadLog adapter tuple and the agent's thread_id in the handler config. Every matching event is translated into one ThreadLog.append/5 call with kind: :policy_result (for policy events) or kind: :sandbox_deny (for sandbox denials).

Detach via detach/1 (e.g. in the agent's terminate/2).

Wiring

Consumers typically call this at agent startup once agent_module.thread_log/0 resolves to a non-nil adapter:

adapter = Raxol.Agent.ThreadLog.normalize(MyAgent.thread_log())
handler_id = "raxol_agent_thread_log_router_#{agent_id}"
Raxol.Agent.ThreadLogRouter.attach(handler_id, adapter, agent_id)

# ... later, on terminate
Raxol.Agent.ThreadLogRouter.detach(handler_id)

When adapter is nil, attach/3 returns :ok without attaching, so callers don't need to branch.

Event mapping

Telemetry eventThreadLog kindPayload
[:raxol, :agent, :policy, :cache_hit]:policy_result%{policy: :cache, decision: :hit, key, params}
[:raxol, :agent, :policy, :cache_miss]:policy_result%{policy: :cache, decision: :miss, key, params}
[:raxol, :agent, :policy, :retry_attempt]:policy_result%{policy: :retry, decision: :attempt, attempt, reason, backoff_ms}
[:raxol, :agent, :policy, :retry_exhausted]:policy_result%{policy: :retry, decision: :exhausted, attempt, reason}
[:raxol, :agent, :policy, :timeout]:policy_result%{policy: :timeout, decision: :fired, wall_ms}
[:raxol, :agent, :policy, :applied]:policy_result%{policy: :applied, policy_kinds, outcome}
[:raxol, :agent, :sandbox, :denied]:sandbox_deny%{action, reason}

All payloads include a metadata map mirroring the telemetry event's metadata (minus agent_id/agent_module which are redundant with the thread_id).

Summary

Functions

Attach a telemetry handler that routes agent-side events to the given ThreadLog adapter under thread_id.

Detach a previously-attached handler. Idempotent.

Functions

attach(handler_id, adapter, thread_id)

@spec attach(
  binary(),
  Raxol.Agent.ThreadLog.config()
  | {module(), Raxol.Agent.ThreadLog.config()}
  | nil,
  binary()
) :: :ok | {:error, term()}

Attach a telemetry handler that routes agent-side events to the given ThreadLog adapter under thread_id.

adapter is the {module, config} tuple (or bare module) as returned by Raxol.Agent.ThreadLog.normalize/1. Pass nil to no-op (useful when the agent declares no thread_log/0).

Returns :ok on success or when adapter is nil. Returns {:error, :already_exists} if handler_id is already attached.

detach(handler_id)

@spec detach(binary()) :: :ok

Detach a previously-attached handler. Idempotent.