Generation loop, router, and agentic engine for persona-core.
Project description
persona-runtime
Conversation loop, prompt builder, router, and agentic engine for Persona. Source-available; noncommercial use only.
Status: PolyForm Noncommercial 1.0.0 · Source Available (Noncommercial Use Only)
What it is
persona-runtime is the orchestration layer that turns a persona-core
persona into a running conversational agent. It owns six things and nothing
else:
ConversationLoop— the one-turn keystone: retrieve typed-memory context, manage history (summarise-and-compact at K=10, keep last 5 verbatim), build the prompt, route, stream-generate with a tool-call sub-loop, write the turn back to the episodic store.PromptBuilder+RetrievedContext— assembles the system prompt from identity + constraints + retrieved chunks + skill index, with a context-window budget reducer.- Routing —
Router(@runtime_checkableProtocol) with two concrete implementations:HeuristicRouter(rule-based, per-turn, per-persona-overridable) andUnifiedRouter(two-layer: hard-filter viaapply_constraint_filterthen sweet-spot scoring, with bounded fallback and per-tier metadata). TierRegistry— lazy-cached backend registry per tier (frontier/mid/small); configured viaPERSONA_{TIER}_*env triples; small→mid→frontier fallback; cross-provider multi-model per tier (Spec 20).AgenticLoop— the plan-act-reflect cycle inpersona_runtime.agentic: one model decides at each step whether to call a tool, ask the user, or produce a final answer;[ASK_USER]/[FINAL]markers as the primary classification signal; step-history compaction at the tier budget; cancel-token boundary; terminal status (completed/max_steps_reached/cancelled/error) authoritative.TurnLog+JSONLTurnLogWriter/MemoryTurnLogWriter— per-turn telemetry record (model, tokens, cost, routing decision, latency, fallback) durable to JSONL or held in memory for tests.
The runtime depends only on persona-core; it does not depend on the API
or web app. The composition root (the API in production, the CLI for
local use, the tests in CI) owns the Conversation object and the
TierRegistry lifecycle — the loop itself is stateless per request.
Install
From PyPI (planned):
pip install persona-runtime
Workspace development:
git clone https://github.com/yasinhessnawi1/Open-Persona.git
cd open-persona
uv sync --all-packages
Run
persona-runtime is a library — no CLI of its own. Compose it on top of
persona-core:
import asyncio
from pathlib import Path
from persona.schema.persona import Persona
from persona.schema.conversation import Conversation, ConversationMessage
from persona.registry import PersonaRegistry
from persona.stores.chroma import ChromaMemoryStore
from persona.tools.toolbox import Toolbox
from persona_runtime import (
ConversationLoop, PromptBuilder, Router, TurnLog, tier_registry_from_env,
)
async def main() -> None:
persona = Persona.from_yaml(Path("examples/astrid_tenancy_law.yaml"))
registry = PersonaRegistry(store=ChromaMemoryStore.local("./.persona-data"))
registry.load(persona)
tiers = tier_registry_from_env()
loop = ConversationLoop(
registry=registry,
tiers=tiers,
router=Router(),
prompt_builder=PromptBuilder(),
toolbox=Toolbox.empty(),
)
conversation = Conversation.new(persona_id=persona.id)
user = ConversationMessage(role="user", content="Hva sier husleieloven om mugg?", created_at=None)
async for chunk in loop.turn(conversation, user):
print(chunk.delta, end="", flush=True)
await tiers.aclose()
asyncio.run(main())
Env vars (per tier; see .env.example at the repo root):
PERSONA_FRONTIER_PROVIDER=anthropic PERSONA_FRONTIER_MODEL=claude-opus-...
PERSONA_MID_PROVIDER=deepseek PERSONA_MID_MODEL=deepseek-chat
PERSONA_SMALL_PROVIDER=groq PERSONA_SMALL_MODEL=llama-...
A single PERSONA_PROVIDER + PERSONA_MODEL + PERSONA_API_KEY pair is
the fallback when no per-tier vars are set.
Test
uv run pytest packages/runtime # unit (default)
uv run pytest packages/runtime -m integration # integration
uv run mypy packages/runtime/src
uv run ruff check packages/runtime
Architecture role
persona-runtime is layer 3 of the Open Persona stack. It sits directly
above persona-core and below persona-api; the API composes the
runtime, attaches it to HTTP routes, and persists the per-request state
(conversation, run, turn-log, event bus). The runtime contains zero HTTP,
zero database client, zero secrets — every collaborator is injected by the
composition root.
Contribute
Contributions welcome under the same PolyForm Noncommercial 1.0.0 license. The package is source-available for noncommercial use; commercial use requires a separate license — contact the rights holder. Issues and pull requests welcome at github.com/yasinhessnawi1/Open-Persona. See CHANGELOG.md for the spec-by-spec history.
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 persona_runtime-0.1.0.tar.gz.
File metadata
- Download URL: persona_runtime-0.1.0.tar.gz
- Upload date:
- Size: 190.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7fdff87f0b6e77fbe04458d7848549d4ec4fa25a1d335c72d8f8306238da427
|
|
| MD5 |
d15dec2a064d92fcedbce943b41c4da0
|
|
| BLAKE2b-256 |
0cc4dafbef8dbb06aca00bdd61ae46adf1bafbdab988058cd72c303af4fa045f
|
File details
Details for the file persona_runtime-0.1.0-py3-none-any.whl.
File metadata
- Download URL: persona_runtime-0.1.0-py3-none-any.whl
- Upload date:
- Size: 111.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c40034e5289f44e4f2be449fc6d224de17c36c75a9bf9d2f8fcf41d7f75945ab
|
|
| MD5 |
7a5b13cefdb0affccb52d34e9ba6ff6b
|
|
| BLAKE2b-256 |
44e03a857202c3abb0e4f065b34b97ea752a8b2abdf6fa0beace01c9e102ab95
|