Quickstart
Install the published package:
Create a logger with a JSONL path and record one workflow run:
from agentlogsafe import AgentLogger
log = AgentLogger(
agent_name="pricing-agent",
workflow_name="margin-risk-review",
sink="agent_events.jsonl",
)
with log.run(input={"request": "Find margin risks in this forecast"}):
log.user_message("Find margin risks in this forecast")
log.model_call(
provider="azure_openai",
model="gpt-4.1",
input_tokens=812,
output_tokens=132,
payload={"prompt": "Find margin risks in this forecast"},
)
log.tool_call(
tool_name="snowflake.query",
args={
"sql": "select * from customer_margin where email = 'person@example.com'",
"authorization": "Bearer abc.def.ghi",
},
)
log.tool_result(
tool_name="snowflake.query",
result={"rows": 20, "sample_email": "person@example.com"},
)
log.policy_check(
policy_name="pii-redaction",
status="success",
payload={"contains_pii": True},
)
log.decision(
decision="Escalated because margin impact exceeded threshold",
requires_human_review=True,
)
A path automatically creates an append-only JSONLSink. The email addresses and
authorization value are redacted before writing:
{"schema_version":"1.0","event_type":"tool_call","tool_name":"snowflake.query","payload":{"args":{"sql":"select * from customer_margin where email = '[REDACTED]'","authorization":"[REDACTED]"}}}
Actual records also include event and run IDs, UTC timestamps, workflow context, status, risk, and metadata.
Trace a Python tool
@log.trace_tool("snowflake.query")
def run_query(sql: str):
return {"rows": 20}
result = run_query("select * from customer_margin")
The decorator emits tool_call, then tool_result or error, and preserves the
function's return value and metadata.
Trace a model call
with log.trace_model_call(
provider="azure_openai",
model="gpt-4.1",
payload={"prompt": "Find margin risks"},
) as trace:
response = client.responses.create(...)
trace.set_response({"response_id": response.id})
The context emits model_call immediately. Calling set_response adds a correlated
model_response; an exception adds error and is re-raised.
In-memory use
For tests and notebooks, retain events without writing a file:
from agentlogsafe import AgentLogger, MemorySink
sink = MemorySink()
log = AgentLogger(sink=sink)
log.user_message("hello")
assert sink.events[0].event_type == "user_message"
Omitting a sink uses NullSink: events are constructed and returned but discarded.