Metadata-Version: 2.4
Name: aiel-runtime
Version: 0.3.4
Summary: AIEL Runtime adapter used by the Execution Plane to load and execute user projects.
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: aiel-sdk>=1.1.6
Requires-Dist: anyio>=4.0
Requires-Dist: pydantic>=2.8
Provides-Extra: ai
Requires-Dist: langchain-core>=0.3.0; extra == 'ai'
Requires-Dist: langgraph>=0.2.0; extra == 'ai'
Provides-Extra: mcp
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# AI Execution Layer Runtime (`aiel-runtime`)

`aiel-runtime` is the **execution adapter** used by the **Execution Plane (EP)** to load and run user projects from
**immutable snapshots**. It provides a stable, versioned runtime entrypoint that:

1. loads a project snapshot (downloaded by EP from the Data Plane),
2. imports `entry_point.py` (registering exports via `aiel-sdk` decorators),
3. validates contracts (signatures, export consistency),
4. executes exported handlers (tools / agents / flows / HTTP / MCP).

This repository is intentionally focused on **runtime orchestration and invocation**, not on developer ergonomics.
Developer-facing contracts live in **`aiel-sdk`**.

---

## Why this exists

A production Execution Plane needs a deterministic way to execute user code that is:

- **versioned** (reproducible across time),
- **contract-driven** (predictable invocation shape),
- **isolated** (sandboxed by EP),
- **observable** (structured outputs and error taxonomy),
- **portable** (runs as a subprocess or container entrypoint).

`aiel-runtime` is that adapter.

---

## Key features

- **Single runner entrypoint**: `python -m aiel_runtime.runner`
- **Contract validation** via `aiel-sdk`
- **Deterministic execution** with lockstep runtime/SDK versioning
- **Describe + Invoke protocol** (stdin JSON → stdout JSON)
- **Snapshot-first** execution model (EP controls downloads/caching)
- Designed for EP sandbox enforcement (CPU/memory/timeouts/network/secrets)

---

## Repository layout (src-layout)

This repo uses a `src/` layout to prevent accidental import shadowing and to support editable installs reliably.


---

## Installation

### Local development (editable)
```bash 
python -m pip install -U pip
python -m pip install -e .
```

## Production (pinned)
Pin versions for deterministic behavior:
```bash 
python -m pip install "aiel-runtime==X.Y.Z"
```

Optional curated bundles (if your runtime image includes these):

```bash 
python -m pip install "aiel-runtime[ai]==X.Y.Z"
```
> Recommended policy: lockstep versions
> `aiel-runtime==X.Y.Z` depends on `aiel-sdk==X.Y.Z.`

## Runtime entrypoint
The Execution Plane runs:
```bash 
python -m aiel_runtime.runner
```

EP must provide:
- EP_FILES_ROOT: absolute path to a snapshot folder containing entry_point.py.

### Example:
```bash 
export EP_FILES_ROOT=/tmp/ep/snapshots/<tenant>/<project>/<release>/files
```

Snapshot expectations
At minimum, the snapshot must contain:
- entry_point.py (required)
- any local modules imported by entry_point.py (e.g., tools/, agents/, mcp_server/)

A typical snapshot layout:
```bash 
files/
  entry_point.py
  tools/
    core.py
  agents/
    main.py
  mcp_server/
    core.py
  requirements.txt   # optional (runtime images should be pre-baked)
```
> Dependency installation at runtime is intentionally not supported.
> Runtime images must include curated dependencies up-front.

## Runner protocol (stdin → stdout)
`aiel-runtime` is a small JSON protocol engine.

### Describe exports

#### stdin
```json
{ "schema_version": "v1", "action": "describe" }
```
### stdout
```json
{
  "schema_version": "v1",
  "ok": true,
  "result": {
    "sdk_version": "X.Y.Z",
    "runtime_version": "X.Y.Z",
    "tools": ["normalize_email"],
    "agents": ["collect_personal_data"],
    "flows": ["driver_onboarding"],
    "http_handlers": [{"method":"POST","path":"/driver/onboard"}],
    "mcp_servers": [{"name":"driver_support","tools":["lookup_existing_driver"]}]
  }
}
```
## Invoke an export
### stdin
```json
{
  "schema_version": "v1",
  "action": "invoke",
  "kind": "tool",
  "name": "normalize_email",
  "payload": {
    "email": "Test@Example.com",
    "name": "Test",
    "ctx": {
      "request_id": "req_123",
      "tenant_id": "t_1",
      "workspace_id": "w_1",
      "project_id": "p_1"
    }
  }
}
```
### stdout
```json
{ "schema_version": "v1", "ok": true, "result": { "email": "test@example.com" } }
```

## Error response
### stdout
```json
{
  "schema_version": "v1",
  "ok": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Tool not found: normalize_email"
  }
}
```

## Execution model

Runtime load sequence:
- Reset registry (defensive against warm process reuse)
- Add EP_FILES_ROOT to sys.path
- Import entry_point (registers exports via decorators)
- Validate contracts (signatures and export invariants)
- Execute describe or invoke

## Export kinds

Supported kind values (current):
- `tool` — callable signature: tool(ctx, payload)
- `agent` — callable signature: agent(ctx, state)
- `flow` — callable signature: flow(ctx, input) OR graph_builder() returning a compiled graph with ainvoke
- (`http`, `mcp` are typically served by EP; runtime can expose metadata via `describe`)

EP is responsible for mapping HTTP/MCP requests into invoke payloads.


## Versioning and compatibility
Runtime version
`runtime_version` identifies the runner behavior and dependency bundle.

### SDK version
sdk_version identifies the contract surface expected by the user project.

### Recommended compatibility policy:
- `aiel-runtime==X.Y.Z` depends on `aiel-sdk==X.Y.Z`
- Data Plane manifest includes both `runtime` and `sdk_version`
- EP allowlists `runtime` values and uses (`runtime`, `sdk_version`, `file hashes`) for cache keys.

## Security model

`aiel-runtime` assumes EP enforces isolation. At minimum, EP should provide:

- process/container isolation
- read-only snapshot filesystem
- strict CPU/memory/timeouts
- deny-by-default network egress (unless explicitly enabled)
- controlled secret injection via context (do not expose host env to user code)

Runtime performs defense-in-depth checks where practical (contract validation, error normalization).
Hard security boundaries belong in EP.

## Development
### Run the runtime directly (fast local iteration)
This runs the same execution engine used by EP, but without auth and without the Data Plane. You point the runtime at a local folder that already contains the files.

#### 1) Prerequisites
Your local folder must contain at least:
- entry_point.py (required)
- any modules imported by entry_point.py (e.g. tools/, agents/, mcp_server/)

```bash
my-project/
  entry_point.py
  tools/
    core.py
  agents/
    main.py
```

#### 2) Install runtime + SDK
```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip

python -m pip install -U aiel-runtime aiel-sdk
```
If you use optional facades locally (LangGraph/LangChain/LangSmith), install extras.
Important (zsh): quote extras:
```bash
python -m pip install -U "aiel-sdk[all]"
```

#### 3) Run `describe` locally
From the project folder (where entry_point.py exists):
```bash
echo '{"schema_version":"v1","action":"describe"}' | python -m aiel_runtime.runner --files-root "$PWD" --no-traceback
```
You should get something like:
{
  "ok": true,
  "result": {
    "tools": ["..."],
    "agents": ["..."],
    "flows": ["..."],
    "http_handlers": [...],
    "mcp_servers": [...]
  }
}
#### 4) Invoke a tool locally
Create a request inline:
```bash
cat > req.json <<'JSON'
{"schema_version":"v1","action":"invoke","kind":"tool","name":"persist_driver_profile","payload":{"email":"a@b.com","name":"Aldenir"}}
JSON

python -m aiel_runtime.runner --files-root "$PWD" < req.json
```
To include sanitized tracebacks for debugging:
```bash
python -m aiel_runtime.runner --files-root "$PWD" --debug < req.json
```

### Common troubleshooting
zsh: `no matches found: aiel-sdk[all]`

Use quotes:
python -m pip install `"aiel-sdk[all]"`

`entry_point.py` not found
Make sure you run from the folder that contains `entry_point.py`, or pass the correct path:
```bash
python -m aiel_runtime.runner --files-root /path/to/project
```
#### Import errors (e.g. No module named ...)
Install the required packages in the same venv, or use an EP runtime bundle that includes them.

`ModuleNotFoundError`: `aiel_sdk`
- Ensure your runtime environment has aiel-sdk installed.
- Prefer installing aiel-runtime (which should depend on the correct aiel-sdk).

## Missing integrations (LangGraph / LangChain / LangSmith)
-  Ensure runtime image includes the curated dependency bundle (aiel-runtime[ai]) or explicit deps.

# Registry leakage between invocations
- Ensure registry is reset per load (runtime does this by default).
- EP should avoid reusing a single Python process across unrelated tenants/projects unless explicitly designed.

# Registry leakage between invocations

- Ensure registry is reset per load (runtime does this by default).
- EP should avoid reusing a single Python process across unrelated tenants/projects unless explicitly designed.

## Testing
Recommended minimal tests:
- load snapshot → describe exports
- invoke tool/flow happy path
- contract violation errors are clear
- missing dependency errors are clear
- registry resets properly

Example (pytest):
```bash
python -m pip install -U pytest
pytest -q
```
