Skip to main content

Drop-in reliability observability for multi-agent AI workflows

Project description

sentinelai-sdk

A control plane for multi-agent AI workflows — tracing, contract enforcement, safe state, and failure replay.

Dashboard: www.agentsentinelai.com/dashboard


Install

pip install sentinelai-sdk

Get an API key: open the dashboard → ⚙️ Settings → Generate Key. Free, no credit card required.


What it does

I want to… Feature
See every agent step — inputs, outputs, latency, token counts Tracing
Block bad data from reaching the next agent Contracts
Replay a failed run from any checkpoint once the bug is fixed Replay
Let concurrent agents write shared state without overwriting each other Shared State

These stack — use one, two, or all four.


Quickstart

import sentinel

sentinel.init(api_key="sk_live_...")

with sentinel.workflow("my-pipeline") as run:
    with run.step("planner", step_type="llm_call") as step:
        step.set_input({"query": "Plan a trip to Tokyo"})
        result = planner_agent(query)
        step.set_output({"plan": result})

    with run.step("researcher", step_type="tool_call") as step:
        step.set_input(result)
        data = researcher_agent(result)
        step.set_output({"findings": data})

Tracing

Option 1 — Workflow context manager (recommended)

import sentinel

sentinel.init(api_key="sk_live_...")

with sentinel.workflow("travel-planner") as run:
    with run.step("plan", step_type="llm_call") as step:
        step.set_input({"query": query})
        output = plan_agent(query)
        step.set_output(output)

Option 2 — Patch OpenAI clients (sync)

Every client.chat.completions.create() call becomes a traced step automatically.

import openai, sentinel

sentinel.init(api_key="sk_live_...")
client = openai.OpenAI(api_key="...")
sentinel.patch_openai(client, workflow_name="my-pipeline")

sentinel.set_active_run("run_001", "my-pipeline")
response = client.chat.completions.create(model="gpt-4o", messages=[...])

Option 3 — Patch AsyncOpenAI clients (async)

import openai, sentinel

sentinel.init(api_key="sk_live_...")
client = openai.AsyncOpenAI(api_key="...")
sentinel.patch_openai_async(client, workflow_name="my-pipeline")

async def main():
    sentinel.set_active_run("run_001", "my-pipeline")
    response = await client.chat.completions.create(model="gpt-4o", messages=[...])

Deep instrumentation — for libraries like gpt-researcher that create their own AsyncOpenAI instances internally, patch at the class level:

import openai.resources.chat.completions as _oai_completions
sentinel.patch_openai_async(_oai_completions.AsyncCompletions)
# Now every AsyncOpenAI client anywhere in the process is traced

Option 4 — LangChain callback

from sentinel import LangChainCallback
from langchain_openai import ChatOpenAI

sentinel.init(api_key="sk_live_...")
cb = LangChainCallback(workflow_name="my-pipeline")
llm = ChatOpenAI(model="gpt-4o", callbacks=[cb])

Option 5 — Decorator

@sentinel.trace_step(name="planner", step_type="llm_call", workflow_name="my-pipeline")
def planner(query):
    return llm.invoke(query)

Contracts (handoff validation)

Define what one agent must pass to the next. If the payload fails validation, Sentinel raises ContractViolationError, marks the run as blocked in the dashboard, and saves a checkpoint for replay.

import sentinel
from sentinel import ContractViolationError

sentinel.init(api_key="sk_live_...")

sentinel.register_contract(
    agent="researcher",
    accepts={
        "destination": {"type": "string",  "required": True, "min_length": 1},
        "budget":      {"type": "number",  "required": True, "min": 100},
        "days":        {"type": "number",  "required": True, "min": 1, "max": 30},
    },
)

with sentinel.workflow("travel-planner") as run:
    with run.step("planner", step_type="llm_call") as step:
        plan = planner_agent(query)
        step.set_output(plan)

    # Validate handoff before the next agent runs
    sentinel.handoff(
        from_agent="planner",
        to_agent="researcher",
        payload=plan,
        run_id=run.run_id,
    )

    with run.step("researcher", step_type="tool_call") as step:
        research = researcher_agent(plan)
        step.set_output(research)

Field spec options

{"type": "string",  "required": True, "min_length": 1}
{"type": "number",  "required": True, "min": 0, "max": 100}
{"type": "boolean", "required": True}
{"type": "array",   "required": False}

Shared State

Safe concurrent writes — no silent overwrites when agents run in parallel.

# Read
value, version = sentinel.get_state(run_id, "research_results")

# Write with conflict protection (raises ConflictError if stale)
sentinel.propose_state(run_id, "research_results", new_value, base_version=version)

# Auto-retry on conflict (merge function receives current value)
sentinel.propose_state_with_retry(
    run_id, "research_results",
    lambda cur: {**(cur or {}), "hotels": hotel_list}
)

gpt-researcher example

Full deep instrumentation — every internal LLM call becomes a visible step:

import asyncio, os
import sentinel
from sentinel import ContractViolationError
import openai.resources.chat.completions as _oai_completions

sentinel.init(api_key="sk_live_...")

# Patch at the class level to catch gpt-researcher's internal AsyncOpenAI clients
sentinel.patch_openai_async(_oai_completions.AsyncCompletions)

sentinel.register_contract(
    agent="write_report",
    accepts={
        "source_count": {"type": "number",  "required": True, "min": 1},
        "has_context":  {"type": "boolean", "required": True},
        "query":        {"type": "string",  "required": True, "min_length": 1},
    },
)

async def run_research(query: str) -> str:
    from gpt_researcher import GPTResearcher
    researcher = GPTResearcher(query=query, report_type="research_report", verbose=False)

    with sentinel.workflow("gpt-researcher") as run:
        sentinel.set_active_run(run.run_id, "gpt-researcher")

        with run.step("conduct_research", step_type="tool_call") as step:
            step.set_input({"query": query})
            await researcher.conduct_research()
            sources = researcher.get_source_urls()
            context = researcher.get_research_context()
            step.set_output({"source_count": len(sources), "sources": sources[:5]})

        sentinel.handoff(
            from_agent="conduct_research",
            to_agent="write_report",
            payload={"source_count": len(sources), "has_context": bool(context), "query": query},
            run_id=run.run_id,
        )

        with run.step("write_report", step_type="llm_call") as step:
            step.set_input({"source_count": len(sources), "query": query})
            report = await researcher.write_report()
            step.set_output({"word_count": len(report.split())})

    return report

asyncio.run(run_research("What is the impact of AI agents on software engineering in 2025?"))

Run with DuckDuckGo (no API key needed):

pip install gpt-researcher sentinelai-sdk ddgs
RETRIEVER=duckduckgo OPENAI_API_KEY=sk-... python your_script.py

Each run produces ~5 nested steps in the dashboard:

  • openai/gpt-4.1 — agent selection
  • conduct_research — phase wrapper
  • openai/o4-mini — report generation
  • write_report — phase wrapper
  • openai/gpt-4.1 — TOC / introduction / conclusion

Links

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

sentinelai_sdk-0.1.6.tar.gz (23.2 kB view details)

Uploaded Source

Built Distribution

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

sentinelai_sdk-0.1.6-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file sentinelai_sdk-0.1.6.tar.gz.

File metadata

  • Download URL: sentinelai_sdk-0.1.6.tar.gz
  • Upload date:
  • Size: 23.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for sentinelai_sdk-0.1.6.tar.gz
Algorithm Hash digest
SHA256 bd9d2f4ef0d9828d867a990f13518cfc3c7ec3ea36eeb6469e7d04d226ee3a57
MD5 9647ca798727c5a3843b981c4dcc2d3a
BLAKE2b-256 2967aeabe7dcf4e6c308eca9b515738ed1bb275416181854b00d92af49371be0

See more details on using hashes here.

File details

Details for the file sentinelai_sdk-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: sentinelai_sdk-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for sentinelai_sdk-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 7bf047ce4d71310052d93f28ca454d3861c2434b3a645888ff264664916c5c49
MD5 1d7eeb42d1b2a6c4c611db5a226a1613
BLAKE2b-256 e1258ed4f8534f4100c0a0d15c9303a64279651dfd1d5917e118283e5b4212c8

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