Metadata-Version: 2.4
Name: al-instrument
Version: 0.1.0
Summary: Auto-instrument LangChain agents with AgentLattice governance — zero-code IAM for AI agents.
Project-URL: Homepage, https://agentlattice.com
Project-URL: Repository, https://github.com/inder/agentlattice
Project-URL: Documentation, https://agentlattice.com/docs
License: MIT
Keywords: agentlattice,ai-governance,iam,instrumentation,langchain
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
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
Requires-Python: >=3.9
Requires-Dist: agentlattice>=0.3.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: langchain-agentlattice>=0.1.0
Requires-Dist: libcst>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Provides-Extra: evals
Requires-Dist: anthropic>=0.20.0; extra == 'evals'
Description-Content-Type: text/markdown

# al-instrument

Auto-instrument LangChain agents with AgentLattice governance. One command adds identity, authorization, and audit trails to every tool your agent calls.

## Install

```bash
pip install al-instrument
```

Requires Python 3.9+. Dependencies: `libcst`, `httpx`, `agentlattice`, `langchain-agentlattice`.

## Quick Start

```bash
# See what al-instrument would change (diff to stdout)
al-instrument agent.py

# Apply the changes
al-instrument agent.py --apply

# Apply + register the agent + verify governance wiring
al-instrument agent.py --apply --register --test
```

The diff is the tutorial. Review the generated code to understand exactly what governance means for your agent.

## What It Does

al-instrument runs a five-stage pipeline on your Python file:

### 1. Analyze

Uses [libcst](https://github.com/Instagram/LibCST) (Concrete Syntax Tree) to find every LangChain tool definition in your code. Three patterns are detected:

```python
# Pattern 1: @tool decorator
@tool
def search_database(query: str) -> str:
    """Search the customer database."""
    return db.search(query)

# Pattern 2: StructuredTool.from_function()
search_tool = StructuredTool.from_function(
    name="search", func=search_database, description="Search the DB"
)

# Pattern 3: BaseTool subclass
class SearchTool(BaseTool):
    name: str = "search"
    description: str = "Search the database"
    def _run(self, query: str) -> str:
        return db.search(query)
```

Detection is deterministic. No LLM involved. Handles aliased imports (`from langchain_core.tools import tool as my_tool`).

### 2. Classify

Each detected tool is classified with an action type and risk level using the `{domain}.{verb}` taxonomy:

| Domain | Example verbs | Default risk |
|--------|--------------|-------------|
| `db` | query, read, write, delete | read/write |
| `email` | send, read | write |
| `file` | read, write, delete | read/write |
| `api` | query, execute | read/write |
| `code` | execute | write |
| `web` | query, read | read |
| `payment` | execute | admin |
| `system` | execute | admin |

If `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` is set, classification uses an LLM for intelligent action type assignment. Without an API key, it falls back to `tool.{name}` with a default risk level of `write`.

### 3. Generate

Transforms your source code using libcst (preserving all comments, formatting, and whitespace):

```python
# BEFORE
from langchain_core.tools import tool

@tool
def search_database(query: str) -> str:
    """Search the customer database."""
    return db.search(query)

@tool
def send_email(to: str, subject: str, body: str) -> str:
    """Send an email to a customer."""
    return email_client.send(to, subject, body)

agent = create_react_agent(llm, [search_database, send_email])
```

```python
# AFTER
import os
from langchain_core.tools import tool
from agentlattice import AgentLattice
from langchain_agentlattice import govern

al = AgentLattice(api_key=os.getenv("AL_API_KEY"))

@tool
def search_database(query: str) -> str:
    """Search the customer database."""
    return db.search(query)

# AgentLattice governance: read-only database access, auto-approved by default policy
governed_search_database = govern(search_database, al=al, action_type="db.query")

@tool
def send_email(to: str, subject: str, body: str) -> str:
    """Send an email to a customer."""
    return email_client.send(to, subject, body)

# AgentLattice governance: external communication, requires human approval
governed_send_email = govern(send_email, al=al, action_type="email.send")

# TODO(al-instrument): Replace tool references in your agent constructor:
#   Use: [governed_search_database, governed_send_email]
agent = create_react_agent(llm, [search_database, send_email])
```

### 4. Register (optional)

With `--register`, al-instrument registers your agent with the AgentLattice API and writes the API key to your `.env` file:

```bash
AL_SERVICE_KEY=sk-svc-... al-instrument agent.py --apply --register
```

You can also pass the key directly:

```bash
al-instrument agent.py --apply --register --service-key sk-svc-...
```

### 5. Verify (optional)

With `--test`, al-instrument calls `execute_sync()` for each action type to verify that governance policies are correctly wired:

```bash
al-instrument agent.py --apply --register --test
```

The verifier checks that each action type gets a policy decision from AgentLattice, confirming that the governance pipeline is live end-to-end.

## CLI Reference

```
al-instrument <file> [options]

Arguments:
  file                  Python file containing LangChain agent code

Options:
  --apply               Write instrumented code back to the file (default: show diff)
  --register            Register the agent with AgentLattice (requires --apply)
  --test                Verify governance wiring (requires --register)
  --service-key KEY     AL_SERVICE_KEY for registration (default: $AL_SERVICE_KEY)
  --agent-name NAME     Agent name for registration (default: derived from filename)
  --base-url URL        AgentLattice API base URL (default: https://agentlattice.com)
  --ci                  CI mode: non-interactive, exit codes only
```

## Idempotency

Running al-instrument on an already-instrumented file is safe. It detects the `from langchain_agentlattice import govern` import and skips with a message:

```
File already has AgentLattice governance (govern() imported). Skipping.
```

## Report Output

After every run, al-instrument prints a structured report:

```
════════════════════════════════════════════════════
  al-instrument report
════════════════════════════════════════════════════

  TOOLS FOUND: 3
    search_database  → db.query     (read, auto-approved)
    send_email       → email.send   (write, requires approval)
    delete_records   → db.delete    (delete, requires approval)

  CLASSIFICATION: LLM-assisted (Claude)
  CHANGES: written to agent.py

  ACTION REQUIRED (1 item):
    1. agent.py:42 — TODO(al-instrument): Replace tool references
       in your agent constructor

  NEXT STEPS:
    1. Review the diff: git diff agent.py
    2. Fix the TODO above (swap tool references)
    3. Set AL_API_KEY in your environment
    4. Run your agent — governance is active
    5. Visit https://agentlattice.com/dashboard to configure policies

════════════════════════════════════════════════════
```

## How It Fits Together

al-instrument generates code that uses two AgentLattice packages:

- **agentlattice** (Python SDK) provides the `AgentLattice` client that communicates with the API
- **langchain-agentlattice** provides the `govern()` wrapper that gates tool execution

After instrumentation, every tool call flows through: Tool invoked → `govern()` calls `al.gate()` → AgentLattice evaluates policy → Approved/Denied → Tool executes or raises error.

Configure policies, approval flows, and audit rules in the AgentLattice dashboard.
