LangGraph-inspired Orchestration LLM Building Block for Mesa prototype
PR: LangGraph-inspired LLM Orchestration Building Block for Mesa
Summary
This PR adds a new orchestration framework to Mesa, enabling modular and declarative reasoning capabilities for agents. Inspired by LangGraph’s execution model, it introduces a graph-based orchestration system where agents can follow structured decision-making workflows using LLMs, rule-based functions, or hybrid reasoning tools. The orchestrator integrates cleanly into Mesa’s agent lifecycle and supports future extensions such as multi-agent collaboration and supervisor-directed task delegation.
By incorporating support for large language models (LLMs), this orchestration framework enables agents to reason using natural language, plan with greater abstraction, and respond adaptively to dynamic goals. LLMs provide an expressive and flexible reasoning substrate that opens up new avenues for research in agent-based cognition, collaboration, and behavior modeling.
Motivation
Mesa excels at modeling individual agents and their interactions over time. However, when it comes to simulating complex cognition, multi-step reasoning, or integrating language-based agents (e.g. LLMs), current approaches often require entangling logic directly within agent classes, resulting in:
- Rigid, hard-to-extend logic
- Limited modularity across reasoning strategies
- Difficulty scaling to richer agent behaviors such as planning, memory, or natural language understanding
This orchestration layer addresses these challenges by:
- Providing agents a dedicated structure to manage cognitive workflows
- Separating reasoning tools from agent class logic
- Supporting conditional branching between reasoning steps using a state-driven graph
- Making it simple to invoke LLMs within well-scoped reasoning steps without cluttering agent definitions
Implementation
The implementation introduces the following core class:
Orchestrator
A lightweight class that defines and executes state-driven graphs.
class Orchestrator:
def __init__(self):
self.nodes = {}
self.edges = {}
def add_node(self, name, func):
self.nodes[name] = func
def add_conditional_edges(self, from_node, condition_fn):
# Adds conditional branching logic between tools
self.edges[from_node] = [(condition_fn, target) for target in self.nodes if target != from_node]
def execute_graph(self, start_node, agent, state):
"""
Executes a directed reasoning graph where each node is a function
and the next node is chosen based on state.
"""
current_node = start_node
while current_node:
result = self.nodes[current_node](agent, state)
state["last_output"] = result
next_node = self._resolve_next_node(current_node, state)
if not next_node:
break
current_node = next_node
return result
def _resolve_next_node(self, current_node, state):
if current_node not in self.edges:
return None
for condition_fn, target in self.edges[current_node]:
if condition_fn(state):
return target
return None
Future: Supervisor Agent Skeleton
def supervisor(state):
"""
Placeholder for a Supervisor Agent pattern.
The supervisor will manage multiple cognitive or utility agents
(e.g., LLMPlanner, TaskDecomposer, ValidatorAgent), delegate
subtasks, and synthesize responses into a global plan or decision.
This supports scalable reasoning workflows in collaborative or
multi-agent systems, and is ideal for integrating advanced cognition
or team-based task allocation in agent-based simulations.
The supervisor concept is also inspired by Ewout's earlier work on
structured agent state management, and would build on that idea to
handle coordination across reasoning-capable agents.
"""
pass
Usage Example
The following shows how a CognitiveAgent can use the orchestrator:
class CognitiveAgent(mesa.Agent):
def __init__(self, unique_id, model, orchestrator):
super().__init__(unique_id, model)
self.orchestrator = orchestrator
self.memory = []
def step(self):
context = {"goal": "explore", "memory": self.memory}
output = self.orchestrator.execute_graph("reasoning_flow", self, context)
self.memory.append(output)
Benefits and Integration with Mesa
- Works with Mesa’s agent lifecycle: No changes needed to model or visualization APIs
- Modular: Reasoning tools are decoupled from agents
- Composable: Easily supports multi-step workflows, memory-based reasoning, and conditional logic
- LLM-Ready: Natural language reasoning and goal-driven planning can be invoked in specific graph nodes
- Visualizable: Graphs can be exported or visualized using external tools (future integration with Solara planned)
Target Audience
- Research labs building simulations of human-like cognition, complex decision-making, or AI agents
- Educators teaching reasoning patterns or planning in ABMs
- Open-source developers building plug-and-play reasoning agents
Future Enhancements
- Full supervisor-agent orchestration (inspired by state management PR #2547)
- Integration with tool abstraction
- Visualization of state graphs in Mesa’s UI
- Natural language prompts to generate graph templates
Conclusion
This PR adds structured cognitive orchestration to Mesa, allowing developers to build more intelligent, modular, and explainable agents. It fits cleanly into Mesa’s existing API while offering an extensible base for future development of agent cognition, memory, planning, and collaboration. It also embraces the power of large language models as versatile tools for decision-making and agent interaction in dynamic simulation environments.
[!IMPORTANT]
Review skipped
Auto reviews are disabled on this repository.
Please check the settings in the CodeRabbit UI or the
.coderabbit.yamlfile in this repository. To trigger a single review, invoke the@coderabbitai reviewcommand.You can disable this status message by setting the
reviews.review_statustofalsein the CodeRabbit configuration file.
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
-
I pushed a fix in commit <commit_id>, please review it. -
Generate unit testing code for this file. -
Open a follow-up GitHub issue for this discussion.
-
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. Examples:-
@coderabbitai generate unit testing code for this file. -
@coderabbitai modularize this function.
-
- PR comments: Tag
@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:-
@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase. -
@coderabbitai read src/utils.ts and generate unit testing code. -
@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format. -
@coderabbitai help me debug CodeRabbit configuration file.
-
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.
CodeRabbit Commands (Invoked using PR comments)
-
@coderabbitai pauseto pause the reviews on a PR. -
@coderabbitai resumeto resume the paused reviews. -
@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository. -
@coderabbitai full reviewto do a full review from scratch and review all the files again. -
@coderabbitai summaryto regenerate the summary of the PR. -
@coderabbitai generate docstringsto generate docstrings for this PR. -
@coderabbitai resolveresolve all the CodeRabbit review comments. -
@coderabbitai planto trigger planning for file edits and PR creation. -
@coderabbitai configurationto show the current CodeRabbit configuration for the repository. -
@coderabbitai helpto get help.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
CodeRabbit Configuration File (.coderabbit.yaml)
- You can programmatically configure CodeRabbit by adding a
.coderabbit.yamlfile to the root of your repository. - Please see the configuration documentation for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation:
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
Documentation and Community
- Visit our Documentation for detailed information on how to use CodeRabbit.
- Join our Discord Community to get help, request features, and share feedback.
- Follow us on X/Twitter for updates and announcements.
Performance benchmarks:
| Model | Size | Init time [95% CI] | Run time [95% CI] |
|---|---|---|---|
| BoltzmannWealth | small | 🔵 +0.8% [-0.2%, +1.8%] | 🔵 +0.3% [+0.1%, +0.5%] |
| BoltzmannWealth | large | 🔵 +0.8% [+0.2%, +1.3%] | 🔴 +7.4% [+5.2%, +10.3%] |
| Schelling | small | 🔵 -1.3% [-1.5%, -1.0%] | 🔵 -0.9% [-1.1%, -0.8%] |
| Schelling | large | 🔵 -3.7% [-8.0%, -1.2%] | 🔵 -3.1% [-4.1%, -2.0%] |
| WolfSheep | small | 🔵 +0.6% [+0.2%, +1.1%] | 🔵 +0.4% [+0.2%, +0.6%] |
| WolfSheep | large | 🔵 -0.1% [-1.2%, +0.8%] | 🔵 -1.3% [-3.5%, +0.5%] |
| BoidFlockers | small | 🔵 +1.3% [+0.7%, +1.9%] | 🔵 +0.7% [+0.5%, +0.9%] |
| BoidFlockers | large | 🔵 +1.1% [+0.8%, +1.5%] | 🔵 +0.5% [+0.2%, +0.7%] |
can i review it
@WingchunSiu thanks a lot for your PR! Sorry we didn’t get back to you, we’re swamped with over a hundred proposals. 😅
@priyanshusingh121812 yes, of course you can review!
@wang-boyu maybe also interesting for you.
@colinfrisch @sanika-n what's your view on this PR?
@colinfrisch @sanika-n what's your view on this PR?
This approach is interesting. I also suggested to implement a graph structure for our reasoning module as a next step (depending on the time we have left). But I didn't plan to build it as a general module, rather something behind the scenes. I'm having trouble to understand here what part really builds something that the user couldn't do more efficiently himself for his specific needs (kind of the same problem than my PR on memory module). I would like to see it in action in a real model to see how it improves compared to the model without.
I really liked the idea! It makes it easier to both code and understand how the model is built but I was a bit skeptical about how we have to manually write conditions that connect two nodes (referring to the code here). For instance, suppose Node A gets the observation from the model, then we are sort of saying that "if condition x holds carry out the function in Node B else if condition y holds carry out the function in Node C" (pls let me know if I misunderstood). In more nuanced examples, it will also be hard to manually code out the conditions. I think we should exploit LLMs in cases like this. In the model we are currently building, we let the LLM decide which functions to call (tools) by looking at the current situation and referring to memory for context, this I believe makes it more flexible and accurate. But of course, we are yet to fully test it... As Colin mentioned, we are considering adopting a similar structure for the reasoning part if we get time, as this architecture is definitely a strong candidate for parts of the model.
Hi @colinfrisch, @sanika-n, @EwoutH apologies for the late follow-up! I've been quite busy recently and just got the chance to catch up on the discussion here.
Thanks a lot for taking the time to review the PR and for your thoughtful comments, really appreciated.
Re: Colin’s point on abstraction tradeoff Totally fair concern—I agree that orchestration can feel like overhead unless it enables something non-trivial. The core motivation here was to separate cognitive reasoning workflows from agent definitions and enable scalable reuse when logic becomes multi-step, LLM-driven, or hybrid (LLM + rule). For simple agents it may feel unnecessary, but for more complex reasoning—especially when agents need conditional memory lookups or tool calls—it reduces duplication, makes debugging easier, and opens the door for plug-and-play behavior graphs. If it’s helpful, I can port an existing Mesa model into this style so the benefits are clearer in practice.
Re: Sanika’s point on node condition logic Great insight—writing out every (condition → target) pair by hand isn’t required. Instead, you can define a “router” node (either LLM-based or performing pure state checks) whose job is simply to return the name of whichever next node should run. The orchestrator then uses a single always-true edge (e.g. (always_true, "ANY")) so that, after calling the router, it jumps directly to the returned node name. This eliminates big if/else chains and keeps the graph flexible.
I’d still love to contribute and help however I can—whether that’s improving this orchestration layer or assisting with any overlapping pieces you guys have. I understand priorities may shift with the current GSoC going on, so please let me know if you’d like me to continue working on anything or if there are other areas where I can help. Thanks!
@WingchunSiu I understand what you are saying, in all cases it's definitely something interesting to dig into ! If you want to contribute specifically to mesa-llm, the element mesa-llm groupchat is open, so feel free to join and contribute in any way you like in the project (including discussing and making experiments for a graph structure in reasoning), we could always use an extra hand ;)
Totally agree! I really did like the LangGraph styled architecture, so if you do have ideas on how we could incorporate any of those elements into what we’ve got so far, definitely drop them in the group chat. Looking forward 😊