Embeddable agent execution kernel — LLM loop, hooks, events, tools, dynamic sub-agents.
Project description
power-loop
Documentation | 中文文档 | Examples | Changelog
Embeddable, stateful agent execution for Python.
power-loop gives application code one small interface, StatefulAgentLoop, and handles the repetitive agent runtime work around it: multi-turn LLM loops, tool calls, hooks, events, context compaction, sub-agents, retry/cancel, structured output, memory, and SQLite-backed session persistence.
It is a library, not a service or a full application framework. You keep ownership of product logic, HTTP APIs, auth, queues, RAG, UI, and deployment.
Scope: orchestration, not isolation
power-loop orchestrates the agent loop; it does not sandbox tool execution. The
built-in bash / file tools run in-process (a subprocess shell inheriting the host
environment) — convenient for trusted, local use, but not a security boundary. If your
agent runs model-authored or otherwise untrusted commands, run them in your own sandbox
(container / gVisor / microVM) and inject it via the ShellBackend seam
(runtime.exec_backend); power-loop launches the persistent shell through your backend.
Keep secrets in your orchestrator — the loop does not scrub the tool environment for you.
Install
pip install power-loop
For local development:
git clone https://github.com/PL-play/power-loop.git
cd power-loop
pip install -e ".[dev]"
Python 3.10+ is required.
Quick Example
import asyncio
from power_loop import AgentLoopConfig, StatefulAgentLoop, create_llm_service_from_env
async def main() -> None:
llm = create_llm_service_from_env()
loop = StatefulAgentLoop(
llm=llm,
db_path="./power_loop_sessions.db",
config=AgentLoopConfig(
system_prompt="You are a concise assistant.",
max_rounds=4,
),
)
sid = loop.new_session(metadata={"user_id": "demo"})
first = await loop.send("My favorite color is teal.", session_id=sid)
second = await loop.send("What is my favorite color?", session_id=sid)
print(second.final_text)
asyncio.run(main())
Configure any OpenAI-compatible endpoint with environment variables:
POWER_LOOP_BASE_URL=https://api.openai.com/v1
POWER_LOOP_API_KEY=sk-...
POWER_LOOP_MODEL=gpt-4o-mini
See Getting Started for the complete first run.
What It Provides
| Capability | Where to read more |
|---|---|
| Stateful sessions and cross-process resume | Sessions |
| Tool calling with JSON Schema validation | Tools |
| Lifecycle hooks for control flow | Hooks |
| Typed events for streaming, audit, and metrics | Events |
| Context compaction | Compaction |
Sub-agents with AgentSpec |
Sub-agents |
| Retry, timeout, and cancellation | Retry & Cancel |
| Structured JSON output | Structured Output |
| Pluggable cross-session memory | Memory |
| Provider configuration | Providers |
Per-call overrides
Build one loop and reuse it across callers; restrict tools or swap the system
prompt per send without rebuilding (the model only sees the allowed
tools). Ideal for multi-tenant hosts.
# loop registered with all tools; this run exposes only "get_weather"
await loop.send("…", session_id=sid, tools=["get_weather"])
# per-run system prompt override (precedence: per-call > session > config)
await loop.send("…", session_id=sid, system_prompt="You are a terse bot.")
The same overrides are available on send_sync(). When follow_up() is idle
and falls back to a new send, it accepts them too. A follow-up queued into an
already running call keeps that call's active tool and prompt policy.
For a multi-tenant host that reuses one registry across workspaces, build an unbound registry and supply the workspace at invocation time:
from power_loop import RuntimeEnv, create_default_tool_registry, runtime_env_context
registry = create_default_tool_registry(preset="core", bind=False)
with runtime_env_context(RuntimeEnv(workspace_dir=tenant_workspace)):
result = await registry.invoke_async("read_file", {"path": "README.md"})
See examples/23_per_send_overrides.py.
Public API
Stable imports are re-exported from power_loop:
from power_loop import (
AgentLoopConfig,
StatefulAgentLoop,
StatefulResult,
ToolDefinition,
ToolRegistry,
)
The stability tiers are:
| Tier | Meaning |
|---|---|
| Stable | Backward compatible across minor releases. Listed in power_loop.STABLE_API. |
| Provisional | Available from the top-level package during 0.x, but may change. |
| Internal | Submodule imports such as power_loop.core.*; no compatibility promise. |
See the API reference for the current surface.
Examples
The examples/ directory is ordered from minimal usage to full chatbot composition:
python examples/00_hello_world.py
python examples/02_tool_calling.py
python examples/19_full_chatbot.py
The full list is in examples/README.md.
Development
pip install -e ".[dev]"
ruff check .
pytest -q --no-real
Real LLM examples/tests use POWER_LOOP_* or the legacy OPENAI_COMPAT_* variables.
Project Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file power_loop-0.8.0.tar.gz.
File metadata
- Download URL: power_loop-0.8.0.tar.gz
- Upload date:
- Size: 134.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2b6619127619f229ed9be12f2d66d6dd41f6fc1daafe5687f1140266f14c900
|
|
| MD5 |
c4e7e729c0b40faf6ae3ce8fd8a4b72a
|
|
| BLAKE2b-256 |
f8dcec9783c63d3693d6e35a29104a8e6e8192a1e497d0fcee6c101bbf3da341
|
File details
Details for the file power_loop-0.8.0-py3-none-any.whl.
File metadata
- Download URL: power_loop-0.8.0-py3-none-any.whl
- Upload date:
- Size: 153.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ca33204ce01ca7707d1172744c183f4cef9417f6da86f955b9c8a18a96b1c29
|
|
| MD5 |
b0aedd4dbfe55e0be35732d2e4762d70
|
|
| BLAKE2b-256 |
3ba8ac24aca330edc120059eca0341a03d1abbb367138340ce576014ebe18c2e
|