Skip to main content

persona-runtime

The MIT-licensed conversation and agentic engine for Open Persona — the loop, the prompt builder, the router, and the agentic plan-act-reflect cycle.

License: MIT — free for any use, including commercial.

persona-runtime is the orchestration layer of Open Persona. It turns a persona-core persona into a running conversational agent and depends only on persona-core — no HTTP, no database, no secrets.

What it is

The runtime owns the per-turn lifecycle and the agentic loop, and nothing else. Every collaborator (the persona registry, the model tiers, the toolbox, the conversation object) is injected by the composition root — the API in production, the CLI for local use, the tests in CI. The loop itself is stateless per request.

  • ConversationLoop — the one-turn keystone: retrieve typed-memory context, manage history (summarise-and-compact at K=10, keep the last 5 turns verbatim), build the prompt, route, stream-generate with a tool-call sub-loop, and write the turn back to the episodic store.
  • PromptBuilder + RetrievedContext — assembles the system prompt from identity + constraints + retrieved chunks + the skill index, with a context-window budget reducer.
  • retrieve_context — the per-turn conditioning retrieval (identity via get_all, the rest via query), extracted so the voice trunk shares the same conditioning rather than reimplementing it.
  • RoutingRouter (a @runtime_checkable Protocol) with HeuristicRouter (rule-based, per-turn, per-persona-overridable) and UnifiedRouter (two-layer: hard constraint-filter then sweet-spot scoring with bounded fallback). Plus the opt-in IntelligentRouter: after the rules pick a tier, it scores the candidate models in that tier on cost / quality / latency (with a hard capability gate) using published metadata — deterministic, no ML, off by default, and degrading to the slot-0 model on any metadata miss.
  • TierRegistry — a lazy-cached backend registry per tier (frontier / mid / small), configured via PERSONA_{TIER}_* env triples, with small→mid→frontier fallback and cross-provider multi-model per tier.
  • AgenticLoop — the plan-act-reflect cycle: one model decides at each step whether to call a tool, ask the user, or produce a final answer, with step-history compaction at the tier budget, a cancel-token boundary, and an authoritative terminal status (completed / max_steps_reached / cancelled / error).
  • TurnLog + JSONLTurnLogWriter / MemoryTurnLogWriter — per-turn telemetry (model, tokens, cost, routing decision, latency, fallback), durable to JSONL or held in memory for tests.

Install

pip install persona-runtime          # pulls in persona-core

Python ≥ 3.11. For workspace development from the monorepo:

git clone https://github.com/yasinhessnawi1/Open-Persona.git
cd Open-Persona
uv sync --all-packages

Quickstart

persona-runtime is a library with 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, 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())

Configuration

Each tier is configured by an env triple (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 triple is the fallback when no per-tier vars are set.

Architecture role

persona-runtime 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. The voice trunk (persona-voice) reuses the runtime's reply producer so a voice turn is conditioned and routed exactly like a text turn.

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

License

persona-runtime is licensed under the MIT License — free for any use, including commercial. See LICENSE. The application layer of Open Persona (persona-api, persona-web) is separately licensed PolyForm Noncommercial 1.0.0; see the root README for the full per-package table.

Links

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

persona_runtime-1.0.0.tar.gz (245.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

persona_runtime-1.0.0-py3-none-any.whl (146.9 kB view details)

Uploaded Python 3

File details

Details for the file persona_runtime-1.0.0.tar.gz.

File metadata

  • Download URL: persona_runtime-1.0.0.tar.gz
  • Upload date:
  • Size: 245.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.9

File hashes

Hashes for persona_runtime-1.0.0.tar.gz
Algorithm Hash digest
SHA256 0a53c6f40553b4872a5184da384e14113a340dec634a6d20070662d20773fe00
MD5 9ebbdf31def27d61b25bef0ebec00d40
BLAKE2b-256 9043100a09d65291c6ac03be3484aaa4dd1f272ff50d5582593dddf993c87025

See more details on using hashes here.

File details

Details for the file persona_runtime-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for persona_runtime-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 60737e8aad2e262741193ac2e5bdf0b979222d6caf6707c8c250fb41e4f2e658
MD5 4a08716d9ef0c557c3782c29dead2a49
BLAKE2b-256 ee768d636e2d7e24330cdf26ec4026d2c1f1c226db3a759ed3508fae04b35436

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page