Metadata-Version: 2.4
Name: agec
Version: 0.2.0
Summary: Pre-execution governance SDK for AI agents
Author-email: Onur Esmercan <onuresmercan@gmail.com>
Maintainer: onure
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/onur-esmercan/agec
Project-URL: Repository, https://github.com/onur-esmercan/agec
Keywords: ai-agents,governance,audit,security,pre-execution
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Security
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == "openai"
Provides-Extra: langgraph
Requires-Dist: langgraph>=0.2; extra == "langgraph"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"

# AGEC

AGEC SDK is a pre-execution governance layer for AI agents.

It is not an agent framework. It validates `Intent + Context + Execution Path`
immediately before an agent executes tools.

```text
Agent Reasoning
    |
AGEC SDK
    |
Tool Execution
```

## Installation

```bash
pip install agec
```

To verify the package exactly as a PyPI user would install it on Windows
PowerShell:

```powershell
python -m venv .venv
.\.venv\Scripts\python -m pip install agec
@'
from agec import AGEC, Context, ExecutionPath, Intent

decision = AGEC().validate(
    Intent(type="send_price_list", source="pypi_smoke_test", confidence=0.91),
    Context(
        facts={
            "price_list_status": "current",
            "campaign_status": "active",
            "customer_segment": "premium",
        }
    ),
    ExecutionPath(
        steps=[
            "crm.read_customers",
            "pricing.get_latest_list",
            "crm.filter_segment",
            "email.send_campaign",
        ],
        approved_path_id="price_campaign_v1",
    ),
)

print(decision.status)
'@ | .\.venv\Scripts\python -
```

Expected output:

```text
proceed
```

You can also run the installed CLI demo:

```powershell
agec-demo
agec-demo --audit-file agec-demo-audit.jsonl
```

The demo runs deterministic `AGEC.validate(...)` scenarios and prints
`proceed`, `review`, `suspend`, `halt`, and `reauthorize` decisions.

## Quick Start

```python
from agec import AGEC, Intent, Context, ExecutionPath

agec = AGEC()

decision = agec.validate(
    intent=Intent(
        type="send_price_list",
        source="user_request",
        confidence=0.91,
    ),
    context=Context(
        facts={
            "price_list_status": "current",
            "campaign_status": "active",
            "customer_segment": "premium",
        }
    ),
    execution_path=ExecutionPath(
        steps=[
            "crm.read_customers",
            "pricing.get_latest_list",
            "crm.filter_segment",
            "email.send_campaign",
        ],
        approved_path_id="price_campaign_v1",
    ),
)

print(decision.status)
# proceed / review / suspend / halt / reauthorize
```

The decision is a structured object:

```json
{
  "agec_id": "agec_123",
  "status": "proceed",
  "intent_score": 0.91,
  "context_score": 0.88,
  "path_score": 1.0,
  "reason": "Intent, context and execution path validated.",
  "audit_id": "audit_456"
}
```

## Core API

```python
agec.validate(intent, context, execution_path)
```

### Models

```python
Intent(type: str, source: str, confidence: float)
Context(facts: dict, context_hash: str | None = None)
ExecutionPath(steps: list[str], approved_path_id: str | None = None)
GovernanceDecision(status, reason, intent_score, context_score, path_score)
```

## MVP Decision Logic

| Condition | Decision |
|---|---|
| Intent invalid | `halt` |
| Intent ambiguous | `review` |
| Context missing | `review` |
| Context invalid | `suspend` |
| Path unknown | `reauthorize` |
| Path modified | `halt` |
| All valid | `proceed` |

## Audit Log

Every validation writes an in-memory audit event. You can persist it as JSONL:

```python
from agec import AGEC, AuditLog

audit_log = AuditLog()
agec = AGEC(audit_log=audit_log)

# ... run validations ...

audit_log.save_json("audit.jsonl")
```

## Simple Agent Wrapper

`AGEC.wrap_callable(...)` can guard a LangGraph node, an OpenAI Agents tool
function, or any regular Python callable:

```python
guarded_tool = agec.wrap_callable(
    tool_function,
    intent=intent,
    context=context,
    execution_path=execution_path,
)

result = guarded_tool()
```

The callable runs only when the decision status is `proceed`.

## OpenAI and LangGraph Adapters

AGEC also ships named adapter helpers. They do not own API keys or create agent
framework clients; they guard the callable you are about to execute.

```python
from agec import wrap_openai_tool

guarded_send = wrap_openai_tool(
    send_email_campaign,
    intent=intent,
    context=context,
    execution_path=execution_path,
)

result = guarded_send()
```

For LangGraph-style nodes, static model objects or state-aware factories can be
used:

```python
from agec import Context, ExecutionPath, Intent, wrap_langgraph_node

guarded_node = wrap_langgraph_node(
    node,
    intent=lambda state: Intent(
        type=state["intent_type"],
        source="agent_plan",
        confidence=state["confidence"],
    ),
    context=lambda state: Context(facts=state["facts"]),
    execution_path=lambda state: ExecutionPath(
        steps=state["steps"],
        approved_path_id=state["approved_path_id"],
    ),
)
```

If AGEC returns anything other than `proceed`, the adapter raises
`AGECExecutionBlocked` and the wrapped call is not executed.

## Examples

- `agec-demo`
- `examples/cto_demo.py`
- `examples/01_basic_validation.py`
- `examples/02_block_bad_context.py`
- `examples/03_openai_tool_guard.py`
- `examples/04_langgraph_node_guard.py`
- `examples/05_audit_log.py`
- `examples/06_persisted_audit_log.py`
- `examples/07_local_automation_guard.py`
- `examples/08_sales_campaign.py`

Run demos locally:

```bash
PYTHONPATH=src python examples/cto_demo.py
PYTHONPATH=src python examples/01_basic_validation.py
PYTHONPATH=src python examples/02_block_bad_context.py
PYTHONPATH=src python examples/03_openai_tool_guard.py
PYTHONPATH=src python examples/04_langgraph_node_guard.py
PYTHONPATH=src python examples/05_audit_log.py
PYTHONPATH=src python examples/06_persisted_audit_log.py
PYTHONPATH=src python examples/07_local_automation_guard.py
PYTHONPATH=src python examples/08_sales_campaign.py
```

## Roadmap

- [x] Python SDK
- [x] Audit log
- [x] Simple LangGraph/OpenAI Agents-compatible callable wrapper
- [x] Named OpenAI/LangGraph adapter helpers
- [ ] MCP server

## License

Apache-2.0
