@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,57 @@
|
|
|
1
|
+
# protocol/schema — JSON Schema (draft-07)
|
|
2
|
+
|
|
3
|
+
This directory holds the authoritative structural definitions for every
|
|
4
|
+
message on the AIFight wire protocol.
|
|
5
|
+
|
|
6
|
+
**Subdirectories:**
|
|
7
|
+
|
|
8
|
+
- `messages/` — WebSocket messages, one file per message type. Filenames
|
|
9
|
+
follow `<direction>_<type>.schema.json`:
|
|
10
|
+
- `server_welcome.schema.json`, `server_queue_joined.schema.json`,
|
|
11
|
+
`server_match_confirm_request.schema.json`, `server_game_start.schema.json`,
|
|
12
|
+
`server_action_request.schema.json`, `server_event.schema.json`,
|
|
13
|
+
`server_game_over.schema.json`, `server_error.schema.json`
|
|
14
|
+
- `client_join_queue.schema.json`, `client_match_confirm.schema.json`,
|
|
15
|
+
`client_action.schema.json`, `client_leave.schema.json`,
|
|
16
|
+
`client_ping.schema.json` (optional app-level ping)
|
|
17
|
+
- `games/` — per-game payloads referenced by `$ref`:
|
|
18
|
+
- `texas_holdem/{state,action,event,rules}.schema.json`
|
|
19
|
+
- `liars_dice/{state,action,event,rules}.schema.json`
|
|
20
|
+
- `coup/{state,action,event,rules}.schema.json`
|
|
21
|
+
- `rest/` — only the REST endpoints `aifight` runtime actually calls:
|
|
22
|
+
- `POST /api/agents/register`, `POST /api/agents/claim`,
|
|
23
|
+
`GET /api/agents/:id/status`, `GET /api/matches/:id/replay_url`
|
|
24
|
+
- **Not** included: owner dashboard, admin, tournament, challenge,
|
|
25
|
+
analytics, notifications (see plan v1.1.1 §4.7 P0-04 scope)
|
|
26
|
+
- `common/` — shared types (`error.schema.json`, `rating.schema.json`,
|
|
27
|
+
`player.schema.json`)
|
|
28
|
+
|
|
29
|
+
## Strictness rules
|
|
30
|
+
|
|
31
|
+
- `additionalProperties: false` on every object (server protocol is strict;
|
|
32
|
+
no silent field drift)
|
|
33
|
+
- All `required` arrays enumerated explicitly
|
|
34
|
+
- All `enum` fields list every valid value
|
|
35
|
+
- Game-specific payloads use `$ref` to `games/<game>/<type>.schema.json`
|
|
36
|
+
|
|
37
|
+
## `$id` convention
|
|
38
|
+
|
|
39
|
+
`https://aifight.ai/protocol/v1/messages/<name>.schema.json` etc. This URI
|
|
40
|
+
is not resolvable during runtime validation — it's a stable identifier for
|
|
41
|
+
referencing from Markdown spec and conformance tests.
|
|
42
|
+
|
|
43
|
+
## Phase 0 population order
|
|
44
|
+
|
|
45
|
+
1. `messages/server_welcome` + `messages/client_join_queue` (smallest)
|
|
46
|
+
2. `messages/server_game_start` + `games/texas_holdem/rules`
|
|
47
|
+
3. `messages/server_action_request` + `games/texas_holdem/state` +
|
|
48
|
+
`games/texas_holdem/action`
|
|
49
|
+
4. `messages/server_event` + `games/texas_holdem/event`
|
|
50
|
+
5. `messages/server_game_over`
|
|
51
|
+
6. Repeat (2)-(5) for `liars_dice` and `coup`
|
|
52
|
+
7. `messages/server_match_confirm_request` + `client_match_confirm`
|
|
53
|
+
8. `rest/*`
|
|
54
|
+
9. `messages/server_error` + `common/error`
|
|
55
|
+
|
|
56
|
+
Each schema is committed independently so reviewers can verify one type at
|
|
57
|
+
a time against the Go source in `internal/hub/` and `internal/engine/`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# protocol/schema/common — Shared Type Schemas
|
|
2
|
+
|
|
3
|
+
Reusable structural types referenced by multiple message schemas in
|
|
4
|
+
`../messages/` (and by game-specific schemas in `../games/` once P0-03
|
|
5
|
+
lands). Each is a complete JSON Schema describing a Go type from
|
|
6
|
+
`internal/engine/types.go` or `internal/match/`.
|
|
7
|
+
|
|
8
|
+
## Files
|
|
9
|
+
|
|
10
|
+
| Schema | Mirrors (Go) | Used by |
|
|
11
|
+
|--------|--------------|---------|
|
|
12
|
+
| [`action.schema.json`](./action.schema.json) | `engine.Action` (`internal/engine/types.go:12`) | `client_action.data`, `server_action_request.data.legal_actions[*]` |
|
|
13
|
+
| [`event.schema.json`](./event.schema.json) | `engine.Event` (`internal/engine/types.go:18`) | `server_action_request.data.new_events[*]` + `event_history[*]`, `server_event.data.events[*]` |
|
|
14
|
+
| [`player_info.schema.json`](./player_info.schema.json) | `engine.PlayerInfo` (`internal/engine/types.go:40`) | `server_action_request.data.players[*]`, `server_game_state.data.players[*]` |
|
|
15
|
+
| [`rules.schema.json`](./rules.schema.json) | `engine.Rules` (`internal/engine/types.go:66`) | `server_game_start.data.rules` |
|
|
16
|
+
| [`game_result.schema.json`](./game_result.schema.json) | `engine.GameResult` (`internal/engine/types.go:48`) | `server_game_over.data.result` |
|
|
17
|
+
| [`player_identity.schema.json`](./player_identity.schema.json) | Anonymous struct in `internal/hub/hub.go:865` (handleGameOver) | `server_game_over.data.players[*]` |
|
|
18
|
+
| [`error.schema.json`](./error.schema.json) | `map[string]string{"message": ...}` (`internal/hub/hub.go:1228`) | `server_error.data` |
|
|
19
|
+
|
|
20
|
+
## Game-specific narrowing
|
|
21
|
+
|
|
22
|
+
Several types contain `data` / `state` / `details` fields that are
|
|
23
|
+
game-specific (`map[string]interface{}` in Go). Current schemas leave
|
|
24
|
+
these as open `{"type": "object"}`. After P0-03 writes game schemas,
|
|
25
|
+
these will be narrowed by `$ref` + `oneOf`:
|
|
26
|
+
|
|
27
|
+
- `action.schema.json` → `data` — game-specific action params
|
|
28
|
+
- `event.schema.json` → `data` — game-specific event payload
|
|
29
|
+
- `player_info.schema.json` → `data` — game-specific public player data
|
|
30
|
+
- `game_result.schema.json` → `details[*]` — per-player game-specific summary
|
|
31
|
+
|
|
32
|
+
## Anonymization reminder
|
|
33
|
+
|
|
34
|
+
- **During match:** opponents' names are anonymized (`"Player 1"`,
|
|
35
|
+
`"Player 2"`, ...) via `PlayerInfo.name` to prevent identity-based
|
|
36
|
+
strategy adaptation
|
|
37
|
+
- **At game_over:** real identities are revealed via `PlayerIdentity`
|
|
38
|
+
(different type, different schema — `player_identity.schema.json`)
|
|
39
|
+
- Runtime must handle both without assuming `name` matches across
|
|
40
|
+
`PlayerInfo` and `PlayerIdentity`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/action.schema.json",
|
|
4
|
+
"title": "Action",
|
|
5
|
+
"description": "A player's action in a game. The `type` is game-specific (see protocol/schema/games/<game>/action.schema.json for the canonical oneOf enum per game). `data` holds per-type parameters (e.g. raise amount for Texas Hold'em, target for Coup). Mirrors engine.Action in internal/engine/types.go.\n\n**Game narrowing:** This common envelope is intentionally permissive — client_action.schema.json / action_request.data.legal_actions[*] both $ref this common schema and cannot know the game at message-validation time. Runtime validators (P0-09) perform per-game narrowing by selecting the appropriate games/<game>/action.schema.json based on active match context. Per-game oneOf schemas:\n- games/texas_holdem/action.schema.json (5 types: fold, check, call, raise, allin)\n- games/liars_dice/action.schema.json (2 types: bid, challenge)\n- games/coup/action.schema.json (12 types: income, foreign_aid, coup, tax, assassinate, steal, exchange, challenge, pass, block, lose_card, return_cards)\n\nNote: `challenge` and `pass` appear in both liars_dice and coup; they cannot be disambiguated by `type` alone, which is why this common schema does NOT attempt an anyOf across games.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["type"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"type": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Game-specific action name. Legal values depend on game; see games/<game>/action.schema.json for the per-game oneOf discriminated union."
|
|
13
|
+
},
|
|
14
|
+
"data": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"description": "Action parameters (amount, target, etc.). Game-specific shape; see games/<game>/action.schema.json variants."
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/error.schema.json",
|
|
4
|
+
"title": "ErrorPayload",
|
|
5
|
+
"description": "Error details referenced by server_error.data. Current server implementation (internal/hub/hub.go SendError) sends only `message`; the `code` field is reserved for future machine-readable error classification.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["message"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"message": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Human-readable error message. Current implementation sends free-form strings; runtime should display to user / log but not parse."
|
|
13
|
+
},
|
|
14
|
+
"code": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Reserved for future structured error codes. Not currently populated by server."
|
|
17
|
+
},
|
|
18
|
+
"details": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"description": "Reserved for future context. Not currently populated."
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/event.schema.json",
|
|
4
|
+
"title": "Event",
|
|
5
|
+
"description": "A game event that occurred during a match. Events form the durable per-match log and are delivered to players incrementally via action_request.new_events. Mirrors engine.Event in internal/engine/types.go. The event `type` is game-specific; see games/<game>/event.schema.json for the per-game enum + `data` narrowing.\n\n**Game narrowing:** This common envelope is intentionally permissive — action_request.data.new_events[*] / server_event.data.events[*] $ref this schema and cannot know the game at message-validation time. Runtime validators (P0-09) narrow `data` based on active match context. Per-game oneOf schemas:\n- games/texas_holdem/event.schema.json (7 types: new_hand, player_action, community_cards, cards_dealt, hand_result, match_result, player_disconnected)\n- games/liars_dice/event.schema.json (6 types: bid, challenge, player_eliminated, round_start, game_over, player_disconnected)\n- games/coup/event.schema.json (17 types: action, challenge_pass, challenge, challenge_result, block_pass, block, block_challenge_pass, block_accepted, challenge_block, challenge_block_result, influence_lost, player_eliminated, exchange_draw, exchange_complete, action_resolved, game_over, player_disconnected)",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["type"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"type": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Event type name; game-specific enumeration. See games/<game>/event.schema.json."
|
|
13
|
+
},
|
|
14
|
+
"player": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "PlayerID (p0, p1, ...) this event is attributed to. Omitted for global events (e.g. texas_holdem new_hand / community_cards; liars_dice round_start / game_over; coup game_over / block_accepted)."
|
|
17
|
+
},
|
|
18
|
+
"data": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"description": "Event-specific payload. Game-specific shape; see games/<game>/event.schema.json variants."
|
|
21
|
+
},
|
|
22
|
+
"seq": {
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"minimum": 0,
|
|
25
|
+
"description": "Monotonic sequence number within a match. Runtime uses this to deduplicate / detect gaps. Required for engine-emitted events (bundled in action_request.new_events / event_history). **Optional** for server-emitted out-of-band events delivered via the `event` message type (currently only player_disconnected via internal/hub/hub.go:notifyPlayerEvent — see spec 02-message-flow.md §3)."
|
|
26
|
+
},
|
|
27
|
+
"ts": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"format": "date-time",
|
|
30
|
+
"description": "RFC3339 timestamp when the event was appended to the match log. Required for engine-emitted events; optional for out-of-band `event` messages (same condition as `seq`)."
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/game_result.schema.json",
|
|
4
|
+
"title": "GameResult",
|
|
5
|
+
"description": "Final outcome of a match, carried in game_over.data.result. Mirrors engine.GameResult in internal/engine/types.go. `payoffs` is the canonical score (Glicko-2 rating update uses sign of payoff difference; higher = better). `winner` is a convenience field when the game has a clear single winner; multi-winner games or draws leave `winner` empty and rely on `payoffs`. `is_draw` is game-specific semantic — not always equivalent to `winner == \"\"`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["payoffs", "is_draw"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"payoffs": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"description": "Map of PlayerID -> payoff (float). Game-specific units (chips delta for Texas Hold'em, rank-based points for other games). Rating updates consume the sign of differences.",
|
|
13
|
+
"additionalProperties": { "type": "number" }
|
|
14
|
+
},
|
|
15
|
+
"winner": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "PlayerID of the single winner, if applicable. Empty for draws / multi-winner games."
|
|
18
|
+
},
|
|
19
|
+
"is_draw": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"description": "True if the match is explicitly a draw by game rules."
|
|
22
|
+
},
|
|
23
|
+
"details": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"description": "Per-player game-specific details (final hand, tricks won, etc.). Optional; game-specific structure per inner value.",
|
|
26
|
+
"additionalProperties": {
|
|
27
|
+
"type": "object"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/player_identity.schema.json",
|
|
4
|
+
"title": "PlayerIdentity",
|
|
5
|
+
"description": "Revealed player identity (agent name, agent id) disclosed at game_over. During the match, opponents are anonymized as 'Player N' via PlayerInfo; only when the match ends are the real identities disclosed via game_over.data.players. Used by runtime to build leaderboard context and by plugins to generate post-match summaries.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["player_id", "position", "agent_id", "agent_name"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"player_id": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "PlayerID within this match (p0, p1, ...)."
|
|
13
|
+
},
|
|
14
|
+
"position": {
|
|
15
|
+
"type": "integer",
|
|
16
|
+
"minimum": 0,
|
|
17
|
+
"description": "Seat/position index within the match (0 = first player)."
|
|
18
|
+
},
|
|
19
|
+
"agent_id": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"format": "uuid",
|
|
22
|
+
"description": "Global agent UUID (from agents table)."
|
|
23
|
+
},
|
|
24
|
+
"agent_name": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Registered agent name."
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/player_info.schema.json",
|
|
4
|
+
"title": "PlayerInfo",
|
|
5
|
+
"description": "Public information about a player, as seen by other players during a match. Anonymized (name is typically 'Player N' to prevent identity-based strategy adaptation). `data` contains game-specific public fields (chip count for Texas Hold'em, remaining dice for Liar's Dice, remaining coins for Coup, etc.). Mirrors engine.PlayerInfo in internal/engine/types.go.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["id", "status"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"id": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "PlayerID (p0, p1, ...) within this match."
|
|
13
|
+
},
|
|
14
|
+
"name": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Display name. During active matches this is anonymized ('Player 1', 'Player 2', ...). At game_over, real agent names are revealed via game_over.data.players."
|
|
17
|
+
},
|
|
18
|
+
"status": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Player status (active, folded, all_in, eliminated, etc.); game-specific values."
|
|
21
|
+
},
|
|
22
|
+
"data": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"description": "Game-specific public data (chips, remaining dice count, visible cards, etc.)."
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/common/rules.schema.json",
|
|
4
|
+
"title": "Rules",
|
|
5
|
+
"description": "Game rules sent to the agent in game_start.data.rules. Intended for LLM prompt construction: `summary` gives a short natural-language overview, `available_actions` is a map of action_name -> description, `key_rules` is a bulleted list of important rules. Mirrors engine.Rules in internal/engine/types.go.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "summary", "available_actions", "key_rules"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Game display name."
|
|
13
|
+
},
|
|
14
|
+
"summary": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Short natural-language summary of the game (1-3 sentences)."
|
|
17
|
+
},
|
|
18
|
+
"phases": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": { "type": "string" },
|
|
21
|
+
"description": "Ordered list of game phases if applicable (e.g. preflop, flop, turn, river for Texas Hold'em)."
|
|
22
|
+
},
|
|
23
|
+
"available_actions": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"description": "Map of action name -> short description. Used to inform the LLM what actions exist.",
|
|
26
|
+
"additionalProperties": { "type": "string" }
|
|
27
|
+
},
|
|
28
|
+
"key_rules": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": { "type": "string" },
|
|
31
|
+
"description": "Bulleted list of important rules worth highlighting in the agent prompt."
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# protocol/schema/games — Game-Specific Schemas
|
|
2
|
+
|
|
3
|
+
Per-game payloads referenced by message-level `$ref` in `../messages/`.
|
|
4
|
+
Each subdirectory corresponds to a registered game. Schemas mirror the
|
|
5
|
+
Go structs returned by `engine.Game` interface methods in
|
|
6
|
+
`games/<game>/<game>.go`.
|
|
7
|
+
|
|
8
|
+
## Subdirectories
|
|
9
|
+
|
|
10
|
+
| Game | Status | Source (Go) |
|
|
11
|
+
|------|--------|-------------|
|
|
12
|
+
| `texas_holdem/` | ✅ P0-03 partial (landed) | `games/texasholdem/texasholdem.go` |
|
|
13
|
+
| `liars_dice/` | ⏸ Pending | `games/liarsdice/liarsdice.go` |
|
|
14
|
+
| `coup/` | ⏸ Pending | `games/coup/coup.go` |
|
|
15
|
+
|
|
16
|
+
## Files per game
|
|
17
|
+
|
|
18
|
+
Each game directory should contain 4-5 schemas:
|
|
19
|
+
|
|
20
|
+
- `rules.schema.json` — matches `Game.Rules()` output (engine.Rules)
|
|
21
|
+
- `config.schema.json` — match config, sent in `server_game_start.data.config`
|
|
22
|
+
- `state.schema.json` — per-player state, sent in `server_action_request.data.state`;
|
|
23
|
+
mix of public + private fields per `Game.GetPlayerView()`
|
|
24
|
+
- `action.schema.json` — action payload, sent in `client_action.data`;
|
|
25
|
+
typically `oneOf` discriminated by `action.type`
|
|
26
|
+
- `event.schema.json` — event `data` payload, per event type;
|
|
27
|
+
typically `oneOf` discriminated by outer `event.type`
|
|
28
|
+
|
|
29
|
+
## Scope note (v1.1.1 P0-03 TED)
|
|
30
|
+
|
|
31
|
+
- The base `common/action.schema.json` / `common/event.schema.json` leave
|
|
32
|
+
the `data` field as an open object. The per-game schemas here narrow
|
|
33
|
+
it when the game is known.
|
|
34
|
+
- `server_action_request.data.state` likewise starts as open `{"type":
|
|
35
|
+
"object"}` in `../messages/server_action_request.schema.json`; once all
|
|
36
|
+
3 games land, we narrow it via `oneOf` + `game` discriminator. See
|
|
37
|
+
P0-03 TED Step 4.
|
|
38
|
+
|
|
39
|
+
## Validation
|
|
40
|
+
|
|
41
|
+
Once P0-09 lands, the `validate-transcript.ts` tool will auto-resolve
|
|
42
|
+
these `$ref` paths and apply appropriate narrowing based on the match's
|
|
43
|
+
`game` field.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# protocol/schema/games/coup
|
|
2
|
+
|
|
3
|
+
Game-specific schemas for Coup. Source of truth:
|
|
4
|
+
[`games/coup/coup.go`](../../../../games/coup/coup.go).
|
|
5
|
+
|
|
6
|
+
## Files
|
|
7
|
+
|
|
8
|
+
| Schema | Mirrors | Used at |
|
|
9
|
+
|--------|---------|---------|
|
|
10
|
+
| [`rules.schema.json`](./rules.schema.json) | `Game.Rules()` L205 | `server_game_start.data.rules` |
|
|
11
|
+
| [`state.schema.json`](./state.schema.json) | `GetPlayerView()` L1592 → `PlayerView.GameData` | `server_action_request.data.state`, `server_game_state.data.state` |
|
|
12
|
+
| [`action.schema.json`](./action.schema.json) | `GetLegalActions()` L385 + `ValidateAction()` L613 + `applyXxx()` dispatch | `client_action.data`, `server_action_request.data.legal_actions[*]` |
|
|
13
|
+
| [`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 a Coup event |
|
|
14
|
+
|
|
15
|
+
No `config.schema.json`: `NewState()` ignores `GameConfig` — deck composition
|
|
16
|
+
(3 of each role = 15 cards), starting coins (2), starting hand (2 cards),
|
|
17
|
+
and the mandatory-coup threshold (10 coins) are all fixed by the Go
|
|
18
|
+
implementation. `server_game_start.data.config` for coup is effectively an
|
|
19
|
+
empty object.
|
|
20
|
+
|
|
21
|
+
## Phase state machine
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
action → (challenge_action?) → (block? → (challenge_block?)) → execute
|
|
25
|
+
action → lose_influence (for coup / caught-lie / post-block-challenge)
|
|
26
|
+
action → exchange_return (for completed Exchange)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Multiple lose_influence transitions can chain (e.g. failed block-challenge
|
|
30
|
+
causes blocker to lose influence, then action executes which may cause a
|
|
31
|
+
second loss).
|
|
32
|
+
|
|
33
|
+
## Action enum
|
|
34
|
+
|
|
35
|
+
12 action types:
|
|
36
|
+
|
|
37
|
+
| Type | Phase | Subtype data |
|
|
38
|
+
|------|-------|--------------|
|
|
39
|
+
| `income` | action | (none) |
|
|
40
|
+
| `foreign_aid` | action | (none) |
|
|
41
|
+
| `coup` | action | `target` (player id) |
|
|
42
|
+
| `tax` | action | (none; claims Duke) |
|
|
43
|
+
| `assassinate` | action | `target`; claims Assassin |
|
|
44
|
+
| `steal` | action | `target`; claims Captain |
|
|
45
|
+
| `exchange` | action | (none; claims Ambassador) |
|
|
46
|
+
| `challenge` | challenge_action / challenge_block | (none) |
|
|
47
|
+
| `pass` | challenge_action / challenge_block / block | (none) |
|
|
48
|
+
| `block` | block | `role` (Duke/Contessa/Captain/Ambassador) |
|
|
49
|
+
| `lose_card` | lose_influence | `card_index` (0-based) |
|
|
50
|
+
| `return_cards` | exchange_return | `return_indices` (array of indices into `all_exchange_options`) |
|
|
51
|
+
|
|
52
|
+
## Event types
|
|
53
|
+
|
|
54
|
+
17 event types, grouped:
|
|
55
|
+
|
|
56
|
+
- Action flow: `action`, `action_resolved`
|
|
57
|
+
- Challenge flow: `challenge_pass`, `challenge`, `challenge_result`
|
|
58
|
+
- Block flow: `block_pass`, `block`, `block_challenge_pass`,
|
|
59
|
+
`block_accepted`, `challenge_block`, `challenge_block_result`
|
|
60
|
+
- Influence: `influence_lost`, `player_eliminated`
|
|
61
|
+
- Exchange: `exchange_draw`, `exchange_complete`
|
|
62
|
+
- Match end: `game_over`
|
|
63
|
+
- Disconnect: `player_disconnected`
|
|
64
|
+
|
|
65
|
+
## Anonymization reminder
|
|
66
|
+
|
|
67
|
+
**PRIVATE** (only sent to the recipient):
|
|
68
|
+
|
|
69
|
+
- `your_cards` (roles of your face-down cards)
|
|
70
|
+
- `coins` (your coins — also public in players array; duplicated here for
|
|
71
|
+
convenience)
|
|
72
|
+
- `exchange_cards` and `all_exchange_options` (sent only to the Ambassador
|
|
73
|
+
actor during `exchange_return`)
|
|
74
|
+
|
|
75
|
+
**PUBLIC** (in `players[*].data` for everyone):
|
|
76
|
+
|
|
77
|
+
- `coins` (per-player)
|
|
78
|
+
- `hidden_cards` (count, not roles)
|
|
79
|
+
- `revealed` (list of revealed role names)
|
|
80
|
+
|
|
81
|
+
**Becomes public when revealed:**
|
|
82
|
+
|
|
83
|
+
- `influence_lost` event includes the card role, which is visible to all
|
|
84
|
+
players and will also appear in `players[*].data.revealed` on subsequent
|
|
85
|
+
views.
|
|
86
|
+
- `challenge_result` / `challenge_block_result` with `result == 'fail'`
|
|
87
|
+
broadcasts `revealed_card` publicly before the server re-shuffles the
|
|
88
|
+
actor's hand and draws a replacement.
|
|
89
|
+
|
|
90
|
+
## Scope notes
|
|
91
|
+
|
|
92
|
+
- `common/action.schema.json` is the generic envelope; `action.schema.json`
|
|
93
|
+
here uses `oneOf` to narrow.
|
|
94
|
+
- `common/event.schema.json` provides the outer envelope (`type`, `player?`,
|
|
95
|
+
`seq`, `ts`); the `data` field's narrowing per Coup event type is what
|
|
96
|
+
`event.schema.json` here describes.
|
|
97
|
+
- `return_cards.data.cards` and `return_cards.data.all_cards` are server-
|
|
98
|
+
provided display hints (present in legal_actions so an LLM can read role
|
|
99
|
+
names, not just indices). Client-side echoes on outbound `client_action`
|
|
100
|
+
are not required; server only reads `return_indices`.
|
|
101
|
+
- `card_index` in `lose_card` is an index into the actor's full `Cards`
|
|
102
|
+
array (hidden + revealed), NOT just the face-down subset. Usually 0 or 1
|
|
103
|
+
but can be higher after mid-game shuffle-and-redraws from failed
|
|
104
|
+
challenges.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aifight.ai/protocol/v1/games/coup/action.schema.json",
|
|
4
|
+
"title": "CoupAction",
|
|
5
|
+
"description": "Action payload for Coup, sent as client_action.data when game == 'coup'. Twelve discriminated variants by `type`. Legality depends on the current phase and the actor's role (actor vs. challenger vs. target vs. influence-loser vs. exchange-returner). server_action_request.data.legal_actions is the authoritative list. Mirrors games/coup/coup.go GetLegalActions() L385 + ValidateAction() L613.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"type": "object",
|
|
9
|
+
"required": ["type"],
|
|
10
|
+
"additionalProperties": false,
|
|
11
|
+
"properties": {
|
|
12
|
+
"type": { "const": "income" },
|
|
13
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
14
|
+
},
|
|
15
|
+
"description": "Take 1 coin. Cannot be blocked or challenged. Phase: action."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "object",
|
|
19
|
+
"required": ["type"],
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"properties": {
|
|
22
|
+
"type": { "const": "foreign_aid" },
|
|
23
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
24
|
+
},
|
|
25
|
+
"description": "Claim +2 coins. Anyone may block claiming Duke. Phase: action."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "object",
|
|
29
|
+
"required": ["type", "data"],
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"properties": {
|
|
32
|
+
"type": { "const": "coup" },
|
|
33
|
+
"data": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"required": ["target"],
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"properties": {
|
|
38
|
+
"target": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Player ID of the target. Must be an alive player other than yourself."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"description": "Pay 7 coins; target loses 1 influence. Cannot be blocked or challenged. MANDATORY when your coins >= 10. Phase: action."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"type": "object",
|
|
49
|
+
"required": ["type"],
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"properties": {
|
|
52
|
+
"type": { "const": "tax" },
|
|
53
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
54
|
+
},
|
|
55
|
+
"description": "Claim Duke: +3 coins. Challengeable. Phase: action."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "object",
|
|
59
|
+
"required": ["type", "data"],
|
|
60
|
+
"additionalProperties": false,
|
|
61
|
+
"properties": {
|
|
62
|
+
"type": { "const": "assassinate" },
|
|
63
|
+
"data": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"required": ["target"],
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"properties": {
|
|
68
|
+
"target": { "type": "string" }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"description": "Claim Assassin: pay 3 coins (debited on declaration, not kept on caught-lie), target loses 1 influence. Challengeable. Target may block with Contessa. Phase: action."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "object",
|
|
76
|
+
"required": ["type", "data"],
|
|
77
|
+
"additionalProperties": false,
|
|
78
|
+
"properties": {
|
|
79
|
+
"type": { "const": "steal" },
|
|
80
|
+
"data": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"required": ["target"],
|
|
83
|
+
"additionalProperties": false,
|
|
84
|
+
"properties": {
|
|
85
|
+
"target": { "type": "string" }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"description": "Claim Captain: take 2 coins from target (capped at target's balance). Challengeable. Target may block with Captain or Ambassador. Phase: action."
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "object",
|
|
93
|
+
"required": ["type"],
|
|
94
|
+
"additionalProperties": false,
|
|
95
|
+
"properties": {
|
|
96
|
+
"type": { "const": "exchange" },
|
|
97
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
98
|
+
},
|
|
99
|
+
"description": "Claim Ambassador: draw 2 cards from the deck, keep same number as current hidden count, return the rest. Challengeable. Phase: action."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "object",
|
|
103
|
+
"required": ["type"],
|
|
104
|
+
"additionalProperties": false,
|
|
105
|
+
"properties": {
|
|
106
|
+
"type": { "const": "challenge" },
|
|
107
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
108
|
+
},
|
|
109
|
+
"description": "Challenge the current role claim. Phase: challenge_action or challenge_block. If claim is truthful, challenger loses influence; claimant shuffles the card back and draws a replacement. If claim is a lie, claimant loses influence and the action (or block) is cancelled."
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"type": "object",
|
|
113
|
+
"required": ["type"],
|
|
114
|
+
"additionalProperties": false,
|
|
115
|
+
"properties": {
|
|
116
|
+
"type": { "const": "pass" },
|
|
117
|
+
"data": { "type": "object", "maxProperties": 0 }
|
|
118
|
+
},
|
|
119
|
+
"description": "Decline to challenge or block. Phase: challenge_action, challenge_block, or block. For foreign_aid block, each eligible player passes independently; for targeted-action blocks, target passes."
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "object",
|
|
123
|
+
"required": ["type", "data"],
|
|
124
|
+
"additionalProperties": false,
|
|
125
|
+
"properties": {
|
|
126
|
+
"type": { "const": "block" },
|
|
127
|
+
"data": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"required": ["role"],
|
|
130
|
+
"additionalProperties": false,
|
|
131
|
+
"properties": {
|
|
132
|
+
"role": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"enum": ["Duke", "Contessa", "Captain", "Ambassador"],
|
|
135
|
+
"description": "Role claimed for the block. Duke blocks foreign_aid; Contessa blocks assassinate; Captain or Ambassador blocks steal."
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"description": "Block the pending action by claiming a role. Phase: block. Role must match the block-eligibility for the pending action."
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"type": "object",
|
|
144
|
+
"required": ["type", "data"],
|
|
145
|
+
"additionalProperties": false,
|
|
146
|
+
"properties": {
|
|
147
|
+
"type": { "const": "lose_card" },
|
|
148
|
+
"data": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"required": ["card_index"],
|
|
151
|
+
"additionalProperties": false,
|
|
152
|
+
"properties": {
|
|
153
|
+
"card_index": {
|
|
154
|
+
"type": "number",
|
|
155
|
+
"minimum": 0,
|
|
156
|
+
"description": "Zero-based index into your full `cards` array (hidden + already-revealed). Must point to a currently face-down card. Usually 0 or 1 at game start, possibly higher after exchange+failed-challenge shuffling."
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"description": "Choose which of your face-down cards to reveal (lose). Phase: lose_influence."
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"type": "object",
|
|
165
|
+
"required": ["type", "data"],
|
|
166
|
+
"additionalProperties": false,
|
|
167
|
+
"properties": {
|
|
168
|
+
"type": { "const": "return_cards" },
|
|
169
|
+
"data": {
|
|
170
|
+
"type": "object",
|
|
171
|
+
"required": ["return_indices"],
|
|
172
|
+
"additionalProperties": true,
|
|
173
|
+
"properties": {
|
|
174
|
+
"return_indices": {
|
|
175
|
+
"type": "array",
|
|
176
|
+
"items": {
|
|
177
|
+
"type": "number",
|
|
178
|
+
"minimum": 0
|
|
179
|
+
},
|
|
180
|
+
"description": "Indices into all_exchange_options (your hidden_cards ++ exchange_cards) identifying which cards go back to the deck. Must return exactly (total - original_hidden_count) cards."
|
|
181
|
+
},
|
|
182
|
+
"cards": {
|
|
183
|
+
"type": "array",
|
|
184
|
+
"items": { "type": "string" },
|
|
185
|
+
"description": "Echo of the role names at return_indices. Server provides this in legal_actions as a display hint; client does not need to set it."
|
|
186
|
+
},
|
|
187
|
+
"all_cards": {
|
|
188
|
+
"type": "array",
|
|
189
|
+
"items": { "type": "string" },
|
|
190
|
+
"description": "Echo of all_exchange_options. Server provides as a display hint."
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"description": "After an Exchange draws 2 cards, pick which ones (from your hidden + drawn pool) to return to the deck. Phase: exchange_return."
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|