unaiverse.world
What this module does 🔴
Defines World, a special AgentBasics subclass representing a world node with no processor or behaviour that coordinates peers, per-role behaviour, and world-level statistics.
world
¶
█████ █████ ██████ █████ █████ █████ █████ ██████████ ███████████ █████████ ██████████
░░███ ░░███ ░░██████ ░░███ ░░███ ░░███ ░░███ ░░███░░░░░█░░███░░░░░███ ███░░░░░███░░███░░░░░█
░███ ░███ ░███░███ ░███ ██████ ░███ ░███ ░███ ░███ █ ░ ░███ ░███ ░███ ░░░ ░███ █ ░
░███ ░███ ░███░░███░███ ░░░░░███ ░███ ░███ ░███ ░██████ ░██████████ ░░█████████ ░██████
░███ ░███ ░███ ░░██████ ███████ ░███ ░░███ ███ ░███░░█ ░███░░░░░███ ░░░░░░░░███ ░███░░█
░███ ░███ ░███ ░░█████ ███░░███ ░███ ░░░█████░ ░███ ░ █ ░███ ░███ ███ ░███ ░███ ░ █
░░████████ █████ ░░█████░░████████ █████ ░░███ ██████████ █████ █████░░█████████ ██████████
░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░ ░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
A Collectionless AI Project (https://collectionless.ai)
Registration/Login: https://unaiverse.io
Code Repositories: https://github.com/collectionlessai/
Main Developers: Stefano Melacci (Project Leader), Christian Di Maio, Tommaso Guidi
World
¶
World(world_folder: str, merge_flat_stream_labels: bool = False, stats: Stats | None = None)
Bases: AgentBasics
A world node: a special agent that hosts and orchestrates other agents.
A world is a peer in the UNaIVERSE network that other agents join. Unlike a regular agent, a world has no processor and no behaviour of its own: it does not produce data and does not run a state machine. Instead, it coordinates the agents connected to it by assigning them roles, broadcasting role changes, keeping track of world membership (masters, agents, humans, artificial agents), awarding badges, and aggregating the statistics that every peer reports into a live connectivity graph.
World is the base class that world designers subclass to define custom
behaviour. The typical pattern is to place an agent.py file inside the world
folder that defines a World subclass overriding hooks such as assign_role
(to decide which role each joining agent receives) and add_peer_stats (to react
to incoming statistics).
Because a world is itself an AgentBasics instance, it inherits the full
membership bookkeeping (all_agents, world_masters, world_agents,
human_agents, artificial_agents) and the role constants
(ROLE_WORLD_MASTER, ROLE_WORLD_AGENT, and the ROLE_BITS_TO_STR lookup)
used throughout this class.
Attributes:
| Name | Type | Description |
|---|---|---|
private_peer_of |
Mapping from a peer's public peer ID to its private peer ID, kept in sync as agents join and leave the world. |
|
agent_badges |
dict[str, list[dict]]
|
Mapping from a peer ID to the list of badge dictionaries awarded
to that agent (see |
stats |
The |
Examples:
A minimal custom world, defined in the world folder's agent.py:
>>> from unaiverse.world import World
>>> from unaiverse.networking.node.profile import NodeProfile
>>>
>>> class ChatRoom(World):
... def assign_role(self, profile: NodeProfile, is_world_master: bool) -> str:
... # The first master keeps the master role; everyone else is a plain agent.
... role = (World.ROLE_WORLD_MASTER if is_world_master and len(self.world_masters) <= 1
... else World.ROLE_WORLD_AGENT)
... return World.ROLE_BITS_TO_STR[role]
>>>
>>> world = ChatRoom(world_folder="./my_chat_room")
Initialize a world as a special agent with no processor and no behaviour.
The parent AgentBasics constructor is invoked with all processor-related
arguments set to None so that no processor is attached. Any dummy processor
allocated during base initialization is then cleared, and the processor-related
attributes are reset to empty (not None) so the rest of the framework can
iterate over them safely. If no stats recorder is supplied, a default one is
created under <world_folder>/stats/world_stats.db.
The world_folder is the single source of truth for a world: it holds the
per-role behaviour JSON files (loaded into role_to_behav and used by
set_role when broadcasting role changes) and the agent.py that defines
this World subclass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
world_folder
|
str
|
Path to the world folder. It contains the per-role behaviour
JSON files and the |
required |
merge_flat_stream_labels
|
bool
|
If True, flat stream labels coming from different peers are merged into a single label space. Defaults to False. |
False
|
stats
|
Stats | None
|
An existing |
None
|
Examples:
>>> world = World(world_folder="./my_world")
>>> # Reuse a pre-configured stats recorder instead of the default one:
>>> from unaiverse.stats import Stats
>>> shared = Stats(is_world=True, db_path="./my_world/stats/world_stats.db")
>>> world = World(world_folder="./my_world", stats=shared)
Source code in unaiverse/world.py
assign_role
¶
assign_role(profile: NodeProfile, is_world_master: bool) -> str
Assign an initial role to a newly connected agent.
This is the main extension point for world designers: override it to implement custom admission logic (for example, a role based on the agent's profile, its CV, or its declared capabilities). In this basic implementation the role depends only on whether the agent is requesting to be a master, and the master role is granted to at most one agent: any further master request is downgraded to a plain world agent.
The returned role is the initial role assigned at join time. It can be changed
later at runtime with set_role, which preserves the base role bits and
broadcasts the change back to the agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
profile
|
NodeProfile
|
The |
required |
is_world_master
|
bool
|
True if the new agent is attempting to join as a master. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The assigned role as a human-readable string, taken from |
str
|
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If called on a node that is not a world. |
Examples:
>>> # Inside a World subclass, accept the first master and downgrade the rest:
>>> def assign_role(self, profile, is_world_master):
... if is_world_master and len(self.world_masters) <= 1:
... return World.ROLE_BITS_TO_STR[World.ROLE_WORLD_MASTER]
... return World.ROLE_BITS_TO_STR[World.ROLE_WORLD_AGENT]
Source code in unaiverse/world.py
set_role
async
¶
Set a new role for a connected agent and broadcast the change to it (async).
The two least significant bits of the agent's current role (its base role bits)
are preserved, while the higher bits are replaced by role. If the resulting
role is identical to the current one, nothing happens. Otherwise the new role is
stored locally and a ROLE_SUGGESTION message is sent to the agent carrying
both the new role and the default behaviour associated with that role (looked up
in role_to_behav). If the message cannot be delivered, the agent is purged
(disconnected) from the world.
This is the runtime counterpart of assign_role: assign_role decides the
role at join time, while set_role changes it afterwards and notifies the
agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peer_id
|
str
|
The peer ID of the agent whose role is to be changed. |
required |
role
|
int
|
The new role to assign, encoded as an integer bitmask. |
required |
Raises:
| Type | Description |
|---|---|
AssertionError
|
If called on a node that is not a world. |
Note
This coroutine has side effects beyond the role update: on a successful
broadcast it sets role_changed_by_world to True, and on a failed
broadcast it disconnects the target agent via the node purge callback.
Source code in unaiverse/world.py
set_addresses_in_profile
¶
Update the network addresses stored in a known agent's profile.
The existing address list inside the agent's dynamic profile is updated in place
(cleared and refilled) rather than replaced, because that list object is shared
by reference with other parts of the framework. If the peer is unknown, the call
is ignored and an error is logged. On success, received_address_update is set
to True to signal that addresses changed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peer_id
|
str
|
The peer ID of the agent whose profile is being updated. |
required |
addresses
|
list[str]
|
The new list of network addresses to store. |
required |
Note
No exception is raised for an unknown peer_id; the condition is logged
and the method returns without modifying any state.
Source code in unaiverse/world.py
add_badge
¶
add_badge(peer_id: str, score: float, badge_type: str, agent_token: str, badge_description: str | None = None) -> None
Award a badge to a connected agent to track and reward its performance.
The score and badge type are validated first, then the badge (together with the agent's node ID, token, description, and an edit timestamp) is appended to the agent's badge list. Awarding a badge marks a change in connections, which forces the world to send out its dynamic profile at the next scheduled instant so that the new badge becomes visible to the network.
Badges accumulate per agent: calling this method several times for the same
peer_id appends to that agent's list rather than replacing it. See
get_all_badges to read the full record and clear_badges to reset it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peer_id
|
str
|
The peer ID of the agent receiving the badge. |
required |
score
|
float
|
The score associated with the badge. Must be in the range [0.0, 1.0]. |
required |
badge_type
|
str
|
The type of badge to award. Must be one of |
required |
agent_token
|
str
|
The token of the agent receiving the badge. The world does not necessarily know this token on its own, because agents usually do not send messages to the world, so the caller must provide it. |
required |
badge_description
|
str | None
|
An optional free-text description for the badge. Defaults to None, which is stored as an empty string. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> world.add_badge(peer_id, score=0.95, badge_type="completion",
... agent_token=token, badge_description="Finished the task")
Source code in unaiverse/world.py
get_all_badges
¶
Retrieve every badge the world has recorded, grouped by agent.
This provides a central log of achievements and performance metrics across all
agents the world has awarded badges to via add_badge.
Returns:
| Type | Description |
|---|---|
dict[str, list[dict[str, Any]]]
|
A dictionary mapping each agent's peer ID to the list of badge dictionaries |
dict[str, list[dict[str, Any]]]
|
awarded to it. Each badge dictionary contains the keys |
dict[str, list[dict[str, Any]]]
|
|
dict[str, list[dict[str, Any]]]
|
and |
dict[str, list[dict[str, Any]]]
|
dictionary, not a copy, so callers should not mutate it directly. |
Examples:
>>> for peer_id, badges in world.get_all_badges().items():
... print(peer_id, sum(b["score"] for b in badges))
Source code in unaiverse/world.py
clear_badges
¶
Remove every badge record from the world's memory.
Useful to reset competition results or to clean up state after a specific event.
Only the in-memory record held by the world is cleared (the same dictionary
returned by get_all_badges); badges already propagated to the network are not
retracted.
Source code in unaiverse/world.py
add_agent
async
¶
add_agent(peer_id: str, profile: NodeProfile, add_proc_streams: bool = True, add_env_streams: bool = True, add_pubsub_streams: bool = True) -> bool
Register a new agent in the world and record its peer ID mapping (async).
The actual registration is delegated to the parent AgentBasics.add_agent. On
success, the mapping from the agent's public peer ID to the private peer ID under
which it is known inside the world is additionally recorded (in
private_peer_of), so that later lookups can translate between the two
namespaces. The inverse cleanup happens in remove_agent.
The add_proc_streams, add_env_streams, and add_pubsub_streams flags
exist for parity with the agent-side signature but have no effect here: a world
has no processor and does not subscribe to peer streams.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peer_id
|
str
|
The (private) peer ID of the agent being added. |
required |
profile
|
NodeProfile
|
The |
required |
add_proc_streams
|
bool
|
Whether to add the peer's processor streams to the set of known streams when compatible. Ignored for worlds. Defaults to True. |
True
|
add_env_streams
|
bool
|
Whether to add the peer's environmental streams to the set of known streams when compatible. Ignored for worlds. Defaults to True. |
True
|
add_pubsub_streams
|
bool
|
Whether to add and subscribe to the peer's pubsub streams. Ignored for worlds. Defaults to True. |
True
|
Returns:
| Type | Description |
|---|---|
bool
|
True if the parent class successfully added the agent, False otherwise. When |
bool
|
False, the peer ID mapping is left untouched. |
Source code in unaiverse/world.py
remove_agent
async
¶
Remove an agent from the world and clean up its peer ID mapping (async).
The agent's profile is captured before delegating removal to the parent
AgentBasics.remove_agent. On success, the corresponding public-to-private
peer ID entry is deleted from private_peer_of so no stale mapping is left
behind. This is the inverse of add_agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peer_id
|
str
|
The private peer ID of the agent to remove. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the parent class successfully removed the agent, False otherwise. |
bool
|
When False, the peer ID mapping is left untouched. |
Source code in unaiverse/world.py
collect_and_store_own_stats
¶
Collect this world's own membership counts and push them to the recorder.
The current number of world masters, world agents, human agents, and artificial
agents is recorded under the world's own private peer ID at the current time. If
no Stats recorder is configured, the call returns immediately. Any error
raised by the recorder is caught and logged rather than propagated, so a stats
failure never interrupts world operation. This is invoked once per batch at the
start of add_peer_stats.
Source code in unaiverse/world.py
add_peer_stats
¶
Process a batch of stats reported by peers and update world state (world-only).
For each update in the batch, the world's own membership stats are refreshed
first, then the stat is either handled by a custom hook (_process_custom_stat),
deferred for graph processing (connected_peers updates), or stored in the
Stats recorder when the stat name is known. After every update is processed,
the connectivity graph is rebuilt from the deferred connected_peers entries
and stale nodes are pruned. Graph updates are deferred to the end of the batch on
purpose: node metadata for a peer may only become available after all updates in
the batch have been seen. Errors on individual updates are caught and logged so a
single malformed update does not abort the whole batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
peer_stats_batch
|
list[dict[str, Any]]
|
A list of stat-update dictionaries. Each entry is expected
to contain |
required |
sender_peer_id
|
str | None
|
The peer ID of the sender. Currently not used for filtering. Defaults to None. |
None
|
Source code in unaiverse/world.py
debug_stats_dashboard
¶
Render the world's stats dashboard to a temporary file and open it (dev only).
Convenience helper for development: the current stats are rendered as an HTML dashboard, written to a temporary file, and opened in the default web browser. If the renderer produces no HTML, nothing is opened. This method is intended for local debugging and is not part of the normal world lifecycle.