SDK Reference

Python SDK Reference

Method signatures, parameter schemas, return types, runnable code examples, and framework integrations for the Blocklog Python client.

Method

blocklog.init()

Initialize the global SDK configuration. Call once at application startup.

def init(
    api_key: str | None = None,
    *,
    base_url: str | None = None,
    signing_key: str | None = None,
    timeout: float | None = None,
    max_retries: int | None = None,
    debug: bool = False,
) -> BlocklogClient

Parameters

  • api_key · str, optional

    Key for verification. Falls back to BLOCKLOG_API_KEY.

  • base_url · str, optional

    Custom API endpoint override. Falls back to BLOCKLOG_BASE_URL.

  • signing_key · str, optional

    HMAC-SHA256 key for tamper-evident log signatures. Falls back to BLOCKLOG_SDK_SIGNING_KEY. This is not asymmetric Ed25519 signing.

  • timeout · float, optional

    Request timeout in seconds. Default is 10.

  • max_retries · int, optional

    Ingestion retries. Default is 3.

Example

import blocklog
blocklog.init(api_key="blk_live_xxxx", debug=True)

Decorator

@blocklog.agent

Trace an AI agent function, linking it to a Blocklog session. Handles sync and async functions automatically.

Note — Class decoration only emits AGENT_START. For full lifecycle tracing, decorate the specific method (e.g. run, execute) rather than the class itself.
def agent(
    func: F | None = None,
    *,
    name: str | None = None,
    version: str = "1.0",
    tags: list[str] | None = None,
    metadata: dict[str, Any] | None = None,
) -> F | Callable[[F], F]

Parameters

  • name · str, optional

    Human-readable agent name. Defaults to func.__name__.

  • version · str

    Semver-style version string. Default is "1.0".

  • tags · list[str], optional

    Optional list of string tags.

  • metadata · dict, optional

    Arbitrary extra data attached to the agent session.

Example

@blocklog.agent(name="stock-trader", version="2.0", tags=["prod"])
def run_trading(ticker):
    pass

Decorator

@blocklog.tool

Wrap a helper function or external API call to record it as a TOOL_CALL event. Inherits trace context from the surrounding @agent.

def tool(
    func: F | None = None,
    *,
    name: str | None = None,
    schema: dict[str, Any] | None = None,
    tags: list[str] | None = None,
    metadata: dict[str, Any] | None = None,
) -> F | Callable[[F], F]

Parameters

  • name · str, optional

    Human-readable tool name. Defaults to func.__name__.

  • schema · dict, optional

    Optional dict describing the input schema.

  • tags · list[str], optional

    Optional string tags.

  • metadata · dict, optional

    Arbitrary extra data.

Example

@blocklog.tool(name="fetch-price", tags=["market-data"])
def get_price(ticker):
    return 189.30

Context Manager

blocklog.decision()

Define a block for recording structured inputs, outputs, and review tasks associated with a system choice.

def decision(
    *,
    type: str,
    asset: str | None = None,
    confidence: float | None = None,
    metadata: dict[str, Any] | None = None,
    agent_id: str | None = None,
    trace_id: str | None = None,
) -> Generator[DecisionContext, None, None]

Parameters

  • type · str

    Decision type identifier (e.g. "BUY").

  • asset · str, optional

    Asset this decision is about.

  • confidence · float, optional

    Model confidence score, from 0 to 1.

  • metadata · dict, optional

    Extra structured fields.

  • agent_id · str, optional

    Links this decision to a specific agent session.

  • trace_id · str, optional

    Links this decision to a specific trace.

Returns: DecisionContext

  • record_input(**kwargs)

    Record structured inputs. Returns self.

  • record_output(**kwargs)

    Record structured outputs. Returns self.

  • tag(*tags)

    Attach string labels. Returns self.

  • request_approval(reason, reviewer=None)

    Non-blocking request for human approval. Returns self.

  • verify()

    Verify the decision after the with block has exited. Raises RuntimeError if called before the decision is committed.

Example

with blocklog.decision(type="BUY", asset="AAPL", confidence=0.9) as d:
    d.record_input(price=189.30)
    d.tag("high-conviction")
    d.record_output(order_id="ord_99")

Governance Method

blocklog.approval.request()

Request human review for an action. Triggers webhooks asynchronously.

def request(
    decision_id: str | None = None,
    *,
    reason: str,
    reviewer: str | None = None,
    log_id: str | None = None,
    metadata: dict[str, Any] | None = None,
) -> dict[str, Any]

Parameters

  • decision_id · str, optional

    ID of the decision this approval request relates to.

  • reason · str

    Why human review is needed.

  • reviewer · str, optional

    Email or identifier of the assigned reviewer.

  • log_id · str, optional

    ID of a specific log entry this request relates to, if not tied to a decision.

  • metadata · dict, optional

    Arbitrary extra data.

Example

blocklog.approval.request(
    decision_id="dec_123",
    reason="Price exceeds limits",
    reviewer="cro@company.com"
)
  • Related: blocklog.approval.reject(), escalate(), list_overrides(), and audit_trail() round out the human-in-the-loop workflow.

Forensic Method

blocklog.replay()

Instantiate a session to examine execution traces, staleness heatmaps, and counterfactual outcomes.

def replay(
    trace_id: str,
    *,
    token_id: str | None = None,
    metadata: dict[str, Any] | None = None,
) -> ReplaySession

Parameters

  • trace_id · str

    Trace ID to replay.

  • token_id · str, optional

    Restrict the replay to a specific token within the trace.

  • metadata · dict, optional

    Extra context attached to the replay session.

Example

session = blocklog.replay("trace-uuid")
cause = session.root_cause()
print(cause["description"])

Verification Method

blocklog.verify.log()

Confirm a single log entry has not been tampered with since creation.

def log(log_id: str) -> dict[str, Any]

Parameters

  • log_id · str

    ID of the log entry to verify.

Example

result = blocklog.verify.log("log-uuid")
assert result["status"] == "verified"

Framework instrumentation

Integrations

Built-in instrumentation for LangChain, LangGraph, the OpenAI SDK, and LiteLLM. Each integration wires into the framework’s native execution model and emits structured events to the Blocklog ingest API — covering LLM calls, tool use, chain and graph lifecycle, streaming, and errors.

Common behaviour across all integrations

  • Concurrent run safety — LangChain/LangGraph key state by run_id, LiteLLM by litellm_call_id, and OpenAI by a ContextVar, so nested or parallel runs never clobber each other.
  • Context inheritance — trace_id, session_id, workflow_id, and agent_id are pulled automatically from the active Blocklog context (blocklog.context.vars); no manual threading required.
  • Safe serialization — Pydantic v1 (.dict()) and v2 (.model_dump()) models, plain Python types, and arbitrary objects are all handled; unknown types fall back to str().
  • Error events always fire — on any exception, an errored event is emitted before it propagates, so failures are never silently dropped from your audit trail.

Integration

LangChain

Attach a callback handler to any chain, agent, or LLM to capture chain, model, and tool lifecycle events.

Setup

import blocklog

client = blocklog.init(api_key="blk_...")
handler = client.instrument_langchain()

Usage

chain.invoke(inputs, config={"callbacks": [handler]})

Events emitted

EventCausality typeFired when
agent.chain.startedchain_startA chain begins; includes inputs and input_keys.
agent.chain.completedchain_endA chain finishes successfully; includes outputs.
agent.chain.erroredchain_errorA chain raises an exception.
agent.model.startedllm_startAn LLM call begins; includes serialized model info and prompts.
agent.model.completedllm_endAn LLM call finishes; includes the full response.
agent.model.erroredllm_errorAn LLM call raises an exception.
agent.tool.startedtool_startA tool begins execution; includes the raw input string.
agent.tool.completedtool_endA tool finishes; includes output.
agent.tool.erroredtool_errorA tool raises an exception.
  • Every event carries a span_id (derived from run_id), a parent_run_id for causality linking, and an agent_metadata block with framework, captured_at, and any LangChain-provided metadata.

Integration

LangGraph

Extends the LangChain handler pattern with graph-native event families. Because LangGraph routes both top-level graphs and individual nodes through on_chain_*, the handler inspects the serialized payload to tell them apart and emit the right event.

Setup

import blocklog

client = blocklog.init(api_key="blk_...")
handler = client.instrument_langgraph()

Usage

result = graph.invoke(state, config={"callbacks": [handler]})

# Or via RunnableConfig
from langchain_core.runnables import RunnableConfig
result = graph.invoke(state, config=RunnableConfig(callbacks=[handler]))

Events emitted

Graph lifecycle

EventCausality typeFired when
agent.graph.startedgraph_startThe top-level CompiledGraph begins; includes graph_name, inputs, and input_keys.
agent.graph.completedgraph_endThe graph finishes successfully; includes outputs.
agent.graph.erroredgraph_errorThe graph raises an unhandled exception.

Node lifecycle

EventCausality typeFired when
agent.graph.node.startednode_startA node begins; includes node_name and inputs.
agent.graph.node.completednode_endA node finishes; includes node_name and outputs.
agent.graph.node.errorednode_errorA node raises an exception; includes node_name and error details.

Subgraph lifecycle

EventCausality typeFired when
agent.graph.subgraph.startedsubgraph_startA nested subgraph begins; includes subgraph_name and inputs.
agent.graph.subgraph.completedsubgraph_endA nested subgraph finishes; includes outputs.

Checkpoint lifecycle

EventCausality typeFired when
agent.graph.checkpoint.startedcheckpoint_startLangGraph is about to write a checkpoint; includes thread_id and checkpoint_ns.
agent.graph.checkpoint.completedcheckpoint_endA checkpoint is successfully persisted; includes checkpoint_id, thread_id, and checkpoint_ns.
  • All agent.model.* and agent.tool.* events are also emitted for calls made inside nodes, identical to the LangChain integration.
  • A _node_name_stack keyed by run_id ensures node names are correctly attributed on completion and error callbacks, which LangGraph does not re-supply.
  • State dicts — which often contain Pydantic models — are safely serialized before emission.

Integration

OpenAI SDK

The OpenAI Python SDK has no callback system, so instrumentation works by monkey-patching the create method on the SDK's resource classes directly. Every OpenAI(), AsyncOpenAI(), and AzureOpenAI() instance in the process — including ones already constructed — is instrumented automatically.

Setup

import blocklog

client = blocklog.init(api_key="blk_...")
client.instrument_openai_agents()

Instrument a single instance instead

import openai
from blocklog.integrations.openai_agents import instrument_openai

blocklog_client = blocklog.init(api_key="blk_...")
openai_client = openai.OpenAI(api_key="...")

instrument_openai(blocklog_client, openai_client=openai_client)

Events emitted

EventCausality typeFired when
agent.model.startedllm_startA chat.completions.create or responses.create call begins; includes model, messages, and remaining request parameters.
agent.model.completedllm_endThe call finishes; includes the full response, usage, duration_s, and a streamed flag.
agent.model.erroredllm_errorThe call raises an exception.
  • Streaming is handled transparently for sync and async clients — chunks are re-yielded unmodified, and agent.model.completed fires only once the stream is fully consumed, with deltas merged into one coherent response.
  • Async create methods are wrapped with an async-native path, including async streaming via async for; sync vs. async is detected automatically.
  • A contextvars.ContextVar (blocklog_openai_span_id) propagates span_id across nested or concurrent calls within the same async context.
  • A _blocklog_wrapped sentinel flag makes calling instrument_openai_agents() more than once safe.

Integration

LiteLLM

LiteLLM has a first-class CustomLogger base class. The handler subclasses it and registers via litellm.callbacks — the same pattern every other LiteLLM observability tool uses, with no monkey-patching required.

Setup

import blocklog

client = blocklog.init(api_key="blk_...")
handler = client.instrument_litellm()

Usage

import litellm

# Replace all existing callbacks
litellm.callbacks = [handler]

# Or append alongside existing callbacks
litellm.callbacks += [handler]

Events emitted

EventCausality typeFired when
agent.model.pre_callllm_pre_callBefore the HTTP request is dispatched; includes model, messages, stream, and litellm_call_id.
agent.model.post_callllm_post_callAfter the API responds, before the success/failure split; includes the full request fields, raw response, and duration_s.
agent.model.stream_chunkllm_stream_chunkFor each individual chunk on the sync streaming path; includes model, chunk, and litellm_call_id.
agent.model.completedllm_endA call finishes successfully (sync or async); includes response, usage, response_cost, duration_s, stream, and cache_hit.
agent.model.erroredllm_errorA call fails (sync or async); includes error_type, error_message, and duration_s.
  • span_id is derived from litellm_call_id, stamped onto kwargs by LiteLLM before any hook fires, so pre-call, post-call, and success/failure events for one request share a consistent span ID.
  • usage (prompt_tokens, completion_tokens, total_tokens) and response_cost are promoted to the top level of agent.model.completed payloads.
  • log_success_event / log_failure_event handle sync calls; async_log_success_event / async_log_failure_event handle acompletion and async streaming — both delegate to shared handlers so payloads are identical regardless of mode.
  • Any metadata dict passed via litellm_params is forwarded into the agent_metadata block on every event.