Skip to main content

Control in Motion SDK -- runtime governance for AI agents

Project description

Control in Motion SDK

Runtime governance enforcement for AI agents. Every tool call your agent makes is checked against your governance policies and delegation contracts before it executes.

Installation

pip install sunbeam-cim

With LangChain support:

pip install sunbeam-cim[langchain]

Quick Start

from sunbeam_cim import CIMAgent

agent = CIMAgent(
    gateway_url="http://localhost:8001",
    agent_id="my-agent-001",
    tenant_id="00000000-0000-0000-0000-000000000001",
)

# Check before acting
decision = agent.check("http_request", domain="api.example.com", method="GET")

if decision.allowed:
    response = requests.get("https://api.example.com/data")
elif decision.denied:
    print(f"Blocked: {decision.explanation}")
elif decision.requires_approval:
    print(f"Waiting for approval: {decision.approval_id}")

Environment Variables

Set these instead of passing constructor args:

export CIM_GATEWAY_URL="http://localhost:8001"
export CIM_AGENT_ID="my-agent-001"
export CIM_TENANT_ID="00000000-0000-0000-0000-000000000001"
export CIM_ENVIRONMENT="prod"

Then just:

from sunbeam_cim import CIMAgent
agent = CIMAgent()  # reads from env

Action Types

HTTP Request

decision = agent.check(
    action_type="http_request",
    domain="api.stripe.com",
    method="POST",
    body={"amount": 1000},
)

Send Message

decision = agent.check(
    action_type="send_message",
    recipient="customer@example.com",
    data_class="internal",
)

Database Query

decision = agent.check(
    action_type="query_db",
    db="production",
    table="users",
)

Decision Object

decision.allowed           # bool — True if ALLOW
decision.denied            # bool — True if DENY
decision.requires_approval # bool — True if REQUIRE_APPROVAL
decision.redacted          # bool — True if REDACT
decision.explanation       # str  — human-readable reason
decision.policy_id         # str  — which policy matched
decision.approval_id       # str  — approval request ID (if pending)
decision.redacted_fields   # list — fields that were masked

# Raise exception instead of checking manually
decision.raise_if_denied()      # raises CIMError on DENY
decision.raise_if_not_allowed() # raises CIMError on anything except ALLOW

Error Handling

from sunbeam_cim import CIMAgent, CIMError

agent = CIMAgent(...)

try:
    decision = agent.check("http_request", domain="api.example.com")
    decision.raise_if_denied()
    # safe to proceed
except CIMError as e:
    print(f"Governance blocked: {e}")
    print(f"Decision was: {e.decision.decision}")

Gateway Unreachable

If the gateway is down, the SDK returns DENY by default (fail-closed):

decision = agent.check("http_request", domain="api.example.com")
# If gateway is unreachable:
# decision.denied == True
# decision.explanation == "Gateway unreachable — action blocked by default"

LangChain Integration

Wrap a tool

from langchain.tools import tool
from sunbeam_cim import CIMAgent

agent = CIMAgent(...)

@tool
def search_web(query: str) -> str:
    """Search the web for information."""
    return requests.get(f"https://api.search.com?q={query}").text

# Wrap with governance
governed_search = agent.as_langchain_tool(
    search_web,
    action_type="http_request",
    domain="api.search.com",
)

# Use in your agent as normal — governance runs automatically

Callback handler (intercepts all tools)

from langchain.agents import AgentExecutor

executor = AgentExecutor(
    agent=llm_agent,
    tools=tools,
    callbacks=[agent.as_langchain_callback()],
)
# Every tool call now goes through governance before executing

Full ActionEvent (advanced)

from sunbeam_cim import CIMAgent, ActionEvent

agent = CIMAgent(...)

event = ActionEvent(
    tenant_id   = "00000000-...",
    agent_id    = "my-agent-001",
    action_type = "http_request",
    tool_name   = "stripe_charge",
    target      = {"domain": "api.stripe.com", "method": "POST"},
    request     = {"body": {"amount": 5000, "currency": "usd"}},
    context     = {
        "data_class": "confidential",
        "tags":       ["verified", "production-ready"],
        "user_id":    "user-123",
    },
    environment = "prod",
)

decision = agent.invoke(event)

Demo (works with local dev stack)

from sunbeam_cim import CIMAgent

agent = CIMAgent(
    gateway_url = "http://localhost:8001",
    agent_id    = "demo-agent-001",
    tenant_id   = "00000000-0000-0000-0000-000000000001",
    environment = "dev",
)

# Should ALLOW (if policy permits)
d = agent.check("http_request", domain="api.example.com")
print(d)  # Decision(ALLOW: Permitted by policy)

# Should DENY (if blocklist policy active)
d = agent.check("http_request", domain="evil.com")
print(d)  # Decision(DENY: Domain blocked by policy)

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

sunbeam_cim-1.0.0.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

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

sunbeam_cim-1.0.0-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file sunbeam_cim-1.0.0.tar.gz.

File metadata

  • Download URL: sunbeam_cim-1.0.0.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for sunbeam_cim-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ea11386e084f3d32d47c07c08b0c8605af2baad396036b07bbe00c65d1ac72e0
MD5 dbbbca5dbc1bc8ca7e6f37e7afa2bd57
BLAKE2b-256 b152e203dfe01cb5cea2778828f801fda2dd0bb6a885c9f0c9d17fabb65a49a5

See more details on using hashes here.

File details

Details for the file sunbeam_cim-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: sunbeam_cim-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 7.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for sunbeam_cim-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 176f512c595821458370d2fcc4024027b8d9771c94f7f8cc370a1af0819489b8
MD5 c06d4e5e91cbd03d7d66be635108665e
BLAKE2b-256 64b337c28dbfe4070738759eaa21fe7c8eb52d848d98e9ccda8aac375c18fda9

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