calute.audit.events#
Typed audit event definitions for structured event export.
This module defines a hierarchy of dataclass-based audit events that capture
every significant decision and transition in a Calute agent run. All events
inherit from AuditEvent and are fully JSON-serializable via their
AuditEvent.to_dict() and AuditEvent.to_json() methods.
The event taxonomy covers the following domains:
Turn lifecycle –
TurnStartEvent,TurnEndEventTool execution –
ToolCallAttemptEvent,ToolCallCompleteEvent,ToolCallFailureEventPolicy & security –
ToolPolicyDecisionEvent,SandboxDecisionEventLoop detection –
ToolLoopWarningEvent,ToolLoopBlockEventHook introspection –
HookMutationEventGeneral errors –
ErrorEvent
Example
Creating and serializing a tool-call event:
event = ToolCallAttemptEvent(
tool_name="web_search",
arguments_preview='{"query": "calute docs"}',
agent_id="agent-1",
turn_id="abc123",
)
print(event.to_json())
- class calute.audit.events.AuditEvent(event_type: str = 'base', timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>)[source]#
Bases:
objectBase audit event carrying the common metadata envelope.
Every audit event in the Calute audit system inherits from this dataclass. It provides the shared envelope fields (timestamps, IDs, severity) and the serialization helpers that collectors rely on.
Subclasses should not override
event_typevia__init__; instead they declare it as afield(default=..., init=False)so that the type tag is automatically set and immutable.- event_type#
A short string tag identifying the event kind (e.g.
"turn_start","tool_call_attempt").- Type
str
- timestamp#
ISO-8601 UTC timestamp captured at construction time.
- Type
str
- agent_id#
Optional identifier of the agent that produced the event.
- Type
str | None
- turn_id#
Optional identifier of the conversational turn.
- Type
str | None
- session_id#
Optional session-level identifier, typically stamped by the
AuditEmitter.- Type
str | None
- severity#
Log-style severity level. One of
"info","warning", or"error".- Type
str
- metadata#
Free-form dictionary for attaching additional context that does not warrant its own field.
- Type
dict[str, Any]
Example
Constructing a bare base event:
event = AuditEvent(agent_id="agent-1", severity="warning") payload = event.to_dict() assert payload["event_type"] == "base"
- agent_id: str | None = None#
- event_type: str = 'base'#
- metadata: dict[str, Any]#
- session_id: str | None = None#
- severity: str = 'info'#
- timestamp: str#
- to_dict() dict[str, Any][source]#
Serialize the event to a plain dictionary.
Converts the entire dataclass tree (including nested dataclasses) into a dictionary of primitive types suitable for JSON encoding.
- Returns
- A recursively-unwrapped dictionary of all
fields and their values.
- Return type
dict[str, Any]
- to_json() str[source]#
Serialize the event to a compact JSON string.
Non-serializable values (e.g.
datetimeobjects stored inmetadata) are coerced to strings via thedefault=strfallback.- Returns
A single-line JSON representation of the event.
- Return type
str
- turn_id: str | None = None#
- class calute.audit.events.ErrorEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'error', metadata: dict[str, typing.Any] = <factory>, error_type: str = '', error_message: str = '', error_context: str = '')[source]#
Bases:
AuditEventEmitted for generic errors not tied to a specific tool call.
Use this event type for infrastructure-level or agent-level errors that cannot be attributed to a single tool invocation (e.g. LLM API failures, serialization errors, or unexpected state transitions). For tool-specific failures, prefer
ToolCallFailureEvent.- event_type#
Fixed to
"error"(not settable via init).- Type
str
- severity#
Defaults to
"error"(overrides the base"info").- Type
str
- error_type#
A short classifier for the error, typically the exception class name (e.g.
"RuntimeError").- Type
str
- error_message#
The human-readable error description or the stringified exception message.
- Type
str
- error_context#
Additional context about where or why the error occurred (e.g.
"during response parsing").- Type
str
Example
event = ErrorEvent( error_type="TimeoutError", error_message="LLM request timed out after 30s", error_context="during turn execution", agent_id="agent-1", )
- error_context: str = ''#
- error_message: str = ''#
- error_type: str = ''#
- event_type: str = 'error'#
- severity: str = 'error'#
- class calute.audit.events.HookMutationEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, hook_name: str = '', tool_name: str = '', mutated_field: str = '')[source]#
Bases:
AuditEventEmitted when a hook mutates a tool call or its result.
Hooks can intercept tool calls before execution (pre-hooks) or modify results after execution (post-hooks). This event records which hook altered which field, providing an audit trail for any data transformations applied outside the tool’s own logic.
- event_type#
Fixed to
"hook_mutation"(not settable via init).- Type
str
- hook_name#
The identifier of the hook that performed the mutation (e.g.
"sanitize_output","inject_context").- Type
str
- tool_name#
The registered name of the tool whose call or result was mutated.
- Type
str
- mutated_field#
The specific field that was changed (e.g.
"arguments","result").- Type
str
Example
event = HookMutationEvent( hook_name="sanitize_output", tool_name="shell_exec", mutated_field="result", agent_id="agent-1", )
- event_type: str = 'hook_mutation'#
- hook_name: str = ''#
- mutated_field: str = ''#
- tool_name: str = ''#
- class calute.audit.events.SandboxDecisionEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', context: str = '', reason: str = '', backend_type: str = '')[source]#
Bases:
AuditEventEmitted when the sandbox router selects an execution backend.
The sandbox router inspects the tool call and its context to decide which isolation backend (e.g. local, Docker, subprocess jail) should execute the call. This event captures that routing decision.
- event_type#
Fixed to
"sandbox_decision"(not settable via init).- Type
str
- tool_name#
The registered name of the tool being routed.
- Type
str
- context#
A short description of the execution context that influenced the routing decision.
- Type
str
- reason#
A human-readable explanation of why the particular backend was selected.
- Type
str
- backend_type#
The identifier of the chosen sandbox backend (e.g.
"local","docker","subprocess").- Type
str
Example
event = SandboxDecisionEvent( tool_name="shell_exec", context="untrusted_input", reason="Input contains user-supplied shell commands", backend_type="docker", )
- backend_type: str = ''#
- context: str = ''#
- event_type: str = 'sandbox_decision'#
- reason: str = ''#
- tool_name: str = ''#
- class calute.audit.events.ToolCallAttemptEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', arguments_preview: str = '')[source]#
Bases:
AuditEventEmitted just before a tool call is dispatched to its executor.
This event is created before the tool actually runs, making it useful for pre-execution auditing and for correlating with the subsequent
ToolCallCompleteEventorToolCallFailureEvent.- event_type#
Fixed to
"tool_call_attempt"(not settable via init).- Type
str
- tool_name#
The registered name of the tool being invoked.
- Type
str
- arguments_preview#
A truncated (up to 200 characters) string representation of the arguments passed to the tool.
- Type
str
Example
event = ToolCallAttemptEvent( tool_name="web_search", arguments_preview='{"query": "Python dataclasses"}', agent_id="agent-1", )
- arguments_preview: str = ''#
- event_type: str = 'tool_call_attempt'#
- tool_name: str = ''#
- class calute.audit.events.ToolCallCompleteEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', status: str = 'success', duration_ms: float = 0.0, result_preview: str = '')[source]#
Bases:
AuditEventEmitted when a tool call completes successfully.
Captures the outcome of a successful tool invocation, including its wall-clock duration and a truncated preview of the result payload.
- event_type#
Fixed to
"tool_call_complete"(not settable via init).- Type
str
- tool_name#
The registered name of the tool that was invoked.
- Type
str
- status#
Completion status string, typically
"success".- Type
str
- duration_ms#
Wall-clock execution time in milliseconds.
- Type
float
- result_preview#
A truncated (up to 200 characters) string representation of the tool’s return value.
- Type
str
Example
event = ToolCallCompleteEvent( tool_name="web_search", status="success", duration_ms=142.5, result_preview="Found 10 results for ...", )
- duration_ms: float = 0.0#
- event_type: str = 'tool_call_complete'#
- result_preview: str = ''#
- status: str = 'success'#
- tool_name: str = ''#
- class calute.audit.events.ToolCallFailureEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'error', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', error_type: str = '', error_message: str = '')[source]#
Bases:
AuditEventEmitted when a tool call raises an exception or otherwise fails.
The event automatically sets
severityto"error"to ensure failures are prominently surfaced in any downstream log consumer.- event_type#
Fixed to
"tool_call_failure"(not settable via init).- Type
str
- severity#
Defaults to
"error"(overrides the base"info").- Type
str
- tool_name#
The registered name of the tool that failed.
- Type
str
- error_type#
A short classifier for the error, typically the exception class name (e.g.
"ValueError").- Type
str
- error_message#
The human-readable error description or the stringified exception message.
- Type
str
Example
event = ToolCallFailureEvent( tool_name="file_read", error_type="FileNotFoundError", error_message="/tmp/missing.txt not found", agent_id="agent-1", )
- error_message: str = ''#
- error_type: str = ''#
- event_type: str = 'tool_call_failure'#
- severity: str = 'error'#
- tool_name: str = ''#
- class calute.audit.events.ToolLoopBlockEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'error', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', pattern: str = '', call_count: int = 0)[source]#
Bases:
AuditEventEmitted when a tool-call loop triggers a hard block.
Unlike
ToolLoopWarningEvent, this event indicates that the loop detector has prevented the tool call from executing. Theseverityis automatically set to"error".- event_type#
Fixed to
"tool_loop_block"(not settable via init).- Type
str
- severity#
Defaults to
"error"(overrides the base"info").- Type
str
- tool_name#
The registered name of the tool that was blocked.
- Type
str
- pattern#
A short description of the repetitive pattern that triggered the block (e.g.
"same_args_5x").- Type
str
- call_count#
The number of consecutive or recent calls that matched the loop pattern before the block was imposed.
- Type
int
Example
event = ToolLoopBlockEvent( tool_name="web_search", pattern="same_args_5x", call_count=5, )
- call_count: int = 0#
- event_type: str = 'tool_loop_block'#
- pattern: str = ''#
- severity: str = 'error'#
- tool_name: str = ''#
- class calute.audit.events.ToolLoopWarningEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'warning', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', pattern: str = '', severity_level: str = '', call_count: int = 0)[source]#
Bases:
AuditEventEmitted when the loop detector identifies a potential tool-call loop.
This is a soft warning – the tool call is still allowed to proceed, but downstream consumers (dashboards, logs) are alerted that the agent may be stuck in a repetitive pattern.
- event_type#
Fixed to
"tool_loop_warning"(not settable via init).- Type
str
- severity#
Defaults to
"warning"(overrides the base"info").- Type
str
- tool_name#
The registered name of the tool involved in the suspected loop.
- Type
str
- pattern#
A short description of the repetitive pattern that was detected (e.g.
"same_args_3x").- Type
str
- severity_level#
An additional severity qualifier supplied by the loop detector (e.g.
"warning","critical").- Type
str
- call_count#
The number of consecutive or recent calls that matched the loop pattern.
- Type
int
Example
event = ToolLoopWarningEvent( tool_name="web_search", pattern="same_args_3x", severity_level="warning", call_count=3, )
- call_count: int = 0#
- event_type: str = 'tool_loop_warning'#
- pattern: str = ''#
- severity: str = 'warning'#
- severity_level: str = ''#
- tool_name: str = ''#
- class calute.audit.events.ToolPolicyDecisionEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, tool_name: str = '', action: str = '', policy_source: str = '')[source]#
Bases:
AuditEventEmitted when the policy engine makes an allow/deny decision.
Records the outcome of the tool-policy evaluation step that occurs before a tool call is dispatched. This is critical for auditing which policy rules allowed or blocked a given tool invocation.
- event_type#
Fixed to
"tool_policy_decision"(not settable via init).- Type
str
- tool_name#
The registered name of the tool under evaluation.
- Type
str
- action#
The policy verdict, typically
"allow"or"deny".- Type
str
- policy_source#
An identifier for the policy rule or configuration file that produced the decision (e.g.
"default_policy"or"operator_override").- Type
str
Example
event = ToolPolicyDecisionEvent( tool_name="shell_exec", action="deny", policy_source="operator_override", agent_id="agent-1", )
- action: str = ''#
- event_type: str = 'tool_policy_decision'#
- policy_source: str = ''#
- tool_name: str = ''#
- class calute.audit.events.TurnEndEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, content_preview: str = '', function_calls_count: int = 0)[source]#
Bases:
AuditEventEmitted when an agent turn finishes.
Records the outcome of a completed turn, including a truncated preview of the assistant’s response and the total number of function calls that were executed during the turn.
- event_type#
Fixed to
"turn_end"(not settable via init).- Type
str
- content_preview#
The first portion (up to 200 characters) of the assistant’s response content. May be empty when no textual content was produced.
- Type
str
- function_calls_count#
The total number of tool / function calls that were dispatched during this turn.
- Type
int
Example
event = TurnEndEvent( agent_id="agent-1", turn_id="t-001", content_preview="The report shows ...", function_calls_count=3, )
- content_preview: str = ''#
- event_type: str = 'turn_end'#
- function_calls_count: int = 0#
- class calute.audit.events.TurnStartEvent(timestamp: str = <factory>, agent_id: str | None = None, turn_id: str | None = None, session_id: str | None = None, severity: str = 'info', metadata: dict[str, typing.Any] = <factory>, prompt_preview: str = '')[source]#
Bases:
AuditEventEmitted when a new agent turn begins.
Captures the opening of a conversational turn, including a truncated preview of the user prompt that initiated it.
- event_type#
Fixed to
"turn_start"(not settable via init).- Type
str
- prompt_preview#
The first portion (up to 200 characters) of the user prompt that triggered this turn. May be empty if no prompt text was available.
- Type
str
Example
event = TurnStartEvent( agent_id="agent-1", turn_id="t-001", prompt_preview="Summarize the latest report", )
- event_type: str = 'turn_start'#
- prompt_preview: str = ''#