-
Notifications
You must be signed in to change notification settings - Fork 988
Meta agents #2748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Meta agents #2748
Conversation
- Add create meta-agents to experimental - Add tests of meta-agents - Add example with an alliance formation model in basic examples
- add alliance formation model to example_tests
for more information, see https://pre-commit.ci
- allow for deliberate meta-agents creation - allow for combinatorics - allow for dynamic agent creation fix methods-functions; add tests
Co-authored-by: Ewout ter Hoeven <[email protected]> --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Ewout ter Hoeven <[email protected]>
updates: - [github.com/astral-sh/ruff-pre-commit: v0.8.1 → v0.8.6](astral-sh/ruff-pre-commit@v0.8.1...v0.8.6) - [github.com/asottile/pyupgrade: v3.19.0 → v3.19.1](asottile/pyupgrade@v3.19.0...v3.19.1)
* reimplementation of draw_voroinoi * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…rojectmesa#2596) This PR adds a render interval slider to the SolaraViz visualization system, allowing users to control how frequently plots and visualizations are updated during model simulation. This feature significantly improves performance when working with complex visualizations or multiple plots.
Update version and release notes for the next feature release, Mesa 3.1.3.
* chore: formatting * fix: changed zsh: command not found: self.rng.randint to zsh: command not found: self.rng.integers
…#2633) - Install SciPy, since that's now a dependency - Use uv for pip install, which is way faster
- Add create meta-agents to experimental - Add tests of meta-agents - Add example with an alliance formation model in basic examples
- update meta-agent to make more functional - add warehouse model - update alliance model -update tests
for more information, see https://pre-commit.ci
Overall: I liked it and thought it was a good addition. Recommend keep. Had some good features, I really like the sequence diagram, had some standard LLM nonsense (which I resolved) but also had some good catches, which I left and will incorporate into my update. Of note based on the sequence diagram I am going to refactor |
I have a personal interview at work tomorrow that was more in-depth than I initially expected - which used up my brain capacity for today. Still on my list, will try to do it Friday. |
@colinfrisch, if you would like to give yourself a challenge, could you take a look at this PR? |
@tpike3 I really love the example models, it really shows what's possible! We can't include them as |
@quaquel given your familiarity with agent registration, are you good modifying the core |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the module and function docstrings are great for the API reference by explaining what each component does, they don't quite capture the higher-level why and how needed for users to effectively understand and adopt this new experimental feature. We still need a more narrative guide that explains the core meta-agent concept, discusses the deliberate vs. emergent usage patterns, clarifies the implications and potential pitfalls of the assume_*
flags, explicitly connects the key_by_name
mechanism to dynamic creation, and outlines current limitations. Such a conceptual overview should act as a user manual, complementing the technical specs from the docstrings and making the feature more discoverable and easier to use correctly.
However, since this is an experimental PR, we can decide to pick this up in a later PR. Not blocking.
Thanks for your continued work! What's the current status? Anything I can help with? |
Thanks @EwoutH! Only thing to be resolved is the The challenge: Referencing a class by name created in the """
""" My challenge is what is an easy intuitive solution for a mesa user? I feel there must simple solution, that is staring me in the face, but I keep missing it. Every time I think I got one it becomes convoluted and difficult. I feel like it is going to be one of these so simple it is hard problems. Writing this out I think I may have one. After initialization of Let me know if you got any thoughts. |
I'll try to look at the problem as soon as possible, but my teaching starts today.... |
I understand the problem and agree that there must be a simple solution to this. I'll play around with some ideas later today. |
assume_subagent_attributes (bool): Whether to retain attributes | ||
from sub-agents. | ||
|
||
Returns: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we simplify this return to allways return the type?
and perhaps also change the name to make clear that this function creates a class rather than an instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did make it consistent, but returned the instance of the meta agent, not the class. Working on/thinking through scenarios for meta-agents there were instances where you wanted the meta-agent instance and not the class.
I am not sure what the best option is but only one of the three results returns a new meta-agent class, while the other two either create a new meta-agent instance of an existing class or add an agent to an existing meta-agent.
The other option would be to make each of these results separate, but that would make the emergent meta-agent approach I think much more difficult, and imply direct creation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The critical thing is to have a single return type. If there is one case that creates a class and two cases that result in instances, I would be inclined to separate those out into two separate functions with clearly distinguished names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The critical thing is to have a single return type. If there is one case that creates a class and two cases that result in instances, I would be inclined to separate those out into two separate functions with clearly distinguished names.
I don't disagree but then that runs into the problem that as the agents do things the code separate functions will have to be more explicit from the user. My thought is to make it more agent behavior to meta-agent creation driven, not explicit creation by the user of when to add and when to create a new instance. My end goal is to enable a network scheduler with active and dormant links, driven by agents with the goal of more novel emergent behavior. My concern is if the user is calling those functions then they are focused on the creation mechanisms instead of the agent behaviors and letting the novelty emerge.
In short, I appreciate your point and have struggled with this choice, but would prefer to keep it like this as it is experimental
So looking at the code again, I think part of the solution to your problem is to actually make sure that # Create Robot Agents
for idx in range(len(self.loading_docks)):
# Create sub-agents
router = RouteAgent(self)
sensor = SensorAgent(self)
worker = WorkerAgent(
self,
self.warehouse[self.loading_docks[idx]],
self.warehouse[self.charging_stations[idx]],
)
# Create meta-agent and place in warehouse
# we assign the new class to some attribute
self.RobotAgent = create_meta_agent(
self,
"RobotAgent",
[router, sensor, worker],
mesa_agent_type=CellAgent,
meta_attributes={
"cell": self.warehouse[self.charging_stations[idx]],
"status": "open",
},
assume_subagent_attributes=True,
assume_subagent_methods=True,
)
def step(self):
"""
Advance the model by one step.
"""
# NOTE PART 2: RobotAgent not imported because it is created here so can't reference e.g. from agents import RobotAgent
for robot in self.agents_by_type[self.RobotAgent]: # we can now use the attribute here to do normal by class lookups
if robot.status == "open": # Assign a task to the robot
item = self.random.choice(self.agents_by_type["InventoryAgent"])
if item.quantity > 0:
robot.initiate_task(item)
robot.status = "inventory"
self.central_move(robot)
else:
robot.continue_task() With this there is no reason to change anything inside |
ff14883
to
bc3f9c0
Compare
Update model.py Update tests Update meta_agent.py debating names
mesa/model.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@quaquel are you good with the changes in model.py
?
Default behavior doesn’t change, but I’m curious if this is the only possible implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am very reluctant about those. As indicated, there is a simple solution possible, even given how @tpike3 addressed my comment on create_meta_agent
. In my view, experimental features should not touch stable features. In fact, in the past, I subclassed Agent or Model into experimental if I needed to make changes to those classes exactly for this reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh dammit, sorry, those should have been removed, I forgot to look at that dif. I agree we should not touch stable features, I will remove now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EwoutH and @quaquel Thanks for the catch!, I cannot believe I didn't remove the changes to mesa/model.py
, must have had too many model.py
open for the example models and just spaced over it.
All changes to stables features in agent.py
and model.py
are removed. Only change to agent.py
is in the notes section which is autoformatting updates based on the JOSS feedback (i.e. less than 80 characters, but ruff doesn't want two line for the first line below the function and so on).
Just to make some good notes for refresh months from now when we revisit:
One outstanding question for meta_agent.py
is in create_meta_agent()
whether to split up into three functions of
add_agent_to_meta_agent
: adds a newconstituting_agent
to an existingMetaAgent
instance. return meta_agent instancecreate_new_meta_agent_instance
: create a newMetaAgent
instance of an existingMetaAgent
, return meta_agent instancecreate_new_meta_agent
: creates a new class ofMetaAgent
, return type of meta-agent instance.
My view right now is to keep it as all part of the create_meta_agent
function as this makes it more user friendly for dynamic creation of new and novel meta agents based on constituting agent behavior. This does however come at a cost which is the return object of the create_meta_agent
function. This then bleeds over into agents_by_type
making it harder on the user to know when to use type(meta_agent) or a specific met-agent instance.
The impact of this can be seen the warehouse model in mesa examples. In the model.py
file and the app.py
files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One option is to seperate them out into 3 but also add a fourth overarching function that can be used if the caller based on context cannot know which of the 3 underlying functions to use.
Also, with @overload
some of the typing might be made clearer.
All this can wait however and I am fine with merging this now.
Remove all traces of key_by_name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with this experimental feature as is! It now looks like a clean changeset that can be integrated in main
and included with its experimental status, while development continues.
I will leave the merge to you, but I would like one more approving review before being merged, given the size/complexity of this new feature.
Awesome work Tom!
Summary
Adds an experimental feature to allow for the deliberate or emergent creation of meta_agents (agents who are compromised of other agents)
Motive
Allow Mesa users to explore complex phenomenon of multi-level systems, while also providing the ability to more effectively leverage threading and multiprocessing for large complex models. (For example each meta-agent can be on a thread and then process their internal dynamics before externally engaging with other meta-agents.)
Implementation
Core additions
MetaAgent
class extends agent classcreate_met_agent
function to create meta_agent class, instance or add agents to existing meta-agent (agents are currently restricted to being part of meta-agent)find_combinations
in the agentset find different possible meta_agent combinations and assess them based on user criteria for optimal combinations.Examples
Usage Examples
Deliberate meta-agent creation. The following is from the warehouse model added to examples (inspired by a project from the team in Brazil who used Mesa to do an actual autonomous warehouse). In this case different pseudo-systems (e.g. sensors) are combined to create a
RobotAgent
Emergent meta-agent creation. The following is from the alliance formation model added to examples. It uses the bilateral shapely value to assess pairwise alliances and creates an emergent hierarchy of alliances. Also demonstrates use of find and evaluate combinations.
For fun some pictures
Alliance formation---


Warehouse Model---


Additional Notes
The interesting problem with objects "existing in" objects and dynamically creating new objects is referencing them. Examples of this are shown through out the
Warehouse
model.Of most significant note was dynamically creating
RobotAgent
in the model class and then the need to reference it, with no import of an Agent Class. I tried a few different options (e.g. make a model attribute), but arguably the one I went with was adding a kwarg to agents calledkey_by_name
this allows users to store the key in agents_by_type as a string vs and object type and seemed to be the most user friendly.For this dynamic, I feel like there are more eloquent ways to handle it, so open to any suggestions. However, it may need to be a protocol that evolves over time and becomes a Mesa standard.