Metadata-Version: 2.4
Name: forma-sdk
Version: 3.3.0
Summary: FORMAAI — the AI Agent Firewall. Zero-config capture of every LLM call, human approvals, kill switch, and a cryptographically signed audit trail.
Home-page: https://github.com/amit5115/forma-sdk
Author: FORMAAI
Author-email: sdk@formaai.in
Keywords: ai agents governance human-approval kill-switch audit-trail cryptography llm openai anthropic langchain
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24.0
Requires-Dist: pydantic>=2.0
Provides-Extra: cli
Requires-Dist: click>=8.0; extra == "cli"
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.20; extra == "anthropic"
Provides-Extra: litellm
Requires-Dist: litellm>=1.0; extra == "litellm"
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.1; extra == "langchain"
Provides-Extra: all
Requires-Dist: click>=8.0; extra == "all"
Requires-Dist: openai>=1.0; extra == "all"
Requires-Dist: anthropic>=0.20; extra == "all"
Requires-Dist: litellm>=1.0; extra == "all"
Requires-Dist: langchain-core>=0.1; extra == "all"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# FORMAAI SDK — v3.0.0

**The AI Agent Firewall. Capture every LLM call, pause high-stakes ones for a human, halt any agent instantly, and prove it all with a signed audit trail.**

FORMAAI sits between your code and the model. The moment you call `tl.init()`, every LLM and tool call is **captured** as a cryptographically signed run, can be **paused for human approval**, and can be **killed** from the dashboard in under two seconds. Four pillars, zero policy config:

1. **Capture** — every OpenAI / Anthropic / LiteLLM / LangChain call is auto-recorded (model, tokens, cost, latency).
2. **Approve** — high-stakes calls pause until a human signs off in the FORMAAI inbox.
3. **Kill** — halt any agent from the dashboard with no redeploy.
4. **Prove** — every captured run is HMAC-signed and tamper-evident.

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)

---

## Install

```bash
pip install forma-sdk
```

Import name is `trustlayer`:

```python
import trustlayer as tl
```

---

## Quickstart — one line, everything captured

```python
import trustlayer as tl

# One call. Every LLM call in your process is now captured + signed.
# No decorators, no context managers, no edits inside your business logic.
tl.init(api_key="tl_live_YOUR_KEY")    # from formaai.in → Settings

# Your existing code is unchanged.
result = run_underwriting_model(application)
```

Confirm it's connected:

```python
print(tl.verify())
# → {"verified": True, "capture": "active", "signing": "enabled",
#    "kill_switch": "off", "approvals": "off", ...}
```

---

## The four pillars

```python
import trustlayer as tl

tl.init(
    api_key="tl_live_YOUR_KEY",
    human_sponsor="ops@company.com",            # accountable human on every run
    kill_switch=True,                            # halt this agent from the dashboard
    max_cost_usd=5.0,                            # hard per-run cost cap
    require_approval_when=lambda ctx: ctx.get("amount", 0) > 1_000_000,
    approval_message="High-value transaction requires human review.",
)
```

- **Capture** is on by default — nothing else needed.
- **Approve**: `require_approval_when(ctx)` returns `True` → the call pauses until a human decides in the FORMAAI inbox (fail-closed).
- **Kill**: `kill_switch=True` → triggering a kill from the dashboard raises `KillSwitchTriggered` on the next call in < 100 ms.
- **Prove**: every run is signed with your API key; verify with `trustlayer verify <run_id>`.

---

## Multiple agents — `tl.register()` / `agents=` (zero edits)

Map your **existing functions** to agents without touching their bodies. Each one gets its own discrete, signed run and its own approval / kill / cost config:

```python
import trustlayer as tl
from my_app import approve_loan, validate_kyc, detect_fraud

tl.init(
    api_key="tl_live_YOUR_KEY",
    agents={
        "kyc-validator":  validate_kyc,                                   # bare callable
        "loan-approval":  {"fn": approve_loan, "risk_level": "HIGH", "kill_switch": True},
        "fraud-detector": {"fn": detect_fraud,
                           "require_approval_when": lambda ctx: True},
    },
)

# Or register after init (decorator form also works):
tl.register("loan-approval", approve_loan, risk_level="HIGH", max_cost_usd=2.0)

@tl.register("kyc-validator", kill_switch=True)
def validate_kyc(doc): ...      # one line above the def — body unchanged

# Call them exactly as before — each captured and attributed independently.
result = approve_loan(application)
```

Per-agent kwargs (same as `tl.init`'s per-agent set): `compliance, risk_level, human_sponsor, purpose, max_cost_usd, require_approval_when, approval_message, approval_title, approval_timeout, approval_poll_interval, approval_via, version, kill_switch`. Unknown keyword → `TypeError`.

---

## Human approvals (human-in-the-loop)

```python
tl.init(
    api_key="tl_live_YOUR_KEY",
    require_approval_when=lambda ctx: ctx.get("amount", 0) > 1_000_000,
    approval_message="High-value transaction requires human review.",
)
result = approve_loan(application)   # pauses for sign-off on high-stakes calls (fail-closed)
```

`require_approval_when(ctx)` receives `{agent_name, provider, model, action_type, prompt, tool_name, tool_args}`; return `True` to require approval. It may also return a dict for per-call overrides: `{"required": True, "timeout": 60, "message": "STAT review"}`. Predicate errors fail closed (require approval).

```python
from trustlayer import ApprovalRejectedError, ApprovalTimeoutError

try:
    result = approve_loan(application)
except ApprovalRejectedError as e:
    ...   # a human rejected the action — it was NOT executed
except ApprovalTimeoutError as e:
    ...   # no decision within the timeout
```

---

## Kill switch

```python
tl.init(api_key="tl_live_YOUR_KEY", kill_switch=True)        # process-wide
# or per agent:
tl.register("fraud-agent", detect_fraud, kill_switch=True)
```

When you trigger a kill from the dashboard, the next LLM/tool call raises `KillSwitchTriggered` — no redeployment. Works offline too via `FORMA_KILL_SWITCH=1` or a `~/.forma/kill.lock` file (useful in air-gapped / strict-egress Kubernetes).

---

## Signed audit trail (Prove)

Every captured run is finalized, HMAC-signed with your API key, and shipped to your audit trail. Verify any run's signature locally — no API key needed if you use an Ed25519 keypair:

```bash
trustlayer verify <run_id>     # ✓ VERIFIED — signature is valid and untampered
trustlayer export <run_id>     # download the signed record (PDF)
trustlayer keygen              # generate an Ed25519 signing keypair
```

---

## Observability API

| Call | Returns |
|---|---|
| `tl.verify()` | `{verified, agent, capture, signing, kill_switch, approvals, summary}` — confirm the SDK is connected and capturing. |
| `tl.status()` | `{version, capture_active, ambient_runs, kill_switch_armed, kill_switch_active, approvals_configured, ambient_agent, frameworks}`. |

```python
tl.init(api_key="tl_live_...", kill_switch=True,
        require_approval_when=lambda ctx: True)
tl.verify()
# → {"verified": True, "capture": "active", "signing": "enabled",
#    "kill_switch": "armed", "approvals": "configured", ...}
```

---

## `tl.init()` parameters

| Parameter | Description |
|---|---|
| `api_key` | FORMAAI API key (or `FORMA_API_KEY` env, or `forma setup`). |
| `api_url` | Backend URL override (default `https://api.formaai.in`). |
| `agent_name` | Display name for ambient auto-captured runs. |
| `human_sponsor` | Accountable human recorded on every run. |
| `auto_capture` (`True`) | Auto-patch OpenAI/Anthropic/LiteLLM/LangChain. |
| `ambient_runs` (`True`) | Create signed runs for auto-captured calls. |
| `kill_switch` (`False`) | Start a process-level kill-switch watcher. |
| `compliance` | Optional framework tags recorded on runs (metadata only). |
| `agents` | Zero-edit multi-agent map. `{"name": fn}` or `{"name": {"fn": fn, ...}}`. |
| `purpose` / `risk_level` | Metadata recorded on runs. |
| `max_cost_usd` | Hard per-run cost cap; runs over it are marked failed. |
| `require_approval_when` | Predicate `ctx -> bool` — pause for a human when it returns `True`. |
| `approval_message` / `approval_title` / `approval_timeout` / `approval_poll_interval` / `approval_via` | Approval configuration. |
| `timeout` (`10`) / `max_retries` (`2`) | HTTP transport settings. |

---

## CLI

```bash
trustlayer setup              # one-time guided setup (paste your key)
trustlayer scan app.py        # check a file for governance coverage
trustlayer verify <run_id>    # verify a run signature
trustlayer export <run_id>    # download a signed record
trustlayer status             # API connection + fleet overview
trustlayer keygen             # Ed25519 signing keypair
```

---

## Node.js / TypeScript

> **Coming soon.** Capture, approvals, kill switch, and signing are **Python-first** today.

---

## Dashboard & docs

- Dashboard: **[formaai.in](https://formaai.in)**
- Developer guide: [formaai.in/developer-guide](https://formaai.in/developer-guide)

## Migrating from 2.x

`company_policy={}` and the local PII / prompt-injection gate (`enforce`, `preset`,
`block`, `allow`, `pii`, `authorized_actions`, `domain`, `tl.preview`,
`ComplianceViolation`) were **removed in 3.0.0**. FORMAAI is now a pure
capture + approve + kill + prove firewall — you define *what needs a human* and
*what can be killed*; we capture and sign everything. Remove `company_policy`
from your `tl.init()` and keep `require_approval_when` / `kill_switch` /
`max_cost_usd` as top-level params.

## License

MIT — see [LICENSE](LICENSE).
