Skip to content

Add agent-supervisor example - #903

Open
shahryarkhalid-cmd wants to merge 1 commit into
apache:mainfrom
shahryarkhalid-cmd:agent-supervisor-example
Open

shahryarkhalid-cmd wants to merge 1 commit into
apache:mainfrom
shahryarkhalid-cmd:agent-supervisor-example

Conversation

@shahryarkhalid-cmd

Copy link
Copy Markdown

Fleshes out the agent_supervisor.py template in examples/templates/ into a
full, runnable example (examples/agent-supervisor/). Ports LangGraph's
"agent supervisor" pattern to Burr: an LLM-driven supervisor that routes
between a researcher agent (web search) and a coder agent (python
execution / charting), deciding the next step at each turn rather than using
fixed transitions.

Scope was discussed beforehand with @Stefan K on Discord, who suggested this
be built as a standalone example that implements the existing template,
rather than modifying templates/ directly.

Changes

  • New examples/agent-supervisor/ folder, following the standard example
    structure:
    • application.py -- supervisor_agent, researcher, coder, tool_node,
      and terminal actions, wired up with ApplicationBuilder. Uses the plain
      OpenAI SDK for LLM calls (matching examples/email-assistant's style)
      rather than LangChain or Hamilton, to keep the example dependency-light.
    • README.md -- explains the example and how it relates to the template
      and to examples/multi-agent-collaboration.
    • requirements.txt, notebook.ipynb, __init__.py, statemachine.png
      (generated via app.visualize()).

This differs from examples/multi-agent-collaboration (which covers the same
researcher/coder domain) in that routing between agents is decided by the
supervisor's own LLM call at each step, rather than fixed transitions --
demonstrating the supervisor pattern specifically, as the template intends.

How I tested this

  • Verified the Burr application graph builds correctly, with all actions and
    transitions wired as expected.
  • Verified app.visualize() produces the expected state diagram (included as
    statemachine.png).
  • Ran the full application end-to-end against Groq's OpenAI-compatible
    endpoint (as a stand-in, since I didn't have an OpenAI key on hand) to
    validate the supervisor's routing logic, the tool-calling loop, and
    termination behavior all work correctly.
  • Have not yet run it against the actual OpenAI API the shipped code targets
    -- happy to do that and confirm, or if a reviewer can sanity-check with
    their own key that'd also be appreciated.
Screenshot 2026-08-29 191150

Notes

  • Open to feedback on the researcher/coder domain choice, or on the routing
    prompt in supervisor_agent if it should be tuned further.
  • TAVILY_API_KEY is optional -- without it, web_search returns a
    placeholder string so the example still runs.

Checklist

  • PR has an informative and human-readable title
  • Changes are limited to a single goal (new example only, no unrelated changes)
  • Code passed the pre-commit check & code is left cleaner/nicer than when first encountered.
  • Any change in functionality is tested
  • New functions are documented (with a description, list of inputs, and expected output)
  • Placeholder code is flagged / future TODOs are captured in comments
  • Project documentation has been updated if adding/changing functionality.

@github-actions github-actions Bot added the area/examples Relates to /examples label Aug 29, 2026

@skrawcz skrawcz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — nice, clean use of Burr (state schema, reads/writes, transitions all follow the agent_supervisor.py template and multi-agent-collaboration conventions well). I ran it through a worktree locally (mocked LLM calls to exercise the full supervisor → agent → tool_node loop) and left a few inline comments on things worth fixing before merge.

Also, examples/README.md's index doesn't include this new example yet — every other example is listed there alongside a one-line description, worth adding this one too.

Otherwise this is a solid, well-documented addition. Happy to take another look once the inline items are addressed.

"args": tool_call.function.arguments,
}
)
new_message = {"role": "assistant", "content": message.content or "", "name": sender}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: tool-call round-trip bug. This stored assistant message drops the tool_calls field from the OpenAI response:

new_message = {"role": "assistant", "content": message.content or "", "name": sender}

tool_node later appends a {"role": "tool", "tool_call_id": ...} message referencing that call, but OpenAI's Chat Completions API requires the immediately-preceding assistant message to carry a matching tool_calls array — otherwise it 400s. Since this field is stripped, the example will likely fail against real api.openai.com the first time a tool is called (this may be why it worked against Groq's endpoint but wasn't verified against OpenAI itself, per the PR description). Suggested fix:

new_message = {
    "role": "assistant",
    "content": message.content or "",
    "name": sender,
    **({"tool_calls": [tc.model_dump() for tc in message.tool_calls]} if message.tool_calls else {}),
}

Would appreciate a live run against real OpenAI (not just Groq) after this fix, since that's the API the example is nominally demonstrating.

app.visualize(
output_file_path="statemachine", include_conditions=True, view=True, format="png"
)
app.run(halt_after=["terminal"]) No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-commit isn't passing on this file (confirmed locally): black --line-length=100 would reformat the app.visualize(...) call above to fit on one line, and flake8 fails with W292 no newline at end of file here. Running pre-commit run --files examples/agent-supervisor/* should surface/fix both.

return _run_agent(
state,
system_message="You are a researcher. Use web_search to gather accurate "
"information for the coder to use. Say FINAL ANSWER when done.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit (optional): this and the coder prompt below say "Say FINAL ANSWER when done," but nothing in the code actually checks for that phrase — the supervisor's own LLM call decides FINISH independently. Looks vestigial from the multi-agent-collaboration pattern (where it was checked via expr). Not a bug, just a bit misleading — could drop it for clarity.

burr[start]
openai
tavily-python
python-dotenv No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python-dotenv isn't imported/used anywhere in application.py or notebook.ipynb. Either wire it up (load_dotenv()) or drop the dependency. Also missing a trailing newline (pre-commit's end-of-file-fixer will flag this).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/examples Relates to /examples

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants