Skip to content

Multi-Flow & Multi-GM Architecture

Advanced composition model for routing agent flows through multiple native game masters.

For: Developers extending the framework with complex orchestration needs. See also: Environment Layer, Configuration Reference


Overview

The multi-GM architecture provides:

  1. Flow-to-GM routing: each configured agent flow maps to one or more GMs.
  2. Per-GM backends: each GM owns exactly one backend for this release.
  3. Per-GM components: each GM defines its own typed component slots.
  4. Sequential flow chains: a flow can pass through multiple GMs in sequence.

When to Use

  • Simulating different backend worlds in the same run.
  • Routing agent cohorts through different decision environments.
  • Multi-stage pipelines such as public action → audit → moderation.

When NOT to Use

  • Simple single-backend world: use one GM.
  • Agents only need sequencing: use a single GM with FlowStepStrategy.

Architecture Model

Layer Stack

┌─────────────────────────────────────────────────────┐
│ Flow → GM chains (env.gm_orchestration.flow_bindings)│
│ Agents are grouped by flow, then routed through GMs   │
├─────────────────────────────────────────────────────┤
│ Agent Flow Sequencing (flow_order, agent_to_flow)   │ ← Agent grouping within GM
│ Groups agents by flow, executes sequentially        │
├─────────────────────────────────────────────────────┤
│ GM component slots                                  │ ← initialize/next/observe/resolve/update
│ Components are configured per GM                    │
└─────────────────────────────────────────────────────┘

Execution Model

Single-GM Mode (Default):

Engine Step Loop:
  → next_acting selects agents
  → group by flow
  → execute flows sequentially (within each, agents parallel)
  → next step

Multi-GM Mode (Advanced):

Engine Step Loop:
  → for each configured GM in sequence order:
    → gm.update(...)
  → group agents by flow
  → for each flow in flow_order:
    → for each GM in that flow's configured GM chain:
      → gm.acting_agents(flow_agents)
      → each active agent observes/acts/resolves through that GM
  → next step

Key property: a GM owns one backend. Multi-backend simulations use multiple GMs, each with its own backend and components.

Each GM updates exactly once at the start of a step, before flow routing and actor selection. Flow chains route agent turns through GMs; they do not trigger additional per-chain GM update calls.


Configuration

Simplest: Single GM

gm:
  name: default_gm
  backend:
    type: twitter_like
    class_path: null
    params: {}
    enabled_actions: null
  components:
    initialize:
      built_in: social_media
      params: {graph: {}}
    next_acting:
      built_in: activity_probability
    observe:
      built_in: timeline_every_turn
    resolve:
      built_in: parsed_action
    update:
      built_in: social_recommendation
    action_prompt:
      built_in: default

All agents use this GM unless the engine step policy routes by flow.

Multi-GM: Different GMs for Different Flows

gm_orchestration:
  gms:
    - name: social_gm
      sequence: 0
      backend:
        type: twitter_like
        class_path: null
        params: {}
        enabled_actions: null
      components:
        initialize: {built_in: social_media, params: {graph: {}}}
        next_acting: {built_in: activity_probability, params: {}}
        observe: {built_in: timeline_every_turn, params: {}}
        resolve: {built_in: tool_calling, params: {}}
        update: {built_in: social_recommendation, params: {}}
        action_prompt: {built_in: default, params: {}}

    - name: market_gm
      sequence: 1
      backend:
        type: resource_market
        class_path: null
        params: {}
        enabled_actions: null
      components:
        initialize: {built_in: app_initialize, params: {}}
        next_acting: {built_in: fixed_order, params: {}}
        observe: {built_in: app_observation, params: {}}
        resolve: {built_in: tool_calling, params: {}}
        update: {built_in: disabled, params: {}}
        action_prompt: {built_in: default, params: {}}

  flow_bindings:
    flow_to_gms:
      social: [social_gm]
      market: [market_gm]

Behavior: - agents with flow social act through social_gm; - agents with flow market act through market_gm; - each GM initializes its own backend and updates once at the start of each step.

env.gm_orchestration.gms[*] is intentionally strict in 0.x. Every GM must declare its own backend and components; orchestrated GMs do not inherit missing backend or component slots from env.gm. Nested backend and component keys use the same strict surface as the default GM.

Within each GM:

engine:
  step:
    built_in: multi_gm
    params:
      flow_order: [pre_analysis, default, post_analysis]
      agent_to_flow:
        alice: "pre_analysis"
        bob: "default"
        charlie: "post_analysis"

agent_to_flow is validated against the final Agent names during runtime construction. Overrides are materialized into each Game Master's agent_flow_tags before the Engine starts, so Engine scheduling and Game Master component routing use the same flow assignment.

Per-Flow Component Configuration

Configure different component behavior per flow:

gm:
  components:
    observe:
      instances:
        active_feed:
          built_in: timeline_every_turn
          params:
            timeline_mode: pure_recsys
        default_feed:
          built_in: timeline_every_turn
          params:
            timeline_mode: follower_chronological
        fixed_pre_episode:
          built_in: episode_only
      flow_map:
        active: active_feed
        default: default_feed
        fixed_pre: fixed_pre_episode

Implementation: 1. Each component instance is a normal slot component. 2. The GM parses flow_map and chooses the component instance for the agent's flow. 3. Custom components do not need flow-aware code.

Example component:

from silisocs.environments.gm.components.base import ObservationComponent

class CustomObserve(ObservationComponent):
  def __init__(self, *, source: str):
    self.source = source

  def make_observation(self, agent_name: str) -> str:
    return f"{agent_name} sees {self.source}"

Implementation Details

Runtime Construction

silisocs.runtime.construction.game_masters.build_game_masters(...) converts Hydra config into native GameMasterConfig specs. In multi-GM mode every item under env.gm_orchestration.gms must define its own backend and components; defaults are not inherited into orchestrated GMs. flow_bindings.flow_to_gms is validated up front: every referenced GM must be declared, every chain must be non-empty, duplicate GMs in a chain are rejected, and multi-GM chains must follow strictly increasing sequence values.

MultiGMRuntimeEngine

MultiGMRuntimeEngine uses MultiGMStepStrategy. It reads materialized flow_to_gms routing metadata, groups agents by flow, and executes each flow through its configured GM chain. A flow with no explicit binding falls back to the earliest-sequence GM. agent_to_flow overrides are included in routing metadata even when no persona class declares that flow.

Checkpoint replay for multi-GM runs is strict: the replay strategy uses the agent's materialized flow and that flow's GM chain, then requires exactly one GM in the chain to expose the replayed backend action. Missing flow metadata, unknown GMs, no action match, and ambiguous action matches fail loudly.

Routed Slot Components

Located: src/silisocs/environments/gm/components/base.py

Flow-routed GMs can route every slot: initialize, next_acting, action_prompt, observe, resolve, and update. The component APIs remain the same as the single-flow APIs; routing is a GM responsibility.


Testing

uv run pytest tests/test_multi_gm_runtime_engine.py -v
uv run pytest tests/test_runner_processing_mode.py::test_multi_gm_specs_can_use_distinct_backends -v
uv run pytest tests/test_initializer_bootstrap.py::test_checkpoint_restore_routes_replay_to_matching_gm_backend -v

Performance Considerations

  • Flow chains are sequential: a flow passes through its configured GMs in order.
  • Within-batch agent turns can run in parallel: agents selected by the same GM and flow are isolated as separate turns.
  • Backend state is per GM: this release does not share one live backend object across multiple GMs.

FAQ

Q: Can agents move between GMs during simulation? A: Flow assignment is configured before the run. Dynamic reassignment requires a custom engine policy.

Q: Can GMs share state? A: Not as a shared backend object in this release. Use one backend per GM, or persist shared state externally in custom components.

Q: Can I route slots by flow without multi-GM? A: Yes. A single GM can use instances + flow_map on any typed component slot.

Q: Do I need to modify existing components? A: No. Flow routing is handled by the GM; components expose the same direct slot methods.


See Also