Running Your Agents π
How to trigger agent runs, stream tokens, hook into execution events, and capture results.
Running a Kern Agent kicks off a stateful orchestration loop. Behind the scenes:
- Context Assembly: The agent builds the conversation payload (system prompt, user messages, history context, database preferences, and session variables).
- Model Reasoning: This packet is sent to your model.
- Tool Loop: If the model decides it needs to use a tool, it calls the tool. The agent executes it, appends the result, and sends it back to the model.
- Final Delivery: Once the model is done looping, the agent wraps up the execution and returns the final answer.
Let's look at how to trigger and control this execution!
π Basic Execution
Trigger your agent using the synchronous Agent.run() method. This returns a RunOutput helper object:
1from kern.agent import Agent, RunOutput2from kern.models.openai import OpenAIChat3from kern.tools.hackernews import HackerNewsTools4from kern.utils.pprint import pprint_run_response56# Wire up the agent using a local Ollama model7agent = Agent(8 model=OpenAIChat(id="llama3.2:3b", base_url="http://localhost:11434/v1"),9 tools=[HackerNewsTools()],10 instructions="Give a short status report.",11 markdown=True,12)1314# Fire! π―15response: RunOutput = agent.run("Show me trending topics on HackerNews")1617# Print the response nicely formatted as markdown18pprint_run_response(response, markdown=True)π¦ What's inside RunOutput?
When you call Agent.run(), you get back a RunOutput object containing rich metadata about the run. Here are the most useful attributes:
content: The text response returned by the model.run_id: A unique UUID for tracking this specific run.session_id: The ID of the session (useful for history).user_id: The ID of the user who triggered the run.messages: The complete list of messages (prompts, tool calls, and tool outputs) sent to and from the model.metrics: Token usage counts, execution durations, and tool metrics.
π Streaming Text Response
For real-time user interfaces, you want to stream tokens as they are generated by the model. Just pass stream=True:
1from typing import Iterator2from kern.agent import Agent, RunOutputEvent, RunEvent3from kern.models.openai import OpenAIChat45agent = Agent(6 model=OpenAIChat(id="llama3.2:3b", base_url="http://localhost:11434/v1"),7 instructions="You are a poet.",8)910# Stream the text chunks as they arrive π11stream: Iterator[RunOutputEvent] = agent.run("Write a haiku about local LLMs", stream=True)12for chunk in stream:13 if chunk.event == RunEvent.run_content:14 print(chunk.content, end="", flush=True)π‘ Rich Event Streams
If you are building a custom UI (like a web dashboard or agent console), you might want to show the user exactly what the agent is doing in real-time (e.g. "Calling HackerNews API", "Thinking...").
Set stream_events=True to receive a stream containing all system events (tool starts, tool completions, reasoning steps, memory updates, etc.):
1from kern.agent import Agent, RunEvent2from kern.models.openai import OpenAIChat3from kern.tools.hackernews import HackerNewsTools45agent = Agent(6 model=OpenAIChat(id="llama3.2:3b", base_url="http://localhost:11434/v1"),7 tools=[HackerNewsTools()],8)910# Listen to everything happening under the hood π‘11stream = agent.run("Summarize HackerNews news", stream=True, stream_events=True)1213for chunk in stream:14 if chunk.event == RunEvent.run_content:15 print(chunk.content, end="", flush=True)16 elif chunk.event == RunEvent.tool_call_started:17 print(f"\n[π οΈ Tool Started] Running: {chunk.tool.tool_name}...")18 elif chunk.event == RunEvent.tool_call_completed:19 print(f"\n[β
Tool Done] Got output length: {len(chunk.tool.tool_output)}")π Core Event Reference
Here are the system event types you can listen to in your event loops:
| Event Group | Event Type | Description |
|---|---|---|
| Lifecycle | RunStarted | The engine has booted up for this run. |
RunCompleted | The run finished successfully. | |
RunError | An exception was raised during execution. | |
RunCancelled | The execution was aborted. | |
| Output | RunContent | A text chunk generated by the model. |
RunContentCompleted | Model has finished generating response text. | |
| Tools | ToolCallStarted | The agent is executing a tool function. |
ToolCallCompleted | The tool function has returned its output. | |
| Reasoning | ReasoningStarted | The model is performing thinking steps. |
ReasoningStep | A reasoning trace chunk has arrived. | |
ReasoningCompleted | Thinking process completed. | |
| Memory | MemoryUpdateStarted | Extracted facts are being updated. |
MemoryUpdateCompleted | Memory transaction saved to database. |
π§ Run Context Configuration
π€ User & Session Association
Group runs by user and thread to maintain session memory across requests:
1agent.run("My name is Alice", user_id="user_42", session_id="thread_abc")πΌοΈ Multimodal Inputs
Send images, audio, video, or files along with the run instruction:
1from kern.media import Image2agent.run("Describe this layout", images=[Image(url="https://example.com/mockup.png")])π― Custom Event Types
Define and yield custom telemetry data structures from your tools:
1from dataclasses import dataclass2from kern.run.agent import CustomEvent34@dataclass5class JobStatusEvent(CustomEvent):6 status_msg: str78# Inside a custom tool:9# yield JobStatusEvent(status_msg="Connecting to cluster...")βΈοΈ Pause, Cancel & Background Runs
- HITL (Human-In-The-Loop): Pause execution for user approval. Resume with
Agent.continue_run(). See Human-in-the-Loop Guides. - Abortion: Cancel a running loop using
Agent.cancel_run(). See Run Cancellation Guides. - Async Backgrounds: Set
background=Trueto execute agents as persistent background processes. See Background Execution Guides.