Metadata-Version: 2.4
Name: forceequals
Version: 0.1.4
Summary: Governance SDK for AI agents. Builders only call emit_event() and request_approval().
Author: ForceEquals
License: Proprietary
Project-URL: Homepage, https://www.forceequals.ai
Project-URL: Documentation, https://www.forceequals.ai
Project-URL: Repository, https://github.com/ForceEquals/forceequals-momentum
Keywords: ai,agents,governance,langchain
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.32.0
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3.0; extra == "langchain"
Requires-Dist: langgraph>=0.2.0; extra == "langchain"

# ForceEquals SDK for Python

Governance for coded AI agents. Your agent reports facts; Momentum applies policy and can pause for a human.

You only call:

```python
fe.emit_event(...)
fe.request_approval(...)
```

Wrap each business run with `@fe.governed`.

Requires **Python 3.10+**.

## Install

```bash
pip install forceequals
```

## Before you start

1. Register the agent in [Momentum](https://www.forceequals.ai) and copy its `agent_id`.
2. Create an API key in **Momentum → API Key** (`fe_live_...`).
3. Put both in your environment:

```bash
FORCEEQUALS_API_KEY=fe_live_paste_your_key_here
FORCEEQUALS_AGENT_ID=loan-agent
```

## Quick start

```python
import os
from forceequals import (
    ForceEquals,
    GovernanceBlockedError,
    GovernanceRejectedError,
)

fe = ForceEquals(
    api_key=os.getenv("FORCEEQUALS_API_KEY"),
    agent_id=os.getenv("FORCEEQUALS_AGENT_ID"),
)


@fe.governed
def handle_application(payload: dict) -> dict:
    fe.emit_event("loan.risk.calculated", {
        "loan_amount": payload["amount"],
        "risk_score": payload["risk_score"],
    })

    fe.request_approval(
        title="Approve disbursement",
        context={"amount": payload["amount"]},
    )

    # your side-effect after Approve
    return {"ok": True}


try:
    result = handle_application({"amount": 12000, "risk_score": 0.4})
    print("Done", result)
except GovernanceBlockedError as exc:
    print("Blocked:", exc.reason)
except GovernanceRejectedError as exc:
    print("Rejected:", exc.reason)
```

That is the whole integration: install, create the client, wrap the run, report facts, ask a human when needed.

## What each call does

| Call | When to use it |
|---|---|
| `@fe.governed` | Wrap one business run (one loan, one ticket, one PR). |
| `fe.emit_event(name, data)` | Report a fact. Policy decides continue, pause, or block. |
| `fe.request_approval(title=..., context=...)` | Ask a human on Momentum Feed. Your process waits until they resolve it. |

If `emit_event` is **blocked**, the SDK raises `GovernanceBlockedError`. If a pause is **rejected**, it raises `GovernanceRejectedError`. Approve resumes the next line.

Review decisions in **Momentum → Feed**.

## Environment

| Variable | Purpose |
|---|---|
| `FORCEEQUALS_API_KEY` | Live key from Momentum (`fe_live_...`) |
| `FORCEEQUALS_AGENT_ID` | Same id you registered in Connect Agent |
| `FORCEEQUALS_BASE_URL` | Optional override (defaults to the hosted API) |
| `FORCEEQUALS_POLL_SECONDS` | How often to check a paused run (default `2`) |

You can pass `api_key` and `agent_id` in the constructor instead of using env vars.

## Docs

- Product: [forceequals.ai](https://www.forceequals.ai)
- Package: [pypi.org/project/forceequals](https://pypi.org/project/forceequals/)
