basic_agent¶
Level 1 · Fundamentals — the high-level SymfonicAgent in under 10 lines.
Where minimal_agent wires the low-level symfonic.core
primitives by hand, this example uses the symfonic.agent orchestration layer.
SymfonicAgent composes the graph, the 5-layer memory system, and the model
provider for you — you construct it, call run(), and read a typed
AgentResponse.
- Lines: ~43
- Prerequisites: none to run as-is (uses
MockModelProvider); a real provider needspip install symfonic-core[anthropic]+ an API key - Key concepts:
SymfonicAgent,FrameworkConfig,FrameworkTenantScope,AgentResponse
Run it¶
Installed via pip? Copy this example into your project with the CLI (no checkout needed):
pip install "symfonic-core[cli]"
symfonic examples add basic_agent
python basic_agent/basic_agent.py
Or, from a source checkout (run from the repo root):
Expected output:
Full code¶
"""Basic SymfonicAgent example -- multi-memory agent in <10 lines.
Usage:
python -m examples.agent.basic_agent
Requires:
pip install symfonic-core[anthropic]
export ANTHROPIC_API_KEY=sk-...
"""
from __future__ import annotations
import asyncio
from symfonic.agent.config import FrameworkConfig
from symfonic.agent.engine import SymfonicAgent
from symfonic.agent.types import FrameworkTenantScope
from symfonic.core.testing import MockModelProvider
async def main() -> None:
# Use MockModelProvider for demo (no API key needed)
# Replace with AnthropicProvider() for real usage:
# from symfonic.core.providers import AnthropicProvider
# provider = AnthropicProvider()
provider = MockModelProvider(response="I remember our conversation!")
agent = SymfonicAgent(
model_provider=provider,
config=FrameworkConfig(auto_hydrate=False, auto_consolidate=False),
)
scope = FrameworkTenantScope(tenant_id="demo-tenant")
response = await agent.run("What do you remember?", scope=scope)
print(f"Response: {response.final_response}")
print(f"Run ID: {response.run_id}")
print(f"Duration: {response.duration_ms:.1f}ms")
print(f"Memory entries used: {response.memory_entries_used}")
if __name__ == "__main__":
asyncio.run(main())
Step by step¶
1. Choose a provider¶
Same ModelProvider seam as minimal_agent. To go live,
swap the two commented lines:
from symfonic.core.providers import AnthropicProvider
provider = AnthropicProvider() # reads ANTHROPIC_API_KEY from env
Nothing else on the page changes — that is the point of the provider protocol.
2. Construct the agent¶
agent = SymfonicAgent(
model_provider=provider,
config=FrameworkConfig(auto_hydrate=False, auto_consolidate=False),
)
SymfonicAgent is the batteries-included orchestrator. FrameworkConfig layers
framework behavior (memory hydration, consolidation, lazy loading) on top of the
core AgentConfig. Here auto_hydrate=False and auto_consolidate=False keep
the demo self-contained — no memory backends are read or written. Flip them on
once you attach real stores.
3. Define a tenant scope¶
Every run is scoped to a tenant. FrameworkTenantScope is how the framework
isolates one customer's memory, documents, and skills from another's. Multi-tenant
isolation is a first-class concept — see
Hierarchical Tenant Scope.
4. Run and read the typed response¶
response = await agent.run("What do you remember?", scope=scope)
print(f"Response: {response.final_response}")
print(f"Run ID: {response.run_id}")
print(f"Duration: {response.duration_ms:.1f}ms")
print(f"Memory entries used: {response.memory_entries_used}")
Unlike the low-level runtime (which returns a raw state dict), SymfonicAgent.run
returns a typed AgentResponse. Beyond final_response it carries observability
fields (run_id, duration_ms, memory_entries_used) and — when you ask for it
— a validated structured payload. See
Structured Output.
Low-level vs high-level¶
minimal_agent (core) |
basic_agent (agent) |
|
|---|---|---|
| Entry type | AgentRuntime |
SymfonicAgent |
| You wire | graph, deps, stores | just the provider |
| Memory layers | none by default | 5-layer HMS available |
| Return | state dict |
typed AgentResponse |
| Best for | learning internals, custom graphs | building applications |
What to try next¶
- Add persistent memory and turn
auto_hydrateon → memory_agent - Delegate work to child agents → sub_agents
- Ask for a validated object back → Structured Output