ogs.dsl.composition¶
Bases: BaseModel
An explicit wiring between two games.
Uses game-theory naming (source_game/target_game). Provides
source_block/target_block properties for GDS interop (GDS
composition validators access these attributes).
source_game and target_game accept either a str (game name)
or an OpenGame instance. When an OpenGame is provided it is
coerced to game.name immediately at construction time, so the IR
and verifier always receive plain strings.
Source code in packages/gds-games/ogs/dsl/composition.py
Bases: StackComposition, OpenGame
g1 >> g2 — sequential composition where output of g1 feeds input of g2.
Extends GDS StackComposition so isinstance(seq, StackComposition)
is True. GDS's validator handles token-overlap checking and interface
computation. The OpenGame.signature property provides x/y/r/s access.
Mathematical Notation¶
In category theory, written as G1 ; G2 (semicolon denotes composition). The output Y1 of the first game becomes the input X2 of the second::
X1 -> G1 -> Y1 = X2 -> G2 -> Y2
Or as a composite::
X1 -> (G1 ; G2) -> Y2
With contravariant feedback::
R1 <- G1 <- S1 = R2 <- G2 <- S2
Signature Transformation¶
- X = X1 + X2 (observations from both games)
- Y = Y1 + Y2 (choices from both games)
- R = R1 + R2 (utilities to both games)
- S = S1 + S2 (coutilities from both games)
Type Matching¶
Sequential composition requires type compatibility between Y1 and X2. If no explicit wiring is provided, the validator checks that the type tokens of Y1 overlap with X2 (at least one shared token).
Example¶
A policy game feeding into a decision game::
policy >> decision
Where Policy.Y = "Latest Policy" and Decision.X = "Latest Policy" (automatic wiring via type token matching).
See Also¶
Specification Notes: Sequential composition via type matching
Source code in packages/gds-games/ogs/dsl/composition.py
Bases: ParallelComposition, OpenGame
g1 | g2 — parallel (tensor) composition: games run independently.
Extends GDS ParallelComposition so isinstance(par, GDSParallelComposition)
is True. GDS's validator handles interface computation.
Mathematical Notation¶
In category theory, written as G1 || G2 (parallel bar denotes tensor product). Games run side-by-side with no shared information flows::
X1 -> G1 -> Y1
X2 -> G2 -> Y2
As a composite::
(X1 x X2) -> (G1 || G2) -> (Y1 x Y2)
Signature Transformation¶
- X = X1 + X2 (concatenated observations)
- Y = Y1 + Y2 (concatenated choices)
- R = R1 + R2 (concatenated utilities)
- S = S1 + S2 (concatenated coutilities)
Independence¶
No game-to-game flows allowed between left and right components. Each game operates independently with separate observations, choices, utilities, and coutilities.
Example¶
Two agents acting in parallel::
agent1 | agent2
Each agent has its own context builder, policy, and decision game. Their outputs feed into a shared decision router via separate wires.
See Also¶
Specification Notes: Parallel composition for multi-agent patterns
Source code in packages/gds-games/ogs/dsl/composition.py
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | |
from_list(games, name=None)
classmethod
¶
Compose a list of games in parallel.
Equivalent to games[0] | games[1] | ... | games[N-1] but
accepts a dynamic list, enabling N-agent patterns without
manually enumerating the | chain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
games
|
list[OpenGame]
|
At least 2 |
required |
name
|
str | None
|
Optional name override for the resulting composition.
Defaults to |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than 2 games are provided. |
Example::
agents = [reactive_decision_agent(f"Agent {i}") for i in range(1, 4)]
agents_parallel = ParallelComposition.from_list(agents)
Source code in packages/gds-games/ogs/dsl/composition.py
Bases: FeedbackLoop, OpenGame
Wraps a game with contravariant S->R feedback within a single timestep.
Extends GDS FeedbackLoop so isinstance(fb, GDSFeedbackLoop)
is True. GDS's validator sets the interface.
Mathematical Notation¶
In category theory, written as feedback(G) or with a feedback loop symbol. Creates backward information flow within a single game execution::
X -> G -> Y
^
| (feedback)
v
R <- S
The coutility S of the inner game feeds back as utility R within the same timestep (before the game "completes").
Information Flow¶
Contravariant (dashed arrows): S -> R - S: Coutility produced by inner game - R: Utility received by inner game - Direction: Right-to-left (backward)
This enables learning within a single decision cycle: 1. Inner game produces choice Y 2. Choice generates outcome (external) 3. Outcome feeds back as utility R 4. Inner game produces coutility S (experience) 5. S feeds back to R via feedback_wiring
Example¶
A reactive decision agent with learning::
agent = (cb >> hist >> pol >> rd >> out).feedback([
Flow("Outcome", "Outcome", "Reactive Decision", "Outcome", CONTRAVARIANT),
Flow("Experience", "Experience", "Policy", "Experience", CONTRAVARIANT),
Flow(
"History Update", "History Update",
"History", "History Update", CONTRAVARIANT,
),
])
See Also¶
Specification Notes: Feedback within Reactive Decision Pattern
Source code in packages/gds-games/ogs/dsl/composition.py
Bases: TemporalLoop, OpenGame
Wraps a game with temporal corecursion: covariant Y->X across timesteps.
Extends GDS TemporalLoop so isinstance(cl, TemporalLoop)
is True. Accepts corecursive_wiring as an alias for temporal_wiring.
GDS's validator enforces COVARIANT-only wiring and sets the interface.
Mathematical Notation¶
In category theory, written as corec(G) or with a temporal loop symbol. Creates forward information flow across multiple timesteps (iterations)::
X -> G -> Y
^ |
| | (corecursive)
| v
---(loop)
The choice Y of one iteration becomes the observation X of the next iteration. This creates a temporal loop that continues until an exit_condition is satisfied.
Information Flow¶
Covariant (solid arrows): Y -> X - Y: Choice produced by inner game in iteration n - X: Observation received by inner game in iteration n+1 - Direction: Forward across time
All corecursive_wiring must be COVARIANT direction. CONTRAVARIANT wiring in corecursive loops is prohibited.
Temporal Structure¶
- Iteration n: Inner game observes X_n, produces Y_n
- Y_n propagates through corecursive_wiring to become X_{n+1}
- Iteration n+1: Inner game observes X_{n+1} (= Y_n), produces Y_{n+1}
- Loop continues until exit_condition is True
Exit Conditions¶
The exit_condition is a string description of when the loop terminates. Common conditions: - "Agreement reached" (bilateral negotiation) - "Consensus threshold met" (multi-party agreement) - "Maximum iterations exceeded" (timeout) - "Both agents reject" (failure state)
Example¶
Bilateral negotiation with corecursive message passing::
negotiation = feedback_loop.corecursive(
wiring=[
Flow("Decision", "Decision", "Agent 2 Context Builder", "Decision"),
Flow("Decision", "Decision", "Agent 1 Context Builder", "Decision"),
],
exit_condition="Agreement reached or timeout",
)
See Also¶
Specification Notes: Corecursive loops in Cyclic Interaction Pattern
Source code in packages/gds-games/ogs/dsl/composition.py
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | |
corecursive_wiring
property
¶
Game-theory alias for temporal_wiring.