SDK Reference

TypeScript SDK Reference

Constructor and configuration, event and lifecycle methods, decorators, tracing, governance, forensic, and verification methods, plus framework integrations for the Blocklog TypeScript client.

Constructor

new BlocklogClient()

The main entry point and orchestration layer. Coordinates configuration, tracing, the event pipeline, queues, and transport — while keeping minimal business logic of its own.

new BlocklogClient(
  config: BlocklogConfig,
  dependencies?: ClientDependencies
)

Parameters

  • config · BlocklogConfig

    Configuration object. See BlocklogConfig below.

  • dependencies · ClientDependencies, optional

    Dependency injection overrides — transport, retry, buffer, processor, memoryQueue, persistentQueue, deadLetterQueue. Mainly used for testing.

Key client properties

  • decisions: DecisionsClient

    Create, get, list, search, update, and verify decision records.

  • traces: TracesClient

    Retrieve traces and trace timelines.

  • approvals: ApprovalClient

    Human-in-the-loop approval workflows. Aliased as client.hitl.

  • incidents: IncidentsClient

    Create, update, assign, resolve, and close incidents.

  • compliance: ComplianceClient

    Generate audits, dashboards, and exportable evidence.

  • replay: ReplayClient

    Reconstruct, verify, replay, and compare traces. Aliased as client.forensics.

  • traceManager: typeof TraceManager

    Static span-management class — see TraceManager below.

Example

const client = new BlocklogClient({
  apiKey: 'your-api-key',
  endpoint: 'base_url',
  batchSize: 100,
  flushInterval: 5000
});

Type

BlocklogConfig

The configuration object passed to the BlocklogClient constructor. Resolved into a ResolvedConfig internally, with environment-variable fallbacks and defaults applied.

interface BlocklogConfig {
  apiKey: string;
  endpoint?: string;
  batchSize?: number;
  flushInterval?: number;
  timeout?: number;
  retryCount?: number;
  enableSigning?: boolean;
  signingKey?: string;
  signingAlg?: 'hmac-sha256' | 'ed25519';
  enableCompression?: boolean;
  debug?: boolean;
}

Fields

  • apiKey · string

    Required. Your Blocklog API key.

  • endpoint · string, optional

    Override the default API base URL.

  • batchSize · number, optional

    Events per batch flush. Default is 100.

  • flushInterval · number, optional

    Milliseconds between automatic flushes.

  • timeout · number, optional

    Per-request timeout in milliseconds.

  • retryCount · number, optional

    Automatic retry attempts on failure.

  • enableSigning · boolean, optional

    Turn on tamper-evident event signing.

  • signingKey · string, optional

    Key used for signing, when enableSigning is true.

  • signingAlg · 'hmac-sha256' | 'ed25519', optional

    Signing algorithm. Defaults to hmac-sha256.

  • enableCompression · boolean, optional

    Compress event payloads before sending.

  • debug · boolean, optional

    Log every outbound request to stderr.

Example

const client = new BlocklogClient({
  apiKey: process.env.BLOCKLOG_API_KEY!,
  enableSigning: true,
  signingAlg: 'hmac-sha256',
  debug: process.env.NODE_ENV !== 'production'
});

Event Methods

client.event() / client.enqueue()

Send a single event immediately with event(), or buffer it for batched delivery with enqueue(). Both take the same arguments — enqueue() simply resolves to null while the event sits in the buffer.

event(eventType: string, payload: any, options?: EventOptions): Promise<IngestResponse>
enqueue(eventType: string, payload: any, options?: EventOptions): Promise<IngestResponse | null>

Parameters

  • eventType · string

    Event type identifier, e.g. "AGENT_RUN" or "TOOL_CALL".

  • payload · any

    Event payload data. Must be serializable.

  • options · EventOptions, optional

    metadata, trace_id, span_id, and timestamp overrides.

Example

await client.event('AGENT_RUN', {
  agent_id: 'my-agent',
  input: 'test input',
  output: 'test output'
});

await client.enqueue('TOOL_CALL', {
  tool_name: 'calculator',
  input: '2 + 2',
  output: '4'
});

Middleware Method

client.addHook()

Register a middleware hook that can transform, enrich, validate, or filter every outbound event. Hooks run in the order they were added and may be async.

addHook(hook: MiddlewareHook): BlocklogClient

type MiddlewareHook = (event: EventEnvelope) => EventEnvelope | Promise<EventEnvelope> | null

Parameters

  • hook · MiddlewareHook

    Receives an EventEnvelope and returns a (possibly modified) envelope, or null to drop the event entirely.

Example

client.addHook((event) => {
  event.metadata = { ...event.metadata, enriched: true };
  return event;
});
  • Returning null from a hook skips the event entirely — useful for filtering debug events in production.
  • addHook() returns the client itself, so calls can be chained.

Lifecycle

client.flush() / shutdown() / health()

Manage the client's buffered events and background resources.

flush(): Promise<IngestResponse>
shutdown(): Promise<void>
health(): Promise<HealthStatus>

What each call does

  • flush()

    Flushes the pipeline, buffer, and queues, then awaits transport completion.

  • shutdown()

    Flushes everything, persists the queue, stops timers, and closes transports to prevent event loss.

  • health()

    Returns { healthy, queueDepth, pendingEvents, transportReady } for monitoring.

Example

await client.flush();

const health = await client.health();
console.log(health);
// { healthy: true, queueDepth: 0, pendingEvents: 0, transportReady: true }

await client.shutdown();

Decorator

@traceAgent

Trace an AI agent method automatically, emitting AGENT_START, AGENT_COMPLETE, and AGENT_ERROR events with input/output, duration, and trace context.

Note — Decorators read from the global client, not an instance you pass in directly — call setGlobalClient() before any @traceAgent method runs.
function traceAgent(options: AgentOptions | string)

Parameters

  • options · AgentOptions | string

    An agent name string, or an options object: { name, version, tags, metadata }.

Example

class WeatherAgent {
  @traceAgent('weather-agent')
  async getWeather(location: string): Promise<string> {
    const response = await fetch(`https://api.weather.com/${location}`);
    return (await response.json()).weather;
  }
}
  • Trace context (trace ID, span ID, parent span ID) propagates automatically to nested @traceAgent calls.
  • On error, AGENT_ERROR is emitted with the error details before it propagates to the caller.

Method

executeAgent()

Trace an agent execution without a decorator — useful for functional code or one-off calls.

function executeAgent<T>(
  agentId: string,
  fn: () => Promise<T>,
  options?: AgentOptions
): Promise<T>

Parameters

  • agentId · string

    Agent identifier.

  • fn · () => Promise<T>

    Function to execute and trace.

  • options · AgentOptions, optional

    version, tags, metadata.

Example

const result = await executeAgent(
  'my-agent',
  async () => 'agent result',
  { version: '1.0', tags: ['test'], metadata: { custom: 'value' } }
);

Tracing

TraceManager

Static class managing span lifecycle and context propagation across async operations, via Async Local Storage.

class TraceManager {
  static startSpan(name: string, options?: SpanOptions): Span
  static endSpan(span: Span | string, status?: string): void
  static currentSpan(): Span | undefined
  static parentSpan(): Span | undefined
  static runWithSpan<T>(span: Span, fn: () => Promise<T>): Promise<T>
}

Static methods

  • startSpan(name, options?)

    Creates and starts a new span, storing it in Async Local Storage.

  • endSpan(span, status?)

    Finalizes a span, optionally recording a status such as "success" or "error".

  • currentSpan()

    Returns the active span for the current async context, if any.

  • parentSpan()

    Returns the parent of the active span, if any.

  • runWithSpan(span, fn)

    Runs fn() with span set as the active context for any nested operations.

Example

const span = TraceManager.startSpan('my-operation');
const result = await TraceManager.runWithSpan(span, async () => {
  return 'result';
});
TraceManager.endSpan(span, 'success');
  • Spans propagate automatically across await boundaries — no manual threading of IDs required.
  • Always end a span, ideally in a finally block, so it isn't left open if the wrapped code throws.

Governance Method

client.approvals.create()

Request human review for a decision. Part of the ApprovalClient, which also exposes approve(), reject(), status(), and list(). Aliased as client.hitl.

client.approvals.create(data: Record<string, any>): Promise<any>
client.approvals.approve(id: string, reason?: string): Promise<any>
client.approvals.reject(id: string, reason?: string): Promise<any>
client.approvals.status(id: string): Promise<any>
client.approvals.list(params?: Record<string, any>): Promise<any>

Parameters

  • decisionId · string

    ID of the decision this approval request relates to.

  • reason · string

    Why human review is needed.

  • metadata · Record<string, any>, optional

    Extra context, e.g. required_approver, expires_at, approval_level.

Example

const approval = await client.approvals.create({
  decisionId: 'decision-123',
  reason: 'High value trade requires approval'
});

await client.approvals.approve(approval.id, 'Approved based on risk analysis');
const status = await client.approvals.status(approval.id);
  • Approval requests resolve to a status of "pending", "approved", or "rejected".

Forensic Method

client.replay.reconstruct()

Reconstruct a trace for debugging and analysis. Part of the ReplayClient, which also exposes verify(), replay(), get(), list(), and compare(). Aliased as client.forensics.

client.replay.reconstruct(traceId: string, options?: Record<string, any>): Promise<any>
client.replay.verify(id: string): Promise<any>
client.replay.replay(id: string, options?: Record<string, any>): Promise<any>
client.replay.compare(idA: string, idB: string): Promise<any>

Parameters

  • traceId · string

    Trace to reconstruct.

  • options · Record<string, any>, optional

    include_tool_calls, include_decisions, include_timeline, and similar flags.

Example

const reconstruction = await client.replay.reconstruct('trace-123', {
  include_tool_calls: true,
  include_decisions: true
});

const result = await client.replay.replay(reconstruction.replay_id, {
  speed: 2,
  stop_on_error: false
});
  • compare(idA, idB) returns { identical, differences, similarity_score } for A/B debugging two executions.

Verification Method

client.decisions.verify()

Confirm a decision record's integrity and that it hasn't been tampered with since creation.

client.decisions.verify(id: string): Promise<any>

Parameters

  • id · string

    Decision ID to verify.

Example

const verification = await client.decisions.verify('decision-123');

if (verification.valid) {
  console.log('Decision is valid');
} else {
  console.log('Decision verification failed:', verification.reason);
}

Framework instrumentation

Integrations

Native instrumentation for LangChain, LangGraph, and OpenAI Agents. Each integration wires into the framework’s callback or hook system to trace chains, nodes, tools, and LLM calls automatically, with manual hooks available for anything outside the automatic path.

Common behaviour across all integrations

  • All instrument*() functions read configuration from the global client — call setGlobalClient() before instrumenting.
  • Trace context (trace ID, span ID, parent span ID) is preserved across async operations via Async Local Storage, the same mechanism TraceManager itself uses.
  • Errors are always traced — automatic instrumentation captures exceptions before they propagate, and manual hooks expose explicit onError / handle*Error methods for the same purpose.
  • Each integration also accepts a custom callback handler class for frameworks that support pluggable callbacks, letting you forward lifecycle events to the tracer or hooks object yourself.

Integration

LangChain

Wraps LangChain's callback system to trace chains, tools, LLM calls, and agents.

Setup

import { BlocklogClient, setGlobalClient, instrumentLangChain } from '@blocklog/sdk';

const client = new BlocklogClient({ apiKey: 'your-api-key' });
setGlobalClient(client);

const tracer = instrumentLangChain();

Automatic tracing

import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';

const agent = await createOpenAIFunctionsAgent(llm, tools, prompt);
const executor = new AgentExecutor({ agent, tools, verbose: true });

// Execution is automatically traced
const result = await executor.invoke({ input: 'What is the weather?' });

Manual tracing hooks

For cases the automatic instrumentation doesn’t cover, call the corresponding hook directly.

MethodUse it to…
handleChainStart(chain, inputs, runId)Mark a chain's start. chain is { name, metadata? }.
handleChainEnd(outputs, runId)Mark a chain's successful completion.
handleToolStart(tool, input, runId)Mark a tool call's start.
handleToolEnd(output, runId)Mark a tool call's completion.
handleLLMStart(llm, prompts, runId)Mark an LLM call's start.
handleLLMEnd(output, runId)Mark an LLM call's completion.
  • For deeper control, subclass BaseCallbackHandler and forward each callback to the matching tracer.handle*() method.
  • Set the global client with setGlobalClient() before calling instrumentLangChain() — the tracer reads from the global client.

Integration

LangGraph

Extends the same hook pattern to LangGraph's node, edge, and graph lifecycle.

Setup

import { BlocklogClient, setGlobalClient, instrumentLangGraph } from '@blocklog/sdk';

const client = new BlocklogClient({ apiKey: 'your-api-key' });
setGlobalClient(client);

const hooks = instrumentLangGraph();

Automatic tracing

const compiledGraph = graph.compile();

// Node, edge, and graph execution are automatically traced
const result = await compiledGraph.invoke({ input: 'test input' });

Manual tracing hooks

For cases the automatic instrumentation doesn’t cover, call the corresponding hook directly.

MethodUse it to…
onGraphStart({ graph_id, metadata? })Mark the start of a graph run.
onGraphEnd({ graph_id })Mark the end of a graph run.
onNodeStart(nodeName, state, runId)Mark a node's start, including the state it received.
onNodeEnd(nodeName, state, runId)Mark a node's completion, including the state it produced.
onEdge(from, to, condition, runId)Mark an edge transition, including whether it matched a condition.
  • Conditional edges added via addConditionalEdges() are traced the same way as static edges.
  • State objects passed to onNodeStart / onNodeEnd are recorded as-is, so keep them serializable.

Integration

OpenAI Agents

Traces OpenAI chat completion calls, tool and function calls, and the messages exchanged during an agent run.

Setup

import { BlocklogClient, setGlobalClient, instrumentOpenAIAgents } from '@blocklog/sdk';

const client = new BlocklogClient({ apiKey: 'your-api-key' });
setGlobalClient(client);

const hooks = instrumentOpenAIAgents();

Automatic tracing

import { OpenAI } from 'openai';

const openai = new OpenAI({ apiKey: 'your-openai-key' });

// Chat completions, tool calls, and messages are automatically traced
const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: 'Hello' }]
});

Manual tracing hooks

For cases the automatic instrumentation doesn’t cover, call the corresponding hook directly.

MethodUse it to…
onAgentRunStart(agentId, input)Mark the start of an agent run.
onAgentRunEnd(agentId, output)Mark an agent run's successful completion.
onAgentRunError(agentId, error)Mark an agent run's failure.
onToolCall(toolName, args)Record a tool call's name and arguments.
onFunctionCall(name, args)Record a legacy function-calling invocation.
onMessage(role, content)Record a message exchanged during the run — user, assistant, or system.
  • Call onAgentRunError() inside a catch block and re-throw, so failures are traced without being swallowed.
  • Metadata such as user_id, session_id, or environment can be passed alongside input on onAgentRunStart().