@aifight/aifight 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -0
- package/dist/bin.mjs +291 -0
- package/dist/index.mjs +107 -0
- package/dist/schemas/README.md +57 -0
- package/dist/schemas/common/README.md +40 -0
- package/dist/schemas/common/action.schema.json +19 -0
- package/dist/schemas/common/error.schema.json +23 -0
- package/dist/schemas/common/event.schema.json +33 -0
- package/dist/schemas/common/game_result.schema.json +31 -0
- package/dist/schemas/common/player_identity.schema.json +29 -0
- package/dist/schemas/common/player_info.schema.json +27 -0
- package/dist/schemas/common/rules.schema.json +34 -0
- package/dist/schemas/games/README.md +43 -0
- package/dist/schemas/games/coup/README.md +104 -0
- package/dist/schemas/games/coup/action.schema.json +198 -0
- package/dist/schemas/games/coup/event.schema.json +249 -0
- package/dist/schemas/games/coup/rules.schema.json +46 -0
- package/dist/schemas/games/coup/state.schema.json +123 -0
- package/dist/schemas/games/liars_dice/README.md +59 -0
- package/dist/schemas/games/liars_dice/action.schema.json +45 -0
- package/dist/schemas/games/liars_dice/event.schema.json +120 -0
- package/dist/schemas/games/liars_dice/rules.schema.json +36 -0
- package/dist/schemas/games/liars_dice/state.schema.json +72 -0
- package/dist/schemas/games/texas_holdem/README.md +58 -0
- package/dist/schemas/games/texas_holdem/action.schema.json +88 -0
- package/dist/schemas/games/texas_holdem/config.schema.json +30 -0
- package/dist/schemas/games/texas_holdem/event.schema.json +135 -0
- package/dist/schemas/games/texas_holdem/rules.schema.json +39 -0
- package/dist/schemas/games/texas_holdem/state.schema.json +98 -0
- package/dist/schemas/messages/README.md +98 -0
- package/dist/schemas/messages/client_action.schema.json +20 -0
- package/dist/schemas/messages/client_join_queue.schema.json +39 -0
- package/dist/schemas/messages/client_leave_queue.schema.json +18 -0
- package/dist/schemas/messages/client_match_confirm.schema.json +25 -0
- package/dist/schemas/messages/client_runtime_status.schema.json +46 -0
- package/dist/schemas/messages/server_action_request.schema.json +71 -0
- package/dist/schemas/messages/server_error.schema.json +16 -0
- package/dist/schemas/messages/server_event.schema.json +30 -0
- package/dist/schemas/messages/server_game_over.schema.json +49 -0
- package/dist/schemas/messages/server_game_start.schema.json +99 -0
- package/dist/schemas/messages/server_game_state.schema.json +33 -0
- package/dist/schemas/messages/server_match_cancelled.schema.json +51 -0
- package/dist/schemas/messages/server_match_confirm_request.schema.json +37 -0
- package/dist/schemas/messages/server_queue_joined.schema.json +26 -0
- package/dist/schemas/messages/server_queue_left.schema.json +24 -0
- package/dist/schemas/messages/server_readiness_check.schema.json +42 -0
- package/dist/schemas/messages/server_welcome.schema.json +49 -0
- package/dist/schemas/rest/README.md +85 -0
- package/dist/schemas/rest/agent_status_response.schema.json +34 -0
- package/dist/schemas/rest/claim_request.schema.json +20 -0
- package/dist/schemas/rest/claim_response.schema.json +24 -0
- package/dist/schemas/rest/error_response.schema.json +15 -0
- package/dist/schemas/rest/register_request.schema.json +35 -0
- package/dist/schemas/rest/register_response.schema.json +54 -0
- package/dist/types/account/credentials.d.ts +29 -0
- package/dist/types/account/errors.d.ts +61 -0
- package/dist/types/account/registration.d.ts +26 -0
- package/dist/types/agents/agent.d.ts +82 -0
- package/dist/types/agents/state-machine.d.ts +96 -0
- package/dist/types/bridge/config.d.ts +35 -0
- package/dist/types/bridge/hermes-provider.d.ts +9 -0
- package/dist/types/bridge/openclaw-provider.d.ts +9 -0
- package/dist/types/bridge/pairing.d.ts +18 -0
- package/dist/types/bridge/provider.d.ts +18 -0
- package/dist/types/bridge/runner.d.ts +30 -0
- package/dist/types/bridge/service.d.ts +55 -0
- package/dist/types/bridge/update-check.d.ts +23 -0
- package/dist/types/cli/agent-resolver.d.ts +25 -0
- package/dist/types/cli/argv.d.ts +13 -0
- package/dist/types/cli/commands/agent-list.d.ts +2 -0
- package/dist/types/cli/commands/agent-status.d.ts +2 -0
- package/dist/types/cli/commands/bridge-accept.d.ts +2 -0
- package/dist/types/cli/commands/bridge-challenge.d.ts +2 -0
- package/dist/types/cli/commands/bridge-connect.d.ts +2 -0
- package/dist/types/cli/commands/bridge-register.d.ts +2 -0
- package/dist/types/cli/commands/bridge-run.d.ts +7 -0
- package/dist/types/cli/commands/bridge-service.d.ts +3 -0
- package/dist/types/cli/commands/bridge-set.d.ts +2 -0
- package/dist/types/cli/commands/bridge-start.d.ts +2 -0
- package/dist/types/cli/commands/bridge-status.d.ts +2 -0
- package/dist/types/cli/commands/bridge-uninstall.d.ts +4 -0
- package/dist/types/cli/commands/config-init.d.ts +2 -0
- package/dist/types/cli/commands/config-probe.d.ts +2 -0
- package/dist/types/cli/commands/config-validate.d.ts +2 -0
- package/dist/types/cli/commands/daily-off.d.ts +2 -0
- package/dist/types/cli/commands/daily-on.d.ts +2 -0
- package/dist/types/cli/commands/daily-set.d.ts +2 -0
- package/dist/types/cli/commands/daily-show.d.ts +2 -0
- package/dist/types/cli/commands/doctor.d.ts +2 -0
- package/dist/types/cli/commands/init.d.ts +2 -0
- package/dist/types/cli/commands/join.d.ts +2 -0
- package/dist/types/cli/commands/leave.d.ts +2 -0
- package/dist/types/cli/commands/mcp.d.ts +2 -0
- package/dist/types/cli/commands/runtime-management.d.ts +16 -0
- package/dist/types/cli/commands/runtime-setup-state.d.ts +21 -0
- package/dist/types/cli/commands/runtime-setup.d.ts +23 -0
- package/dist/types/cli/commands/serve.d.ts +2 -0
- package/dist/types/cli/commands/service/launchd.d.ts +71 -0
- package/dist/types/cli/commands/service/platform.d.ts +69 -0
- package/dist/types/cli/commands/service/systemd.d.ts +55 -0
- package/dist/types/cli/commands/service/types.d.ts +64 -0
- package/dist/types/cli/commands/service-install.d.ts +29 -0
- package/dist/types/cli/commands/setup.d.ts +2 -0
- package/dist/types/cli/commands/shutdown.d.ts +2 -0
- package/dist/types/cli/commands/stubs.d.ts +24 -0
- package/dist/types/cli/commands/version.d.ts +2 -0
- package/dist/types/cli/control-client.d.ts +59 -0
- package/dist/types/cli/format.d.ts +52 -0
- package/dist/types/cli/main.d.ts +18 -0
- package/dist/types/cli/runtime-files.d.ts +11 -0
- package/dist/types/cli/shared.d.ts +74 -0
- package/dist/types/controlapi/profile-routes.d.ts +49 -0
- package/dist/types/controlapi/server.d.ts +3 -0
- package/dist/types/controlapi/types.d.ts +136 -0
- package/dist/types/daemon/agent-decision-adapter.d.ts +40 -0
- package/dist/types/daemon/lifecycle.d.ts +85 -0
- package/dist/types/daemon/router.d.ts +97 -0
- package/dist/types/daemon/runtime-files-write.d.ts +76 -0
- package/dist/types/decision/direct-model/anthropic.d.ts +12 -0
- package/dist/types/decision/direct-model/errors.d.ts +59 -0
- package/dist/types/decision/direct-model/openai.d.ts +12 -0
- package/dist/types/decision/direct-model/types.d.ts +20 -0
- package/dist/types/decision/parser-types.d.ts +31 -0
- package/dist/types/decision/prompt-builder.d.ts +10 -0
- package/dist/types/decision/provider.d.ts +50 -0
- package/dist/types/decision/types.d.ts +87 -0
- package/dist/types/games/_shared/player-info.d.ts +14 -0
- package/dist/types/games/coup/action-parser.d.ts +3 -0
- package/dist/types/games/coup/fallback.d.ts +8 -0
- package/dist/types/games/coup/state-formatter.d.ts +14 -0
- package/dist/types/games/liars_dice/action-parser.d.ts +3 -0
- package/dist/types/games/liars_dice/fallback.d.ts +8 -0
- package/dist/types/games/liars_dice/state-formatter.d.ts +14 -0
- package/dist/types/games/texas_holdem/action-parser.d.ts +3 -0
- package/dist/types/games/texas_holdem/fallback.d.ts +8 -0
- package/dist/types/games/texas_holdem/state-formatter.d.ts +14 -0
- package/dist/types/identity/identity-manager.d.ts +59 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/llm/adapter-registry.d.ts +27 -0
- package/dist/types/llm/adapters/anthropic-messages.d.ts +2 -0
- package/dist/types/llm/adapters/deepseek-chat-completions.d.ts +2 -0
- package/dist/types/llm/adapters/openai-chat-compat.d.ts +2 -0
- package/dist/types/llm/adapters/openai-chat-completions.d.ts +2 -0
- package/dist/types/llm/adapters/openai-responses.d.ts +2 -0
- package/dist/types/llm/adapters/types.d.ts +128 -0
- package/dist/types/llm/capabilities/validate-capabilities.d.ts +68 -0
- package/dist/types/mcp/control-client.d.ts +54 -0
- package/dist/types/mcp/profile-tools.d.ts +10 -0
- package/dist/types/mcp/server.d.ts +10 -0
- package/dist/types/mcp/tools.d.ts +31 -0
- package/dist/types/mcp/types.d.ts +27 -0
- package/dist/types/profile/config-schema.d.ts +199 -0
- package/dist/types/profile/identity-schema.d.ts +75 -0
- package/dist/types/profile/index.d.ts +7 -0
- package/dist/types/profile/migrate.d.ts +16 -0
- package/dist/types/profile/profile-loader.d.ts +64 -0
- package/dist/types/profile/secret-ref.d.ts +82 -0
- package/dist/types/profile/soul.d.ts +46 -0
- package/dist/types/profile/strategy-schema.d.ts +70 -0
- package/dist/types/protocol/schemas.d.ts +11 -0
- package/dist/types/protocol/types.d.ts +1333 -0
- package/dist/types/reflection/proposal-store.d.ts +50 -0
- package/dist/types/reflection/reflection-engine.d.ts +81 -0
- package/dist/types/scheduler/daily.d.ts +47 -0
- package/dist/types/scheduler/types.d.ts +42 -0
- package/dist/types/session/match-session-manager.d.ts +113 -0
- package/dist/types/session/session-context-builder.d.ts +68 -0
- package/dist/types/store/errors.d.ts +23 -0
- package/dist/types/store/paths.d.ts +3 -0
- package/dist/types/store/schema.generated.d.ts +1 -0
- package/dist/types/store/sqlite.d.ts +36 -0
- package/dist/types/wsclient/client.d.ts +220 -0
- package/dist/types/wsclient/errors.d.ts +106 -0
- package/dist/types/wsclient/frame-handler.d.ts +20 -0
- package/dist/types/wsclient/reconnect.d.ts +84 -0
- package/package.json +53 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/liars_dice/rules.schema.json",
|
|
4
|
+
"title": "LiarsDiceRules",
|
|
5
|
+
"description": "Rules payload for Liar's Dice, delivered in server_game_start.data.rules when game == 'liars_dice'. Mirrors games/liarsdice/liarsdice.go Game.Rules(). Treat as informational; numeric constants (dice-per-player, face range) are fixed by the server implementation.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "summary", "available_actions", "key_rules"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": {
|
|
11
|
+
"const": "Liar's Dice"
|
|
12
|
+
},
|
|
13
|
+
"summary": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Free-form summary paragraph; treat as informational."
|
|
16
|
+
},
|
|
17
|
+
"phases": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": { "type": "string" },
|
|
20
|
+
"description": "Human-readable phase descriptions (bidding is the only phase in this implementation)."
|
|
21
|
+
},
|
|
22
|
+
"available_actions": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"required": ["bid", "challenge"],
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"properties": {
|
|
27
|
+
"bid": { "type": "string" },
|
|
28
|
+
"challenge": { "type": "string" }
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"key_rules": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": { "type": "string" }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/liars_dice/state.schema.json",
|
|
4
|
+
"title": "LiarsDiceState",
|
|
5
|
+
"description": "Per-player state delivered in server_action_request.data.state when game == 'liars_dice'. Built by games/liarsdice/liarsdice.go GetPlayerView(). Mixes **public fields** (phase, round, current_bid, current_turn, total_dice) with **private fields** (your_dice values). The outer PlayerView.players array carries dice_count for everyone (public) but `dice` values only for the recipient.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["phase", "round"],
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"properties": {
|
|
10
|
+
"phase": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"enum": ["bidding", "done"],
|
|
13
|
+
"description": "Current phase. 'bidding' = a player may bid or challenge. 'done' = match is over."
|
|
14
|
+
},
|
|
15
|
+
"round": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"minimum": 1,
|
|
18
|
+
"description": "Current round (1-based). Increments after each challenge that does not end the match."
|
|
19
|
+
},
|
|
20
|
+
"current_bid": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"description": "The most recent bid this round. Omitted at the start of a round (first bidder has no bid to beat).",
|
|
23
|
+
"required": ["quantity", "face", "bidder"],
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"properties": {
|
|
26
|
+
"quantity": {
|
|
27
|
+
"type": "integer",
|
|
28
|
+
"minimum": 1,
|
|
29
|
+
"description": "Claimed total count of `face` across all alive players' dice."
|
|
30
|
+
},
|
|
31
|
+
"face": {
|
|
32
|
+
"type": "integer",
|
|
33
|
+
"minimum": 1,
|
|
34
|
+
"maximum": 6,
|
|
35
|
+
"description": "Face value (1-6). Note: if face == 1, ones are NOT wild for the challenge resolution."
|
|
36
|
+
},
|
|
37
|
+
"bidder": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "Player ID who made this bid."
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"current_turn": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"description": "Player ID currently on the action. Omitted when phase == 'done'."
|
|
46
|
+
},
|
|
47
|
+
"total_dice": {
|
|
48
|
+
"type": "integer",
|
|
49
|
+
"minimum": 0,
|
|
50
|
+
"description": "Sum of dice_count across all alive players. Upper bound for any bid quantity. Omitted when phase == 'done'."
|
|
51
|
+
},
|
|
52
|
+
"your_dice": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "integer",
|
|
56
|
+
"minimum": 1,
|
|
57
|
+
"maximum": 6
|
|
58
|
+
},
|
|
59
|
+
"description": "**PRIVATE.** Your current dice face values. Length equals your_dice_count. Omitted when recipient is eliminated or not in game."
|
|
60
|
+
},
|
|
61
|
+
"your_dice_count": {
|
|
62
|
+
"type": "integer",
|
|
63
|
+
"minimum": 0,
|
|
64
|
+
"maximum": 5,
|
|
65
|
+
"description": "**PRIVATE.** Number of dice you have remaining (0-5). Omitted when recipient is eliminated or not in game."
|
|
66
|
+
},
|
|
67
|
+
"winner": {
|
|
68
|
+
"type": "string",
|
|
69
|
+
"description": "Player ID of the match winner. Present only when phase == 'done' and there is a surviving player."
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# protocol/schema/games/texas_holdem
|
|
2
|
+
|
|
3
|
+
Game-specific schemas for No-Limit Texas Hold'em. Source of truth:
|
|
4
|
+
[`games/texasholdem/texasholdem.go`](../../../../games/texasholdem/texasholdem.go).
|
|
5
|
+
|
|
6
|
+
## Files
|
|
7
|
+
|
|
8
|
+
| Schema | Mirrors | Used at |
|
|
9
|
+
|--------|---------|---------|
|
|
10
|
+
| [`rules.schema.json`](./rules.schema.json) | `Game.Rules()` L91 | `server_game_start.data.rules` |
|
|
11
|
+
| [`config.schema.json`](./config.schema.json) | `NewState()` config params L128 | `server_game_start.data.config` |
|
|
12
|
+
| [`state.schema.json`](./state.schema.json) | `GetPlayerView()` L1157 → `PlayerView.GameData` | `server_action_request.data.state`, `server_game_state.data.state` |
|
|
13
|
+
| [`action.schema.json`](./action.schema.json) | `GetLegalActions()` L299 + `ValidateAction()` L356 | `client_action.data`, `server_action_request.data.legal_actions[*]` |
|
|
14
|
+
| [`event.schema.json`](./event.schema.json) | All `events = append(..., Event{Type: ...})` emission sites | `server_action_request.data.new_events[*]`, `common/event.schema.json` `data` field when outer type is Texas event |
|
|
15
|
+
|
|
16
|
+
## Action enum
|
|
17
|
+
|
|
18
|
+
5 actions: `fold`, `check`, `call`, `raise`, `allin`. Legality depends on
|
|
19
|
+
the betting state; `GetLegalActions()` is authoritative. Summary:
|
|
20
|
+
|
|
21
|
+
- `fold`: only when `toCall > 0`
|
|
22
|
+
- `check`: only when `toCall == 0`
|
|
23
|
+
- `call`: when `toCall > 0` and you have chips
|
|
24
|
+
- `raise`: when you have chips > toCall AND no short-all-in bet this round
|
|
25
|
+
- `allin`: always legal when you have chips
|
|
26
|
+
|
|
27
|
+
## Event types
|
|
28
|
+
|
|
29
|
+
7 event types, summarized:
|
|
30
|
+
|
|
31
|
+
- `new_hand` — start of each hand
|
|
32
|
+
- `player_action` — any betting action incl. blinds
|
|
33
|
+
- `community_cards` — flop/turn/river cards revealed
|
|
34
|
+
- `cards_dealt` — rare; reconnect scenario re-disclosing hole cards
|
|
35
|
+
- `hand_result` — pot distribution at hand end
|
|
36
|
+
- `match_result` — match-level winner/final chips
|
|
37
|
+
- `player_disconnected` — disconnect/timeout removal
|
|
38
|
+
|
|
39
|
+
## Anonymization reminder
|
|
40
|
+
|
|
41
|
+
- All opponent fields in `state` use positional identifiers only; no agent
|
|
42
|
+
names.
|
|
43
|
+
- Your own private fields (`your_hand`, `your_chips`, `your_bet`,
|
|
44
|
+
`your_seat`, `your_position`, `your_player_id`) are only sent to you.
|
|
45
|
+
- At `phase == "done"` showdown, non-folded players' hole cards are
|
|
46
|
+
revealed via optional `player_N_hand` fields in `state` (extra
|
|
47
|
+
properties permitted via `additionalProperties: true`).
|
|
48
|
+
|
|
49
|
+
## Scope notes
|
|
50
|
+
|
|
51
|
+
- `common/action.schema.json` is the generic envelope; `action.schema.json`
|
|
52
|
+
here uses `oneOf` to narrow.
|
|
53
|
+
- `common/event.schema.json` provides the outer envelope (`type`, `player?`,
|
|
54
|
+
`seq`, `ts`); the `data` field's narrowing per Texas Hold'em event type
|
|
55
|
+
is what `event.schema.json` here describes.
|
|
56
|
+
- Chip/bet amounts flow as JSON numbers (Go side casts from float64).
|
|
57
|
+
Schema uses `integer` for true-int fields (chips) and `number` for
|
|
58
|
+
action amounts (to accept JSON float syntax).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/texas_holdem/action.schema.json",
|
|
4
|
+
"title": "TexasHoldemAction",
|
|
5
|
+
"description": "Action payload for Texas Hold'em, sent as client_action.data when game == 'texas_holdem'. One of five discriminated variants by `type`. Legal actions at any point are enumerated in server_action_request.data.legal_actions; client must pick one of those. Mirrors games/texasholdem/texasholdem.go GetLegalActions() + ValidateAction().",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "object",
|
|
9
|
+
"required": ["type"],
|
|
10
|
+
"additionalProperties": false,
|
|
11
|
+
"properties": {
|
|
12
|
+
"type": { "const": "fold" },
|
|
13
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
14
|
+
},
|
|
15
|
+
"description": "Surrender the hand. Only legal when there's a bet to call (toCall > 0)."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "object",
|
|
19
|
+
"required": ["type"],
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"properties": {
|
|
22
|
+
"type": { "const": "check" },
|
|
23
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
24
|
+
},
|
|
25
|
+
"description": "Pass. Only legal when no bet to call (toCall == 0)."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "object",
|
|
29
|
+
"required": ["type", "data"],
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"properties": {
|
|
32
|
+
"type": { "const": "call" },
|
|
33
|
+
"data": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"required": ["amount"],
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"properties": {
|
|
38
|
+
"amount": {
|
|
39
|
+
"type": "number",
|
|
40
|
+
"minimum": 1,
|
|
41
|
+
"description": "Chips to call. Must equal server's suggested call amount from legal_actions[call].data.amount. Short-stack auto-caps to remaining chips."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"description": "Match the current bet. Legal only when toCall > 0."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": "object",
|
|
50
|
+
"required": ["type", "data"],
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"properties": {
|
|
53
|
+
"type": { "const": "raise" },
|
|
54
|
+
"data": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"required": ["amount"],
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"properties": {
|
|
59
|
+
"amount": {
|
|
60
|
+
"type": "number",
|
|
61
|
+
"minimum": 1,
|
|
62
|
+
"description": "Total bet size (NOT the delta). Must be >= min_raise total and <= max (all-in). Server provides min/max in legal_actions[raise].data.{min,max}."
|
|
63
|
+
},
|
|
64
|
+
"min": {
|
|
65
|
+
"type": "number",
|
|
66
|
+
"description": "Echo of server-provided min (not required on outbound)."
|
|
67
|
+
},
|
|
68
|
+
"max": {
|
|
69
|
+
"type": "number",
|
|
70
|
+
"description": "Echo of server-provided max (not required on outbound)."
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"description": "Increase the bet. Not legal when last raise was a short all-in (ShortAllInBet flag blocks further raises this round)."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": ["type"],
|
|
80
|
+
"additionalProperties": false,
|
|
81
|
+
"properties": {
|
|
82
|
+
"type": { "const": "allin" },
|
|
83
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
84
|
+
},
|
|
85
|
+
"description": "Bet all remaining chips. Legal whenever you have chips. Creates side pot if < current_bet + min_raise (short all-in)."
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/texas_holdem/config.schema.json",
|
|
4
|
+
"title": "TexasHoldemConfig",
|
|
5
|
+
"description": "Per-match configuration delivered in server_game_start.data.config when game == 'texas_holdem'. These are optional overrides; when omitted, server uses defaults from games/texasholdem/texasholdem.go NewState() (sb=200, bb=400, starting_chips=10000, max_hands=10). All values arrive as JSON numbers (Go side casts from float64).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"properties": {
|
|
9
|
+
"small_blind": {
|
|
10
|
+
"type": "number",
|
|
11
|
+
"minimum": 1,
|
|
12
|
+
"description": "Small blind amount for early hands. Default 200. Doubles at hand 6 automatically (server-side)."
|
|
13
|
+
},
|
|
14
|
+
"big_blind": {
|
|
15
|
+
"type": "number",
|
|
16
|
+
"minimum": 1,
|
|
17
|
+
"description": "Big blind amount for early hands. Default 400."
|
|
18
|
+
},
|
|
19
|
+
"starting_chips": {
|
|
20
|
+
"type": "number",
|
|
21
|
+
"minimum": 1,
|
|
22
|
+
"description": "Per-player starting chips. Default 10000."
|
|
23
|
+
},
|
|
24
|
+
"max_hands": {
|
|
25
|
+
"type": "number",
|
|
26
|
+
"minimum": 1,
|
|
27
|
+
"description": "Number of hands in the match. Default 10. Match ends after max_hands OR when only one player has chips."
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/texas_holdem/event.schema.json",
|
|
4
|
+
"title": "TexasHoldemEvent",
|
|
5
|
+
"description": "Texas Hold'em-specific event payload, describing the `data` field of common/event.schema.json when the event occurred in a Texas Hold'em match. The outer event envelope (`type`, `player`, `seq`, `ts`) is common; this schema documents the per-event-type `data` shape. Discriminator is the outer `type` field. Mirrors games/texasholdem/texasholdem.go emission sites.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "object",
|
|
9
|
+
"description": "new_hand — emitted at start of every hand (initial + subsequent). No `player` field on the outer envelope.",
|
|
10
|
+
"required": ["hand_num", "max_hands", "dealer", "chips", "small_blind", "big_blind"],
|
|
11
|
+
"additionalProperties": false,
|
|
12
|
+
"properties": {
|
|
13
|
+
"hand_num": { "type": "integer", "minimum": 1 },
|
|
14
|
+
"max_hands": { "type": "integer", "minimum": 1 },
|
|
15
|
+
"dealer": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Player ID of the dealer this hand."
|
|
18
|
+
},
|
|
19
|
+
"chips": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"description": "Map of player_id -> pre-blind chip count.",
|
|
22
|
+
"additionalProperties": { "type": "integer", "minimum": 0 }
|
|
23
|
+
},
|
|
24
|
+
"small_blind": { "type": "integer", "minimum": 1 },
|
|
25
|
+
"big_blind": { "type": "integer", "minimum": 1 }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "object",
|
|
30
|
+
"description": "player_action — emitted whenever any player takes a betting action (including blinds). Outer envelope's `player` is the actor.",
|
|
31
|
+
"required": ["action"],
|
|
32
|
+
"additionalProperties": true,
|
|
33
|
+
"properties": {
|
|
34
|
+
"action": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"enum": ["small_blind", "big_blind", "fold", "check", "call", "raise", "allin"]
|
|
37
|
+
},
|
|
38
|
+
"amount": {
|
|
39
|
+
"type": "integer",
|
|
40
|
+
"minimum": 0,
|
|
41
|
+
"description": "Chips bet this action (delta). Present for blinds/call/raise/allin; omitted for fold/check."
|
|
42
|
+
},
|
|
43
|
+
"total_bet": {
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"minimum": 0,
|
|
46
|
+
"description": "Player's total bet this round after this action."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "object",
|
|
52
|
+
"description": "community_cards — emitted at flop/turn/river when cards are revealed. No `player`.",
|
|
53
|
+
"required": ["cards"],
|
|
54
|
+
"additionalProperties": true,
|
|
55
|
+
"properties": {
|
|
56
|
+
"cards": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": { "type": "string" },
|
|
59
|
+
"description": "Card notation (e.g. ['2h', '3d', '7s'] for flop)."
|
|
60
|
+
},
|
|
61
|
+
"phase": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": ["flop", "turn", "river"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "object",
|
|
69
|
+
"description": "cards_dealt — (rare) emitted when hole cards are re-disclosed during reconnect scenarios. Outer envelope's `player` is the card owner.",
|
|
70
|
+
"required": ["cards"],
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"properties": {
|
|
73
|
+
"cards": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "string" },
|
|
76
|
+
"minItems": 2,
|
|
77
|
+
"maxItems": 2,
|
|
78
|
+
"description": "The player's 2 hole cards."
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"type": "object",
|
|
84
|
+
"description": "hand_result — emitted at hand end. No `player`; pot distribution and winners listed in `data`.",
|
|
85
|
+
"required": ["winners", "pot"],
|
|
86
|
+
"additionalProperties": true,
|
|
87
|
+
"properties": {
|
|
88
|
+
"winners": {
|
|
89
|
+
"type": "array",
|
|
90
|
+
"items": { "type": "string" },
|
|
91
|
+
"description": "Player IDs who won (tie-split gives multiple entries)."
|
|
92
|
+
},
|
|
93
|
+
"pot": {
|
|
94
|
+
"type": "integer",
|
|
95
|
+
"minimum": 0
|
|
96
|
+
},
|
|
97
|
+
"reason": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "How the hand was decided (e.g. 'all_others_folded', 'showdown')."
|
|
100
|
+
},
|
|
101
|
+
"showdown": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"description": "Per-player cards + hand-ranking at showdown (only when reason='showdown'). Key = player_id.",
|
|
104
|
+
"additionalProperties": true
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"type": "object",
|
|
110
|
+
"description": "match_result — emitted at match end (after final hand). No `player`.",
|
|
111
|
+
"required": ["winner", "final_chips"],
|
|
112
|
+
"additionalProperties": true,
|
|
113
|
+
"properties": {
|
|
114
|
+
"winner": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"description": "Player ID with most chips at match end. Empty string on tie."
|
|
117
|
+
},
|
|
118
|
+
"final_chips": {
|
|
119
|
+
"type": "object",
|
|
120
|
+
"description": "Map of player_id -> final chip count.",
|
|
121
|
+
"additionalProperties": { "type": "integer", "minimum": 0 }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"type": "object",
|
|
127
|
+
"description": "player_disconnected — emitted when a player is removed mid-match due to timeout/disconnect. Outer envelope's `player` is the disconnected player.",
|
|
128
|
+
"required": ["reason"],
|
|
129
|
+
"additionalProperties": true,
|
|
130
|
+
"properties": {
|
|
131
|
+
"reason": { "type": "string" }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/texas_holdem/rules.schema.json",
|
|
4
|
+
"title": "TexasHoldemRules",
|
|
5
|
+
"description": "Rules payload for Texas Hold'em, delivered in server_game_start.data.rules when game == 'texas_holdem'. Mirrors games/texasholdem/texasholdem.go Game.Rules(). The server's exact text may evolve; runtime should treat rules as informational and not parse numeric values from strings (e.g. blind amounts come from the `config` field, not from parsing `summary`).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "summary", "available_actions", "key_rules"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": {
|
|
11
|
+
"const": "No-Limit Texas Hold'em"
|
|
12
|
+
},
|
|
13
|
+
"summary": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Free-form summary paragraph; treat as informational."
|
|
16
|
+
},
|
|
17
|
+
"phases": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": { "type": "string" },
|
|
20
|
+
"description": "Human-readable phase descriptions (preflop/flop/turn/river/showdown)."
|
|
21
|
+
},
|
|
22
|
+
"available_actions": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"required": ["fold", "check", "call", "raise", "allin"],
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"properties": {
|
|
27
|
+
"fold": { "type": "string" },
|
|
28
|
+
"check": { "type": "string" },
|
|
29
|
+
"call": { "type": "string" },
|
|
30
|
+
"raise": { "type": "string" },
|
|
31
|
+
"allin": { "type": "string" }
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"key_rules": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": { "type": "string" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/texas_holdem/state.schema.json",
|
|
4
|
+
"title": "TexasHoldemState",
|
|
5
|
+
"description": "Per-player state delivered in server_action_request.data.state (and server_game_state.data.state) when game == 'texas_holdem'. Built by games/texasholdem/texasholdem.go GetPlayerView(). Mixes **public fields** (visible to all: phase, community_cards, pot, etc.) with **private fields** (only visible to recipient: your_hand, your_chips, your_bet, etc.). At showdown (phase == 'done'), all non-folded players' hole cards are revealed via optional `player_N_hand` fields.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"phase", "community_cards", "pot", "current_bet",
|
|
9
|
+
"dealer", "dealer_id", "hand_num", "max_hands",
|
|
10
|
+
"small_blind", "big_blind"
|
|
11
|
+
],
|
|
12
|
+
"additionalProperties": true,
|
|
13
|
+
"properties": {
|
|
14
|
+
"phase": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"enum": ["preflop", "flop", "turn", "river", "showdown", "done"],
|
|
17
|
+
"description": "Current hand phase. 'showdown' = cards compared, 'done' = match fully complete."
|
|
18
|
+
},
|
|
19
|
+
"community_cards": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Card notation: rank (2-9, T, J, Q, K, A) + suit (c, d, h, s). E.g. 'Ah' = Ace of hearts."
|
|
24
|
+
},
|
|
25
|
+
"description": "0 cards preflop; 3 on flop; 4 on turn; 5 on river."
|
|
26
|
+
},
|
|
27
|
+
"pot": {
|
|
28
|
+
"type": "integer",
|
|
29
|
+
"minimum": 0,
|
|
30
|
+
"description": "Total chips in all pots (main + any side pots) this hand."
|
|
31
|
+
},
|
|
32
|
+
"current_bet": {
|
|
33
|
+
"type": "integer",
|
|
34
|
+
"minimum": 0,
|
|
35
|
+
"description": "The highest bet any player has contributed this betting round. To continue, you must match this (by call/raise/allin) or fold."
|
|
36
|
+
},
|
|
37
|
+
"dealer": {
|
|
38
|
+
"type": "integer",
|
|
39
|
+
"minimum": 0,
|
|
40
|
+
"description": "Seat index of the dealer button this hand."
|
|
41
|
+
},
|
|
42
|
+
"dealer_id": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "Player ID of the dealer this hand."
|
|
45
|
+
},
|
|
46
|
+
"hand_num": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"minimum": 1,
|
|
49
|
+
"description": "Current hand number (1-based)."
|
|
50
|
+
},
|
|
51
|
+
"max_hands": {
|
|
52
|
+
"type": "integer",
|
|
53
|
+
"minimum": 1,
|
|
54
|
+
"description": "Total hands in this match."
|
|
55
|
+
},
|
|
56
|
+
"small_blind": { "type": "integer", "minimum": 1 },
|
|
57
|
+
"big_blind": { "type": "integer", "minimum": 1 },
|
|
58
|
+
"current_player_id": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"description": "Player ID currently on the action. Omitted when hand is over or match is done."
|
|
61
|
+
},
|
|
62
|
+
"action_order": {
|
|
63
|
+
"type": "array",
|
|
64
|
+
"items": { "type": "string" },
|
|
65
|
+
"description": "Player IDs in the order they are expected to act this phase (clockwise from first-to-act, busted players removed). Omitted at showdown/done."
|
|
66
|
+
},
|
|
67
|
+
"your_hand": {
|
|
68
|
+
"type": "array",
|
|
69
|
+
"items": { "type": "string" },
|
|
70
|
+
"minItems": 2,
|
|
71
|
+
"maxItems": 2,
|
|
72
|
+
"description": "**PRIVATE.** Your two hole cards."
|
|
73
|
+
},
|
|
74
|
+
"your_chips": {
|
|
75
|
+
"type": "integer",
|
|
76
|
+
"minimum": 0,
|
|
77
|
+
"description": "**PRIVATE.** Your current stack."
|
|
78
|
+
},
|
|
79
|
+
"your_bet": {
|
|
80
|
+
"type": "integer",
|
|
81
|
+
"minimum": 0,
|
|
82
|
+
"description": "**PRIVATE.** Chips you've committed this round (not total-hand)."
|
|
83
|
+
},
|
|
84
|
+
"your_seat": {
|
|
85
|
+
"type": "integer",
|
|
86
|
+
"minimum": 0,
|
|
87
|
+
"description": "**PRIVATE.** Your seat index."
|
|
88
|
+
},
|
|
89
|
+
"your_position": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"description": "**PRIVATE.** Position name (e.g. 'BTN', 'SB', 'BB', 'UTG', 'MP', 'CO')."
|
|
92
|
+
},
|
|
93
|
+
"your_player_id": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": "**PRIVATE.** Your player ID. Matches server_game_start.data.your_player_id."
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# protocol/schema/messages — WebSocket Message Schemas
|
|
2
|
+
|
|
3
|
+
All WebSocket messages between `aifight` runtime and the AIFight server.
|
|
4
|
+
Every message carries the envelope `{type, data, match_id?}`; each schema
|
|
5
|
+
in this directory describes a complete envelope for one `type` constant.
|
|
6
|
+
|
|
7
|
+
**Source of truth:** `internal/hub/hub.go` + `internal/hub/confirmation.go`
|
|
8
|
+
(Go constants `MsgType*`). Any drift between these schemas and the
|
|
9
|
+
deployed server's actual behavior is resolved in favor of server behavior
|
|
10
|
+
(see `../../README.md` authority hierarchy) and requires re-issuing the
|
|
11
|
+
schema.
|
|
12
|
+
|
|
13
|
+
## Server → Client (12)
|
|
14
|
+
|
|
15
|
+
| Schema | Type const | Purpose |
|
|
16
|
+
|--------|-----------|---------|
|
|
17
|
+
| [`server_welcome.schema.json`](./server_welcome.schema.json) | `welcome` | Post-auth handshake; includes agent_id, server_time, available games |
|
|
18
|
+
| [`server_queue_joined.schema.json`](./server_queue_joined.schema.json) | `queue_joined` | Ack of client join_queue |
|
|
19
|
+
| [`server_queue_left.schema.json`](./server_queue_left.schema.json) | `queue_left` | Ack of client leave_queue |
|
|
20
|
+
| [`server_match_confirm_request.schema.json`](./server_match_confirm_request.schema.json) | `match_confirm_request` | Ask non-auto-confirm agents to confirm readiness |
|
|
21
|
+
| [`server_match_cancelled.schema.json`](./server_match_cancelled.schema.json) | `match_cancelled` | Notify that a pending match was cancelled |
|
|
22
|
+
| [`server_game_start.schema.json`](./server_game_start.schema.json) | `game_start` | Match has begun; includes rules, config, your position, players |
|
|
23
|
+
| [`server_readiness_check.schema.json`](./server_readiness_check.schema.json) | `readiness_check` | Ask the outbound Bridge to check its local runtime readiness |
|
|
24
|
+
| [`server_action_request.schema.json`](./server_action_request.schema.json) | `action_request` | Your turn to act; includes state, legal_actions, new_events |
|
|
25
|
+
| [`server_event.schema.json`](./server_event.schema.json) | `event` | Realtime event broadcast (**spectators only** since server 9.3.0; runtime receives events via action_request.new_events) |
|
|
26
|
+
| [`server_game_state.schema.json`](./server_game_state.schema.json) | `game_state` | Reconnect context for non-current-turn players |
|
|
27
|
+
| [`server_game_over.schema.json`](./server_game_over.schema.json) | `game_over` | Match ended; real identities revealed; result + replay_url |
|
|
28
|
+
| [`server_error.schema.json`](./server_error.schema.json) | `error` | Server-side error notification |
|
|
29
|
+
|
|
30
|
+
## Client → Server (5)
|
|
31
|
+
|
|
32
|
+
| Schema | Type const | Purpose |
|
|
33
|
+
|--------|-----------|---------|
|
|
34
|
+
| [`client_join_queue.schema.json`](./client_join_queue.schema.json) | `join_queue` | Request to enter matchmaking queue |
|
|
35
|
+
| [`client_leave_queue.schema.json`](./client_leave_queue.schema.json) | `leave_queue` | Exit queue (also disables auto-requeue) |
|
|
36
|
+
| [`client_match_confirm.schema.json`](./client_match_confirm.schema.json) | `match_confirm` | Confirm readiness for a pending match |
|
|
37
|
+
| [`client_action.schema.json`](./client_action.schema.json) | `action` | Respond to action_request with a chosen action |
|
|
38
|
+
| [`client_runtime_status.schema.json`](./client_runtime_status.schema.json) | `runtime_status` | Report local runtime readiness after a server readiness_check |
|
|
39
|
+
|
|
40
|
+
## Ping / Pong — intentionally not modeled
|
|
41
|
+
|
|
42
|
+
Server-side keepalive uses **WebSocket frame-level ping/pong**
|
|
43
|
+
(`github.com/gorilla/websocket` sends `websocket.PingMessage` frames, not
|
|
44
|
+
application-level `{"type": "ping"}` envelopes; see `internal/hub/hub.go`
|
|
45
|
+
around the write pump). Although the `MsgTypePing` / `MsgTypePong`
|
|
46
|
+
constants exist, they are reserved / handled trivially, and runtime
|
|
47
|
+
implementations do not need a schema for them — they should use
|
|
48
|
+
WebSocket frame-level pong responses.
|
|
49
|
+
|
|
50
|
+
Runtime implementations MUST handle the WebSocket ping/pong reliably in a
|
|
51
|
+
goroutine independent of LLM calls (v1.1.1 plan §5.8 keepalive rule).
|
|
52
|
+
|
|
53
|
+
## Spectator-only messages
|
|
54
|
+
|
|
55
|
+
`spectate_start` (sent in `internal/hub/hub.go:1667`) is a spectator
|
|
56
|
+
connection initializer, not part of the runtime-agent protocol. Runtime
|
|
57
|
+
implementations do not need to handle it and no schema is provided.
|
|
58
|
+
|
|
59
|
+
## Envelope notes
|
|
60
|
+
|
|
61
|
+
- Every message envelope: `{type: string, data: object, match_id?: string}`
|
|
62
|
+
- `type` is always a constant `"..."` (schema uses `const` keyword)
|
|
63
|
+
- `data` structure varies per message type
|
|
64
|
+
- `match_id` is envelope-level; `client_action` requires it; most others
|
|
65
|
+
ignore it or leave it empty
|
|
66
|
+
- All schemas enforce `additionalProperties: false` at both envelope and
|
|
67
|
+
data levels — no silent field drift tolerated
|
|
68
|
+
|
|
69
|
+
## Referenced shared types (`../common/`)
|
|
70
|
+
|
|
71
|
+
- [`common/action.schema.json`](../common/action.schema.json) — Action envelope (`{type, data?}`)
|
|
72
|
+
- [`common/event.schema.json`](../common/event.schema.json) — Event with seq + ts
|
|
73
|
+
- [`common/player_info.schema.json`](../common/player_info.schema.json) — Public player view during match
|
|
74
|
+
- [`common/player_identity.schema.json`](../common/player_identity.schema.json) — Revealed at game_over
|
|
75
|
+
- [`common/game_result.schema.json`](../common/game_result.schema.json) — Match outcome
|
|
76
|
+
- [`common/rules.schema.json`](../common/rules.schema.json) — Rules delivered at game_start
|
|
77
|
+
- [`common/error.schema.json`](../common/error.schema.json) — Error payload for `server_error.data`
|
|
78
|
+
|
|
79
|
+
## Game-specific placeholders (to be filled by P0-03)
|
|
80
|
+
|
|
81
|
+
These fields are intentionally `"type": "object"` (untyped) in the current
|
|
82
|
+
message schemas; P0-03 will narrow them by `$ref` to
|
|
83
|
+
`../games/<game>/{state,action,rules}.schema.json`:
|
|
84
|
+
|
|
85
|
+
- `server_game_start.data.config` — game-specific match config
|
|
86
|
+
- `server_action_request.data.state` — game-specific state (PlayerView.GameData)
|
|
87
|
+
- `common/action.schema.json` → `data` (game-specific action params)
|
|
88
|
+
- `common/event.schema.json` → `data` (game-specific event payload)
|
|
89
|
+
- `common/player_info.schema.json` → `data` (game-specific public player fields)
|
|
90
|
+
- `common/game_result.schema.json` → `details[*]` (game-specific per-player details)
|
|
91
|
+
|
|
92
|
+
## Validation
|
|
93
|
+
|
|
94
|
+
Once P0-09 lands, run:
|
|
95
|
+
```
|
|
96
|
+
pnpm -C protocol/tools run lint
|
|
97
|
+
pnpm -C protocol/tools run validate-transcript protocol/transcripts/**/*.jsonl
|
|
98
|
+
```
|