Prepared Turn Context
One immutable plan per agent turn, shared by every runtime (native, plugin, CLI).
Build one frozen turn plan from an Agent and prompt — any runtime (native, plugin, CLI) executes the same context.
from praisonaiagents import Agent
from praisonaiagents.runtime import default_context_builder
agent = Agent(name="Researcher", instructions="Find facts and cite sources.")
context = default_context_builder.build_context(agent, "Who built the Eiffel Tower?")
print(context.to_dict())The user sends a prompt; the runtime builds one shared PreparedTurnContext for the turn.
Quick Start
- Simple Usage
Inspect what the agent will send on the next turn:
python from praisonaiagents import Agent from praisonaiagents.runtime import default_context_builder agent = Agent(name="Writer", instructions="Summarise pull requests.") context = default_context_builder.build_context(agent, "Summarise this PR") print(context.has_tools(), context.get_message_count()) print(context.to_dict()) - With Configuration
Run the same context through your own runtime by implementing
TurnRuntimeProtocol:python import asyncio from typing import List from praisonaiagents import Agent from praisonaiagents.runtime import ( default_context_builder, PreparedTurnContext, RuntimeMode, ) class MyHarness: async def run_turn(self, context: PreparedTurnContext) -> str: return f"Handled turn {context.correlation.turn_id} with {context.get_message_count()} messages." def supports_runtime_mode(self, mode: RuntimeMode) -> bool: return mode in (RuntimeMode.SYNC, RuntimeMode.ASYNC) def get_supported_modes(self) -> List[RuntimeMode]: return [RuntimeMode.SYNC, RuntimeMode.ASYNC] agent = Agent(name="Writer", instructions="Summarise pull requests.") context = default_context_builder.build_context(agent, "Summarise this PR") asyncio.run(MyHarness().run_turn(context))
How It Works
| Stage | What happens |
|---|---|
| Build | Resolves model, tools (kwarg → agent.tools), transcript, delivery, correlation |
| Freeze | Context is immutable after construction |
| Execute | Any TurnRuntimeProtocol runs the same plan |
Key imports: PreparedTurnContext, default_context_builder, RuntimeMode, DeliveryChannels.
Tool Resolution
build_context(agent, prompt, tools=…) resolves tools from the kwarg first, then the agent:
| Call | Result |
|---|---|
build_context(agent, prompt) | Uses agent.tools |
build_context(agent, prompt, tools=None) | Uses agent.tools |
build_context(agent, prompt, tools=[]) | No tools this turn (explicit disable) |
build_context(agent, prompt, tools=[fn]) | Overrides agent.tools with [fn] |
from praisonaiagents import Agent
from praisonaiagents.runtime import default_context_builder
def lookup(topic: str) -> str:
"""Return a short fact about the topic."""
return f"fact about {topic}"
agent = Agent(name="Researcher", instructions="Cite facts.", tools=[lookup])
# 1. Uses agent.tools
ctx1 = default_context_builder.build_context(agent, "Tell me about Paris")
assert ctx1.has_tools()
# 2. tools=None also uses agent.tools (same as omitting the kwarg)
ctx2 = default_context_builder.build_context(agent, "Tell me about Paris", tools=None)
assert ctx2.has_tools()
# 3. tools=[] explicitly disables tools for this turn
ctx3 = default_context_builder.build_context(agent, "Just chat", tools=[])
assert not ctx3.has_tools()Configuration Options
| Field | Type | Notes |
|---|---|---|
runtime_mode | RuntimeMode | SYNC, ASYNC, STREAM, ASYNC_STREAM |
delivery | DeliveryChannels | Required for streaming modes |
correlation | SessionCorrelation | session_id, turn_id, agent_id, run_id |
STREAM and ASYNC_STREAM raise ValueError if delivery.has_streaming() is false.
Best Practices
Treat context as read-only
Fields are frozen — mutate via hooks, not assignment.
Build one context per turn
Do not cache plans across turns in multi-agent setups.
Reuse default_context_builder
It is a module-level singleton — no need to instantiate your own builder.
Match runtime_mode to delivery
Enable DeliveryChannels(enable_streaming=True, ...) before choosing stream modes.
Disable tools with an empty list, not None
tools=None (or omitting the kwarg) uses agent.tools. Pass an explicit empty list to run a turn with no tools.