# aiel-sdk

AI Execution Layer SDK: local contracts + decorators + registry for code that runs server-side.

This package is intentionally lightweight. It provides importable symbols, typing, and a
stable contract surface that mirrors the server runtime. Your local code can type-check,
lint, and run basic smoke tests without depending on the full server implementation.

## Install

```bash
pip install aiel-sdk
```

## Quickstart

Use the `aiel.*` namespace for explicit library-style imports:

```py
from aiel.langgraph.graph import StateGraph, MessagesState, START, END
from aiel.llangchain.agents import create_agent

g = StateGraph(MessagesState).add_node("x", lambda s: s).add_edge(START, END)
app = g.compile()
print("OK", app.invoke({"messages": []}), create_agent)
```

You can also import everything from the SDK surface directly:

```py
from aiel_sdk.sdk import (
  StateGraph, MessagesState, START, END, InMemorySaver,
  tools_condition, ToolNode,
  ChatPromptTemplate, PromptTemplate, Runnable, RunnableConfig,
  tool, agent, flow, flow_graph, http, mcp_server
)
```

## Core Concepts

### Contract-first SDK

This SDK mirrors the server runtime contracts. Most symbols are shims or stubs and
do not execute real server logic locally. They exist so your code can:

- import familiar library surfaces
- type-check and validate signatures
- build graphs and registry entries that the server can later execute

### Registry + decorators (travel agency example)

Use decorators to register tools, agents, flows, flow graphs, and HTTP handlers. The
registry is in-memory and used as the local source of truth before deployment.

```py
from aiel_sdk.sdk import tool, agent, flow, flow_graph, http, mcp_server
from aiel.langgraph.graph import StateGraph, MessagesState, START, END, tools_condition
from aiel.langchain import ChatPromptTemplate, RunnableConfig

# Tool: discrete action callable by an agent or graph.
@tool("search_flights")
def search_flights(ctx, payload):
    origin = payload.get("origin")
    destination = payload.get("destination")
    return {"options": [{"flight": "AE101", "from": origin, "to": destination}]}

# Tool: another discrete action.
@tool("quote_hotel")
def quote_hotel(ctx, payload):
    city = payload.get("city")
    return {"hotel": "Skyline Inn", "nightly_usd": 180, "city": city}

# Agent: orchestration entry point.
@agent("travel_agent")
def travel_agent(ctx, input):
    prompt = ChatPromptTemplate.from_messages([
        {"role": "system", "content": "You are a travel agent."},
        {"role": "user", "content": input.get("request", "")},
    ])
    _ = prompt.format_messages()
    return {"intent": "plan_trip", "request": input}

# Flow: simple function flow.
@flow("daily_deals")
def daily_deals(ctx, input):
    flights = search_flights(ctx, input)
    hotels = quote_hotel(ctx, {"city": input.get("destination")})
    return {"flights": flights, "hotels": hotels}

# Flow graph: build a LangGraph-style state graph.
def build_trip_planner():
    g = StateGraph(MessagesState)
    g.add_node("agent", lambda s: s).add_edge(START, "agent").add_edge("agent", END)
    g.add_conditional_edges("agent", tools_condition, path_map={"continue": END})
    return g

flow_graph("trip_planner", build_trip_planner)

# HTTP handler: exposes a REST entry point (server-side at runtime).
@http.post("/travel/quote")
def travel_quote(ctx, body: dict):
    return daily_deals(ctx, body)

# MCP server: register tools exposed via MCP.
mcp = mcp_server("travel_agency")

@mcp.tool("search_flights")
def mcp_search_flights(ctx, origin: str, destination: str):
    return {"options": [{"flight": "AE202", "from": origin, "to": destination}]}

@mcp.tool("quote_hotel")
def mcp_quote_hotel(ctx, city: str):
    return {"hotel": "Harbor View", "nightly_usd": 210, "city": city}

# RunnableConfig is accepted by contract shims for IDE and typing support.
_config = RunnableConfig(trace_id="req-123")
```

### LangGraph contract surface

The `aiel.langgraph.graph` module mirrors core LangGraph symbols used for building
state graphs. Execution is local only for simple checks; the real runtime happens
server-side.

```py
from aiel.langgraph.graph import StateGraph, MessagesState, START, END, tools_condition

g = StateGraph(MessagesState)
g.add_node("x", lambda s: s)
g.add_edge(START, END)
app = g.compile()
print(tools_condition({}), app.invoke({"messages": []}))
```

### LangChain contract surface

The `aiel.langchain` and `aiel.llangchain` modules expose minimal prompt and runnable
shims plus placeholder agent helpers.

```py
from aiel.langchain import ChatPromptTemplate, PromptTemplate, RunnableConfig

prompt = ChatPromptTemplate.from_messages([])
print(prompt.format_messages(), RunnableConfig(trace_id="abc"))
```

## Import map

- `aiel.langgraph.graph` mirrors `langgraph.graph` surface.
- `aiel.langchain` mirrors a minimal `langchain` prompt/runnable surface.
- `aiel.llangchain.agents` mirrors agent factory helpers (contract stub).
- `aiel_sdk.sdk` exposes the full SDK surface in one import.

## Explicit import mapping (LangGraph / LangChain Core / Community)

The SDK provides an explicit surface for the essential imports used in the LangGraph
customer-support tutorial. Use these as drop-in local contracts:

```py
# LangGraph
from aiel.langgraph.graph import END, StateGraph, START, InMemorySaver, ToolNode, tools_condition

# LangChain Core (contract shims provided by this SDK)
from aiel.langchain import ChatPromptTemplate, Runnable, RunnableConfig

# LangChain Core messages + runnables
from aiel.langchain_core.messages import ToolMessage
from aiel.langchain_core.runnables import RunnableLambda

# LangGraph message helpers
from aiel.langgraph.graph.message import AnyMessage, add_messages

# LangGraph checkpointer
from aiel.langgraph.checkpoint.memory import InMemorySaver

# LangChain Community tools (planned shim)
# from aiel.langchain_community.tools.tavily_search import TavilySearchResults
```

Planned mirrors for the tutorial (not yet implemented in this repo):
- `aiel.langchain_community.tools.tavily_search.TavilySearchResults`

## Project layout

- `src/aiel_sdk/sdk/*` core decorators, registry, HTTP/MCP, and shim surfaces.
- `src/aiel/*` explicit `aiel.*` namespace mirror for library-style imports.
- `src/aiel_sdk/examples/*` small smoke examples.

## What runs locally vs server-side

Local:
- decorators and registry updates
- basic graph wiring
- type-checking and IDE support

Server-side (not implemented in this repo):
- actual agent/tool execution
- graph runtime
- HTTP/MCP serving

## Status

![PyPI](https://img.shields.io/pypi/v/aiel-cli)
Backend integration: not implemented yet (planned per sprint output)
