Skip to content

real_agent

Level 6 · Real LLM — the first example that talks to an actual model.

Every other curated example runs on MockModelProvider so it's free and deterministic. real_agent calls a live model: it prefers the ChatGPT subscription credential written by codex login, then falls back to ANTHROPIC_API_KEY. It's the bridge from "the framework runs" to "the framework answers."

  • Prerequisites: pip install "symfonic-core[openai]" + codex login, or pip install "symfonic-core[anthropic]" + ANTHROPIC_API_KEY
  • Key concepts: automatic provider selection, CodexOAuthProvider, AnthropicProvider

Get it and run it

Installed via pip? Copy it in and run against a real model — no checkout:

pip install "symfonic-core[cli,openai]"
codex login
symfonic examples add real_agent
python -m real_agent "What is the largest planet in our solar system?"

Or from a source checkout (run from the repo root):

python -m examples.real_agent "Your question here"

Expected output:

Provider: Codex OAuth (gpt-5.6-sol)
Query: What is the largest planet in our solar system?
---
Response: Jupiter is the largest planet in our solar system.
Nodes: ['react']

Full code

"""Real LLM example — uses Codex OAuth or Anthropic's Claude API.

Provider selection defaults to ``auto``: Codex OAuth from ``codex login`` is
preferred, then ``ANTHROPIC_API_KEY`` is used as a fallback. Override with
``SYMFONIC_EXAMPLE_PROVIDER=codex`` or ``=anthropic``.

Usage: python -m examples.real_agent
       python -m examples.real_agent "Your custom question here"
"""

import asyncio
import sys

from symfonic.core import (
    AgentGraph,
    AgentRuntime,
    BaseAgentDeps,
)

from .provider import select_live_provider


async def main() -> None:
    selected = select_live_provider()
    if selected is None:
        sys.exit(1)

    query = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "What is symfonic? Make up a creative answer in 2 sentences."

    config = selected.config
    deps = BaseAgentDeps(ModelProvider=selected.provider)
    graph = AgentGraph()
    runtime = AgentRuntime(graph=graph, deps=deps, config=config)

    print(f"Provider: {selected.label}")
    print(f"Query: {query}")
    print("---")

    result = await runtime.run(query)

    print(f"Response: {result['final_response']}")
    print(f"Nodes: {result['node_execution_log']}")


if __name__ == "__main__":
    asyncio.run(main())

Step by step

1. Select credentials and provider

selected = select_live_provider()
if selected is None:
    sys.exit(1)

In auto mode, the selector first checks the environment and ~/.codex/auth.json for a Codex credential. If the [openai] extra or Codex credential is unavailable, it uses ANTHROPIC_API_KEY. Optional .env loading remains supported when python-dotenv is installed.

Force a provider when testing a specific wire path:

SYMFONIC_EXAMPLE_PROVIDER=codex python -m real_agent
SYMFONIC_EXAMPLE_PROVIDER=anthropic python -m real_agent

2. Wire the selected provider and its model

deps = BaseAgentDeps(ModelProvider=selected.provider)
runtime = AgentRuntime(graph=graph, deps=deps, config=selected.config)

Provider and model travel together so Codex never receives Claude's default model name, and an explicit Anthropic run keeps its Claude model.

3. Run and read the answer

result = await runtime.run(query)
print(f"Response: {result['final_response']}")

Same AgentRuntime.run as the mock examples; now final_response carries a genuine model completion. Pass a question on the command line (python -m real_agent "...") or it uses a built-in default.

Going further

  • Swap the provider for another vendor — OpenRouterProvider, AWSBedrockProvider — the rest of the code is unchanged. See Model Providers.
  • Add memory so the model reasons over stored context → see real_agent_with_memory in the Examples Index.
  • Ask for a validated object back → Structured Output.

See also