Skip to Content
GuidesAdapter Authoring
💡
Quick overview

Adapter Authoring

Adapter Authoring is for teams integrating frameworks that VeriProof does not support out of the box. Instead of adding manual SDK calls throughout your application, you can hook into the framework lifecycle and let the adapter open, record, and close sessions automatically.

Use this when you want consistent instrumentation across a custom runtime, middleware layer, or internal AI platform without duplicating session logic in every service.

Adapter Authoring

VeriProof ships built-in adapters for popular frameworks across Python (LangGraph, CrewAI, OpenAI Agents SDK, LlamaIndex, Pydantic AI, Google ADK, Anthropic), TypeScript (Vercel AI SDK, LangChain.js, LlamaIndex.TS, Next.js, Express, Fastify, Anthropic, OpenAI Agents SDK), and .NET (Semantic Kernel, AutoGen). See the SDK overview for the full list. If your framework is not covered, you can author a custom adapter that integrates VeriProof session recording directly into your framework’s execution lifecycle — so every model call, tool invocation, and agent delegation is captured automatically without manual annotation in application code.

Custom adapters are framework middleware, not VeriProof product extensions. They use the same public SDK API as manual instrumentation — they simply call it automatically on behalf of the application developer.


Adapter Architecture

An adapter intercepts the AI framework’s execution at a framework-specific extension point (middleware, hook, event, or decorator), then calls the VeriProof SDK to:

  1. Open a VeriproofSession at the start of an AI interaction
  2. Record individual steps (LLM calls, tool calls, guardrail events) as they occur
  3. Set top-level governance annotations (decision outcome, risk level, intent) either from framework signals or based on configuration
  4. Close the session when the interaction completes

The adapter is registered with the framework once during application startup — application code then requires no VeriProof imports.


Implementing an Adapter

from opentelemetry import trace from veriproof_sdk.enums import StepType class MyFrameworkAdapter: """VeriProof adapter for MyFramework.""" def __init__(self, tracer_name: str = "MyFrameworkAdapter"): self._tracer = trace.get_tracer(tracer_name) def register(self, framework_instance): framework_instance.on_before_invoke(self._on_before_invoke) framework_instance.on_after_invoke(self._on_after_invoke) framework_instance.on_tool_call(self._on_tool_call) def _on_before_invoke(self, context): span = self._tracer.start_span(context.request_id) span.set_attribute("veriproof.session.id", context.request_id) context._vp_span = span context._vp_token = trace.use_span(span, end_on_exit=False).__enter__() def _on_after_invoke(self, context, result): span = context._vp_span # Record the LLM step as a child span with self._tracer.start_as_current_span("llm-call") as step: step.set_attribute("gen_ai.system", result.provider) step.set_attribute("gen_ai.request.model", result.model) step.set_attribute("veriproof.step.type", StepType.LLM_CALL.value) # Set top-level governance annotations span.set_attribute("veriproof.decision", result.decision) span.set_attribute("veriproof.risk.level", self._compute_risk(result)) span.end() def _on_tool_call(self, context, tool_name, tool_result): with self._tracer.start_as_current_span(f"tool:{tool_name}") as step: step.set_attribute("veriproof.step.type", StepType.TOOL_CALL.value) step.set_attribute("gen_ai.tool.name", tool_name)

Required Adapter Behaviors

Every adapter must implement these behaviors to pass the adapter test suite:

Session lifecycle management

Open exactly one session per top-level AI interaction. Close the session — even on error — to prevent orphaned sessions from accumulating. Use try/finally or equivalent to guarantee close on exception paths.

Step recording completeness

Record every LLM call, tool call, and agent delegation as a step. Missing steps result in incomplete governance timelines and may cause low governance scores.

Error resilience

SDK calls must not throw exceptions that propagate into application code. Wrap all SDK calls in try/catch. If the VeriProof ingest endpoint is unreachable, the circuit breaker handles buffering — your adapter should not implement its own retry logic.

Thread and concurrency safety

If the framework executes steps concurrently (parallel tool calls, fan-out agents), associate each step with the correct session. Use the span handle stored in the framework context directly rather than via a global or thread-local.


Testing Your Adapter

To test your adapter without sending data to VeriProof’s ingest API, pass a custom VeriproofIngestTransport implementation that captures payloads in memory. The simplest approach is to mock the HTTP transport:

from unittest.mock import MagicMock, patch from veriproof_sdk import VeriproofClientOptions, configure_veriproof # Patch the HTTP client so no real requests are made with patch('httpx.Client') as mock_http: mock_http.return_value.post.return_value.status_code = 200 mock_http.return_value.post.return_value.json.return_value = {"merkle_root": "abc"} provider, exporter = configure_veriproof( VeriproofClientOptions(api_key="test-key", application_id="test"), service_name="test", set_global=True, ) adapter = MyFrameworkAdapter() # ... run a test interaction ... provider.force_flush() # Assert via the captured spans on the mock_http call

Last updated on