The mjairuntime package manages the lifecycle of a Mahjong AI session. It bridges the gap between raw transport layers (TCP sockets or Standard I/O) and the core domain logic by implementing the MJAI protocol's message loop and session management.
The runtime supports two primary execution modes: Stdio (typically used for local testing or pipe-based engines) and TCP Client (using the mjsonp protocol). Both modes share a common message loop implemented in runJSONLines internal/adapter/mjai/runtime/json_lines.go22-50
| Mode | Entry Point | Protocol | Behavior |
|---|---|---|---|
| Stdio | RunStdio | JSON Lines | Sparse output; only responds when an action is taken cmd/README.md50-52 Does not exit on end_game cmd/README.md52-53 |
| TCP | RunTCP | mjsonp | Synchronous; sends {"type":"none"} if no action is taken cmd/README.md58-59 Exits immediately on end_game cmd/README.md60 |
The following diagram illustrates how the Driver orchestrates data between the transport layer and the internal Bot.
Runtime Dispatch Logic
Sources: internal/adapter/mjai/runtime/json_lines.go36-38 internal/adapter/mjai/runtime/driver.go34-74
The Driver struct is the stateful manager of a single connection internal/adapter/mjai/runtime/driver.go14-22 It handles protocol-level handshakes and initializes the game state.
hello with a join message containing the player name and room internal/adapter/mjai/runtime/driver.go36-37start_game, it resets the ai.Agent, determines the player's seat ID (preferring the message ID over the fallbackID), and instantiates a new application.Bot internal/adapter/mjai/runtime/driver.go38-50inbound.ParseEvent and passes them to the Bot for processing internal/adapter/mjai/runtime/driver.go61-65application.Reaction back into a serialized MJAI outbound.Message using outbound.ToMessage internal/adapter/mjai/runtime/driver.go72The fallbackID is used when a start_game message lacks an id field, which is common when replaying logs or in certain server configurations cmd/mjai-manue/main.go33 cmd/README.md41-43 The Driver ensures that if a message ID is present, it takes precedence internal/adapter/mjai/runtime/driver.go39-42
Sources: internal/adapter/mjai/runtime/driver.go24-32 internal/adapter/mjai/runtime/driver.go34-74 cmd/mjai-manue/main.go33
The runtime behavior is governed by a jsonLinesPolicy internal/adapter/mjai/runtime/json_lines.go13-16 This allows the same loop to satisfy the different requirements of Stdio and TCP modes.
| Policy Flag | Stdio Setting | TCP Setting | Description |
|---|---|---|---|
respondNoneOnNoReaction | false | true | If true, sends {"type":"none"} when the AI passes internal/adapter/mjai/runtime/json_lines.go72-76 |
stopOnEndGame | false | true | If true, terminates the loop immediately after end_game internal/adapter/mjai/runtime/json_lines.go68-70 |
Sources: internal/adapter/mjai/runtime/stdio.go20 internal/adapter/mjai/runtime/tcp.go55-58
The runtime provides visibility into the AI's internal state and the raw protocol stream.
Driver uses a reporter to pipe internal AI logs (e.g., Shanten counts, evaluation scores) to the stderr stream internal/adapter/mjai/runtime/driver.go48<- and -> respectively via traceLine and writeMessageWithTrace internal/adapter/mjai/runtime/json_lines.go53 internal/adapter/mjai/runtime/json_lines.go77Sources: internal/adapter/mjai/runtime/driver.go48 internal/adapter/mjai/runtime/json_lines.go53 internal/adapter/mjai/runtime/json_lines.go77
The runtime is verified using a "Golden File" testing approach in TestGoldenStdout internal/adapter/mjai/runtime/golden_test.go16-133
.mjson file containing a sequence of MJAI messages representing a game scenario internal/adapter/mjai/runtime/golden_test.go20runJSONLines function is called with a mock input reader and output buffer internal/adapter/mjai/runtime/golden_test.go109.golden file. To ensure stability, the log fields (which contain non-deterministic AI metadata) are stripped before comparison via stripMessageLogs internal/adapter/mjai/runtime/golden_test.go126-127Entity Mapping: Test Setup to Code Entities
Sources: internal/adapter/mjai/runtime/golden_test.go16-133 internal/adapter/mjai/runtime/golden_test.go193-197