Agent Core Runtime
Agent Core Runtime is a small Python runtime for building tool-using agents from a few explicit pieces: Node, Flow, RunContext, Tool, and Agent.
Chinese README · API Reference · Design · Changelog · Contributing
Why This Exists
The runtime is meant to be easy to read and easy to replace:
Nodeis one unit of work.Flowconnects nodes by action names.Agentis also aNode, so an agent can run alone or sit inside a larger flow.RunContextcarries scoped messages, one event stream, metadata, artifacts, and cumulative model usage for one run.payloadcarries explicit business data between nodes and is returned by the flow.@toolturns typed Python functions into OpenAI-compatible tool schemas.LLMis the default OpenAI-compatible model adapter. Configuration comes from constructor arguments or the process environment.
You can build a normal chat agent in one declaration, or wire your own flow when the loop needs custom logic.
Scope and Boundary
The runtime's story is deliberately small: it is the minimal unit that runs one agent, and the same pieces compose into workflows and multi-agent systems because Agent is a Node. It owns execution — flows, model and tool calls, and the per-run RunContext.
Everything that makes a product an agent product lives above it, in a harness: prompt layering, session persistence, context compaction, memory, permissions, verification loops, and user surfaces. Friday is one such harness; its architecture doc describes this boundary from the consumer side.
The contract for harness authors: drive the runtime through its public API — compose flows from published nodes, run them via Agent, and use RunContext through add_message / get_messages / metadata / artifacts / emit / observe / notify, usage snapshots, and the event subscriptions. When conversation history must change (compaction, resume), build a fresh context and replay messages through that API instead of editing the runtime's internal bookkeeping.
Runtime Shape
flowchart TD
App["Application"] --> Agent["Agent"]
Agent -->|"direct chat"| BuiltIn["built-in model/tool loop"]
Agent -->|"custom"| Flow["Flow"]
Agent -. "Agent is a Node" .-> OuterFlow["Another Flow"]
Flow --> Data["payload"]
Data --> Node["Node"]
Node -->|"action + payload"| Next["Next Node"]
Next --> Node
Flow -. "runtime context" .-> Context["RunContext"]
Context --> Messages["messages"]
Context --> Events["events"]
Context --> Usage["usage"]
Context --> Artifacts["artifacts"]
Context --> Metadata["metadata"]
BuiltIn --> ModelNode["ModelNode"]
ModelNode --> ChatModel["ChatModel"]
ChatModel --> OpenAI["OpenAI-compatible API"]
ModelNode --> Router["ToolRouterNode"]
Router -->|"tool_calls"| ToolNode["ToolCallNode"]
ToolNode --> Tools["@tool functions"]
ToolNode --> ModelNode
Router -->|"no tool_calls"| Answer["answer"]
Package Layout
src/agent_core/
agent.py # Agent: direct chat runner and embeddable Node
core/ # Node, Flow, RunContext, trace events
llm/ # LLM, ChatModel protocol, ModelNode, router
tools/ # @tool, ToolExecutor, ToolCallNode
examples/
01_basic_agent.py # Node and Flow only
02_custom_prompt.py # Real model call with a custom prompt
03_custom_tool.py # Tool schema and execution
04_tool_agent.py # Manually wired model-tool-model loop
05_custom_agent.py # Direct Agent(instructions, tools)
tests/
Install
uv add friday-agent-core
Or with pip:
pip install friday-agent-core
The distribution name is friday-agent-core; the import name stays agent_core. To develop the runtime itself, clone this repository and run uv sync.
Verify the installed package without an API key or model call:
python -c "import agent_core; print(agent_core.__version__)"
python -m agent_core --version
python -m agent_core check
check executes a local Node -> Flow -> RunContext smoke test. It confirms
that the installed runtime can execute; provider credentials and model
connectivity belong to the consuming harness and are intentionally not tested.
Set model credentials in the process environment or pass them to LLM(...):
$env:LLM_API_KEY = "..."
$env:LLM_BASE_URL = "https://api.example.com"
$env:LLM_MODEL = "model-name"
Quick Agent
from typing import Annotated
from agent_core import Agent, tool
@tool(description="Search private notes.")
def search_notes(topic: Annotated[str, "Topic to search."]) -> dict[str, str]:
return {"topic": topic, "result": "mock note"}
agent = Agent(
instructions="You are a concise research assistant.",
tools=[search_notes],
stream=True,
chat_kwargs={"tool_choice": "auto"},
)
context = agent.new_context()
answer = agent.chat("Draft a short evaluation plan.", context=context)
print(answer)
Custom Flow
Use explicit nodes when the agent loop is not a simple chat loop:
from agent_core import Agent, CallableNode, Flow
def classify(payload: dict) -> tuple[str, dict]:
return "question" if payload["text"].endswith("?") else "statement", payload
def answer(payload: dict) -> dict:
payload["answer"] = "received"
return payload
router = CallableNode(classify)
answer_node = CallableNode(answer)
router - "question" >> answer_node
router - "statement" >> answer_node
result = Agent(Flow(router)).run({"text": "Hello?"})
print(result.payload["answer"])
Because Agent is a Node, you can compose agents:
researcher = Agent(model=model, instructions="Research.", tools=[search_notes])
writer = Agent(model=model, instructions="Write the final response.")
researcher - "final" >> writer
team = Agent(Flow(researcher))
When an Agent is used as a node, it exposes the final action from its inner flow. Pass action="some_action" only when you want to force a fixed outward action.
Examples
Run the examples in order:
uv run python examples/01_basic_agent.py
uv run python examples/02_custom_prompt.py
uv run python examples/03_custom_tool.py
uv run python examples/04_tool_agent.py --context messages
uv run python examples/05_custom_agent.py
LLM examples stream by default. Use --no-stream to print full responses after completion.
04_tool_agent.py also supports:
--interactive: start an interactive loop.--context summary|messages|events|artifacts|all|none: inspect the run context.
In your own agent, use Agent(..., stream=False) to disable streaming by default, or override one call with agent.chat(..., stream=False).
Runtime Events
Each run returns a RunContext:
result = agent.run({"text": "hello"})
messages = result.context.messages
events = [event.to_dict() for event in result.context.events]
usage = result.usage.to_dict()
Streaming OpenAI-compatible models emit model.delta for answer text and
model.reasoning.delta for provider reasoning, allowing a harness to render
the two channels independently.
RunUsage accumulates every model request in the flow, including streamed responses. Input and output totals are exact when every provider response includes usage; otherwise the totals are reported as unknown instead of a misleading partial sum.
Nodes can also write to the active context:
from agent_core import get_current_context
context = get_current_context()
if context:
context.set_artifact("note", "saved")
Keep business state in payload and runtime/session data in RunContext. For example, a router decision, plan, or artifact path belongs in result.payload; streamed model deltas, messages, UI events, and artifact metadata belong in result.context. Large artifacts such as full reports should live in files, databases, or object storage, with payload/context carrying references rather than the full content.
In multi-agent flows, RunContext is shared for events, usage, artifacts, and metadata, but each Agent gets an isolated message scope for LLM input. This keeps the observable run unified without leaking one agent's prompt/history into another agent's model call.
Validate
uv run python -m unittest discover -s tests
uv run python -m compileall src tests examples
Metadata
Release files for friday-agent-core 0.1.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| friday_agent_core-0.1.9.tar.gz | 59.5 kB | With provenance | Details for friday_agent_core-0.1.9.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| friday_agent_core-0.1.9-py3-none-any.whl | Python 3 | none | any | Details for friday_agent_core-0.1.9-py3-none-any.whl |
Total release size: 86.4 kB
Release files / friday_agent_core-0.1.9.tar.gz
| Download URL | friday_agent_core-0.1.9.tar.gz |
|---|---|
| Size | 59.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7c546570acd4c318e913a199c04afeebf6e52a53bfdd560284e69ed52c55180
|
|
BLAKE2b-256 checksum How to use checksums |
045bc553780540fd38682940b63fa6309e6694fe52eacb8129093a6ba264d1bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency logRelease files / friday_agent_core-0.1.9-py3-none-any.whl
| Download URL | friday_agent_core-0.1.9-py3-none-any.whl |
|---|---|
| Size | 26.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
da6353ccd6f005c5d174c2f0cb8d756957f65a9f355b3006150121d71faf4461
|
|
BLAKE2b-256 checksum How to use checksums |
e2b255d412c6f938a7fc1aa24c6462209b6bdf68eb7957e9f4ecd84fb6514f59
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency logSecurity for friday-agent-core 0.1.9
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for friday_agent_core-0.1.9.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.