Metadata-Version: 2.4
Name: betaloop
Version: 0.1.0
Summary: A reusable, storage-free ReAct agent kernel (engine + framework + protocols) with optional capability bundles.
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"

# betaloop

A reusable, **storage-free** ReAct agent kernel: the engine, framework and
protocols that drive a tool-calling agent, plus optional capability bundles. It
knows nothing about how runs are stored (or even whether they are) — persistence
is an optional `EventSink` a host plugs in. Any application (a thesis-writing
platform, a coding agent, ...) implements its own tools + prompt + storage and
reuses this kernel.

## Core (zero I/O, zero business)
- `runtime` — `AgentRuntime` ReAct loop + event stream
- `llm` — OpenAI-compatible chat client (retry / jittered backoff / response-shape validation)
- `tools` — `ToolRegistry` (register / dispatch / mode filtering)
- `actions` — `Action` + `UndoEngine` (pure, storage-free undo)
- `memory` — `replay_messages` / `recap_text` + `MemoryProvider`
- `events` — `EventSink` (display + record channels) + SSE serialization
- `context` / `modes` — `AgentContext` + `AgentMode` / `ToolCategory`

## Optional bundles (`betaloop.bundles`)
- `host` — `AgentHost` host-adapter framework: message assembly, run envelope
  (`run_start`/`done`), error funneling, `StoreSink` (persist via a store),
  `undo_run`, `DictToolAdapter` (wrap a dict-based tool system). Eliminates the
  per-host boilerplate round 1 left behind.
- `store` — `RunStore`/`ConversationStore`/`BlobStore` Protocols +
  `JsonlRunStore` (default, **zero-database** JSONL + content-addressed blob
  spillover). Hosts wanting a DB implement the Protocols; the default needs none.
- `subagents` — `SubagentEngine` + `SubagentRoster`/`SubagentSpec` + `delegate`
  tool: isolated worker agents the orchestrator hands subtasks to, tagged so undo
  still reverts them while the orchestrator's context stays lean.
- `admin` — `tool_categories` / `list_tools_admin` / `list_tool_packages_admin` /
  `check_packages` over a registry + display packages (admin-panel source;
  packages are grouping only, tools stay per-name togglable).
- `workspace` — sandboxed file I/O + read/write/edit/list tools + file undo reverters
- `sandbox` — Python code execution (bubblewrap or passthrough backend)
- `skills` — markdown skill-pack library + `load_skill` tool

## Install
```bash
pip install betaloop
# local dev (editable + test/lint deps):
pip install -e ".[dev]"
```

## Storage model
The kernel stores nothing. A host provides:
- an **`EventSink`** (write side) — persists message records however it likes
  (DB / file / nowhere);
- a **`MemoryProvider`** (read side, optional) — replays prior turns;
- an **`UndoEngine`** fed from wherever the host kept actions.

## Minimal host sketch
```python
from betaloop import LLMConfig, ToolRegistry
from betaloop.bundles import AgentHost, JsonlRunStore
from betaloop.bundles.workspace import register_file_tools

registry = ToolRegistry()
register_file_tools(registry, lambda ctx: f"/data/{ctx.user_id}")  # your files
store = JsonlRunStore("/var/lib/myapp/agent")                       # zero-DB default
host = AgentHost(registry,
                 LLMConfig(model=..., base_url=..., api_key=...),
                 store, build_system_prompt=my_prompt_builder)

ctx = AgentContext(run_id=rid, user_id=uid)
async for event in host.run(ctx, task, history=prior_turns):
    ...  # forward run_start / step / tool_call / tool_result / done to your frontend
```
A host supplies only its **tools**, **system prompt**, and (optionally) a store
backend — the engine, persistence, run envelope, undo, and (via `subagents`)
delegation are all reused.

## License
MIT
