Skip to main content

DapplePot Python SDK for AI agent security observability — instruments LangChain/LangGraph, OpenAI, and Anthropic

Project description

DapplePot Python SDK

Python SDK for instrumenting LLM agents with DapplePot security observability. Drop-in integrations for LangChain/LangGraph, OpenAI, and Anthropic — sends structured events to the DapplePot ingest API and runs real-time threat detection in the hot path.

Installation

Ensure you have Python 3.10+ installed, then:

pip install dapplepot-sdk

# Framework-specific extras:
pip install "dapplepot-sdk[langchain]"    # LangChain / LangGraph
pip install "dapplepot-sdk[openai]"       # OpenAI
pip install "dapplepot-sdk[anthropic]"    # Anthropic
pip install "dapplepot-sdk[all]"          # Everything

Quick Start

Get your sdk_key, tenant_id, agent_id, and ingest_url from the DapplePot dashboard.

Anthropic

The standard anthropic package is patched in-place — upgrade it freely without coordinating with DapplePot releases.

import anthropic
from dapplepot_sdk import DapplePot

dp = DapplePot(
    sdk_key    = "dp_sk_...",
    tenant_id  = "your-tenant-id",
    agent_id   = "your-agent-id",
    ingest_url = "https://ingest.dapplepot.com",
)
dp.instrument_anthropic()

client = anthropic.Anthropic(api_key="...")

with dp.session(user_context_id="user_123", user_tenant_id="acme_corp"):
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    )

All LLM, tool, and session events are captured automatically. See Tool Tracking for how multi-turn tool-use loops are traced with zero extra code.

OpenAI

import openai
from dapplepot_sdk import DapplePot

dp = DapplePot(
    sdk_key    = "dp_sk_...",
    tenant_id  = "...",
    agent_id   = "...",
    ingest_url = "https://ingest.dapplepot.com",
)
dp.instrument_openai()

with dp.session(user_context_id="user_123"):
    response = openai.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
    )

LangChain / LangGraph

LangChain fires its own callbacks during chain or graph execution — pass dp.callback_handler() and DapplePot listens.

from dapplepot_sdk import DapplePot

dp = DapplePot(
    sdk_key    = "dp_sk_...",
    tenant_id  = "...",
    agent_id   = "...",
    ingest_url = "https://ingest.dapplepot.com",
)

handler = dp.callback_handler(
    user_context_id="user_123",
    user_tenant_id="acme_corp",
)
result = graph.invoke(
    {"messages": [...]},
    config={"callbacks": [handler]},
)

For LangGraph: each named graph node automatically becomes a node_start / node_end event. Tool calls handled via ToolNode emit tool_start / tool_end automatically.

Core API

dp.session(*, user_context_id=None, user_tenant_id=None)

Context manager that opens a DapplePot session for a multi-call conversation. The session ID is generated automatically.

with dp.session(user_context_id="u_42", user_tenant_id="acme") as sess:
    # All LLM calls inside this block belong to the same session
    response = client.messages.create(...)
Parameter Description
user_context_id Identifies the end-user within the session (optional)
user_tenant_id For multi-tenant agents, identifies the customer tenant (optional)

Outside dp.session(), every patched LLM call becomes its own one-event session.

dp.node(name, *, input=None)

Optional context manager that adds named structure to your agent code. Emits node_start on entry, node_end on success, or node_error if an exception escapes.

with dp.session():
    with dp.node("retrieve_context", input=query):
        docs = vector_store.search(query)

    with dp.node("generate_response"):
        response = client.messages.create(...)

Use this when you want named steps in the trace UI — it is entirely optional. LangChain and LangGraph emit node events automatically from their own callbacks.

dp.callback_handler(*, user_context_id=None, user_tenant_id=None)

Returns a fresh DapplePotCallbackHandler for one invocation of a LangChain chain or LangGraph run.

Tool Tracking

For the Anthropic and OpenAI integrations, tool calls are detected automatically — no client-side instrumentation is required.

Anthropic: when the model returns tool_use content blocks, tool_start is emitted. When the next messages.create() call carries matching tool_result blocks, tool_end is emitted with the real tool output and latency. Set is_error=True on the tool_result block to emit tool_error instead.

OpenAI: when the model returns tool_calls, tool_start is emitted. When the next chat.completions.create() carries the corresponding role="tool" message, tool_end is emitted. Add is_error=True to the tool message to emit tool_error instead (a DapplePot convention — OpenAI ignores extra fields).

LangChain / LangGraph: tool callbacks are wired automatically by the framework's own BaseTool and ToolNode.

Constructor

DapplePot(
    sdk_key,     # required — your SDK key from the DapplePot dashboard
    tenant_id,   # required — your tenant ID
    agent_id,    # required — the agent being instrumented
    ingest_url,  # required — your DapplePot ingest endpoint
    *,
    sample_rate        = 1.0,   # 0.0–1.0; fraction of sessions traced
    pii_scrubber       = None,  # custom scrubber object (must implement .scrub_value())
    redact_keys        = None,  # list[str] of payload keys to replace with [REDACTED]
    flush_interval_ms  = 500,   # background flush cadence
    flush_batch_size   = 100,   # max events per flush batch
)

All events are posted to {ingest_url}/v1/ingest/events with Authorization: Bearer {sdk_key}.

Call dp.shutdown() on exit to flush buffered events.

Online Security Checks

The SDK runs 12 sub-checks synchronously on every event. When a check fires it emits a finding immediately (without waiting for session end). Which checks are active and what action they take is configured per-agent in the DapplePot dashboard and fetched automatically at SDK startup.

Sub-check Category Phase Severity
PI-01a prompt_injection input high
PI-01b prompt_injection input critical
PI-01c prompt_injection input high
PI-02a prompt_injection tool_end high
PI-05a prompt_injection input high
PI-08a prompt_injection llm_start high
SID-01a data_disclosure output critical
SID-01c data_disclosure output critical
SID-02a data_disclosure output high
IOH-01a output_handling output critical
EA-01a excessive_agency tool_start high
EA-02b excessive_agency tool_start high

Check configuration and the tool manifest are fetched from the DapplePot API at startup. Update checks in the dashboard and restart your agent — no code changes needed.

Actions

When a check fires, it takes one of four actions (configured per sub-check in the dashboard):

Action Effect
alert Logs a warning; execution continues
sanitize Redacts matched content from the event payload; execution continues
block_call Raises DapplePotBlockedError
terminate_session Raises DapplePotSessionTerminatedError
from dapplepot_sdk import DapplePot, DapplePotBlockedError, DapplePotSessionTerminatedError

try:
    result = graph.invoke(...)
except DapplePotBlockedError as e:
    print(e.signal, e.reason, e.session_id)
except DapplePotSessionTerminatedError:
    print("Session terminated by security policy")

PII Scrubbing

Use the built-in RegexScrubber or implement your own:

from dapplepot_sdk import DapplePot
from dapplepot_sdk.scrubbers import RegexScrubber

scrubber = RegexScrubber(patterns=["email", "ssn", "aws_key", "jwt", "phone"])

dp = DapplePot(
    sdk_key      = "dp_sk_...",
    tenant_id    = "...",
    agent_id     = "...",
    ingest_url   = "https://ingest.dapplepot.com",
    pii_scrubber = scrubber,
)

Built-in pattern names: email, phone, ssn, credit_card, uk_nino, iban, ip_address, aws_key, jwt.

To implement a custom scrubber, subclass BaseScrubber and implement scrub(text: str) -> str:

from dapplepot_sdk.scrubbers import BaseScrubber

class MyScrubber(BaseScrubber):
    def scrub(self, text: str) -> str:
        return text.replace("sensitive", "[REDACTED]")

You can also redact known keys without touching values:

dp = DapplePot(..., redact_keys=["api_key", "password", "ssn"])

Impact on detection: Scrubbing runs after real-time online checks, so live session checks marked for online detection (e.g. SID-02a) still operate on the original content and fire correctly. However, events stored for post-session analysis contain the scrubbed values — PII is replaced with tokens like [EMAIL] or [SANITIZED] before storage, so any offline detection pass on those events will find nothing to flag.

Event Reference

All events flow through POST {ingest_url}/v1/ingest/events.

Event When
session_start dp.session() enter, or first patched call in standalone mode
session_end dp.session() exit (normal close), or last patched call in standalone mode
session_error Exception escapes dp.session() uncaught
node_start dp.node() enter, or LangGraph/LangChain child chain start
node_end dp.node() clean exit, or LangGraph/LangChain child chain end
node_error dp.node() raises, or LangGraph/LangChain child chain fails
llm_start Patched LLM call begins
llm_end Patched LLM call returns (tokens, latency, model, finish reason)
llm_error Patched LLM call raises
tool_start Tool invoked by the model (auto-detected from response)
tool_end Tool result fed back into the model (auto-detected from next call)
tool_error Tool result marked is_error=True, or framework tool callback fails
security_finding Online security check fired (out-of-band)

Errors propagate upward only as far as the exception actually travels. Catch an exception inside dp.node() and the session keeps going. Catch it inside dp.session() and you only see node_error and llm_error, never session_error.

License

Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dapplepot_sdk-0.1.0.tar.gz (26.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dapplepot_sdk-0.1.0-py3-none-any.whl (27.9 kB view details)

Uploaded Python 3

File details

Details for the file dapplepot_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: dapplepot_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 26.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dapplepot_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 82d1414e4f2eb86e498e548edfe2511a4cf2cbf1db05ffeeb2b6cab8a368325f
MD5 c8817bf6ac40751ac0382cb1cae6cb2a
BLAKE2b-256 3dcbc80ad07aa0863bf887a9fd5cf5a1c5bbac1045cbc7ed107c607068fff188

See more details on using hashes here.

File details

Details for the file dapplepot_sdk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dapplepot_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 27.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dapplepot_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 78472733f8de9c663ebcd4de75a5a7f8303d890c5d34cc6bf6250b82fd28dd23
MD5 2b871820d17788e14f7dfd842168db08
BLAKE2b-256 9d39dd69be258192bfe2241628a2cff6b3b86a716e8507e9ac88418c037db837

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page