170 lines
8.3 KiB
Markdown
170 lines
8.3 KiB
Markdown
|
|
# botagent_gear Architecture & Workflow Diagrams
|
|||
|
|
|
|||
|
|
This document outlines the system architecture, component relationships, and decision workflows of **`botagent_gear`**, the Google Cloud Vertex AI (Gemini) autonomous agent for **botWebWars**.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. System Architecture Diagram
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph HostEnv["Environment & Configuration"]
|
|||
|
|
ENV["CLI Flags & Environment Variables<br/>(BOT_SERVER_URL, VERTEX_MODEL, etc.)"]
|
|||
|
|
AUTH_SRC["Auth Sources<br/>(ADC / gcloud / Service Account / API Key)"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph BotAgentGear["botagent_gear (bot.py)"]
|
|||
|
|
subgraph ClientLayer["LLM & Authentication Subsystem"]
|
|||
|
|
VGC["VertexGeminiClient<br/>Token cache, auth check, endpoint routing"]
|
|||
|
|
AUTH_RESOLV["Auth Resolver<br/>google.auth / gcloud CLI / API Key"]
|
|||
|
|
PROMPT_ENG["Prompt & Payload Builder<br/>System Instructions + JSON Schema Mode"]
|
|||
|
|
JSON_PARSE["extract_json<br/>Markdown stripping & JSON validation"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph CoreAgent["VertexAIBotAgent Subsystem"]
|
|||
|
|
RUN_LOOP["Turn Polling Loop<br/>GET /api/turn"]
|
|||
|
|
PERCEPTION["Perception Engine<br/>• Radar targets (distance, party, strength)<br/>• Available moves & diagonal squeeze cost<br/>• _build_local_map (17x17 ASCII minimap)"]
|
|||
|
|
|
|||
|
|
subgraph StrategyEngine["Decision & Rules Engine"]
|
|||
|
|
ENCOUNTER["Encounter Evaluator<br/>_handle_adjacent_encounter"]
|
|||
|
|
RULES_GUARD["Mandatory Rules Enforcer<br/>(GAME_RULES.md: forced joins & battles)"]
|
|||
|
|
LLM_ALLIANCE["Voluntary Alliance Reasoner<br/>_decide_voluntary_alliance (Gemini)"]
|
|||
|
|
LLM_NAV["Tactical Navigation Reasoner<br/>_ask_llm_for_direction (Gemini)"]
|
|||
|
|
FALLBACK["Guardrail / Fallback Pathing<br/>Server recommended or nearest distance"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
ACTIONS["Action Dispatcher<br/>• Move bot (/move)<br/>• Form party (/parties)<br/>• Initiate battle (/battles/fight)<br/>• Pass turn (/pass)"]
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph ExternalBackends["External Services"]
|
|||
|
|
SERVER["botWebWars Backend (FastAPI)<br/>Port 8000 REST API"]
|
|||
|
|
GEMINI["Google Vertex AI / AI Studio<br/>gemini-2.5-flash / gemini-3.8-flash"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
%% Wiring
|
|||
|
|
ENV --> CoreAgent
|
|||
|
|
AUTH_SRC --> AUTH_RESOLV
|
|||
|
|
AUTH_RESOLV --> VGC
|
|||
|
|
VGC --> PROMPT_ENG
|
|||
|
|
PROMPT_ENG --> GEMINI
|
|||
|
|
GEMINI --> JSON_PARSE
|
|||
|
|
JSON_PARSE --> VGC
|
|||
|
|
|
|||
|
|
RUN_LOOP --> SERVER
|
|||
|
|
RUN_LOOP --> PERCEPTION
|
|||
|
|
PERCEPTION --> SERVER
|
|||
|
|
PERCEPTION --> StrategyEngine
|
|||
|
|
|
|||
|
|
StrategyEngine --> VGC
|
|||
|
|
LLM_ALLIANCE -.-> VGC
|
|||
|
|
LLM_NAV -.-> VGC
|
|||
|
|
|
|||
|
|
StrategyEngine --> ACTIONS
|
|||
|
|
RULES_GUARD --> ACTIONS
|
|||
|
|
FALLBACK --> ACTIONS
|
|||
|
|
ACTIONS --> SERVER
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Turn Execution & Tactical Decision Flow
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
Start(["Turn Polled (bot's turn)"]) --> Refresh["refresh_status & fetch Radar Data"]
|
|||
|
|
Refresh --> CheckAdj{"Adjacent hostile / neutral<br/>target within distance <= 1?"}
|
|||
|
|
|
|||
|
|
%% Adjacent Target Path
|
|||
|
|
CheckAdj -- Yes --> SoloCheck{"Is current bot Solo?"}
|
|||
|
|
|
|||
|
|
SoloCheck -- "Yes (Solo)" --> TargetPartyCheck{"Is target in a Party?"}
|
|||
|
|
TargetPartyCheck -- "No (Target is Solo)" --> GeminiAlliance["Query Gemini via ask_json<br/>(Voluntary Alliance)"]
|
|||
|
|
GeminiAlliance --> AllianceChoice{"Form Alliance?"}
|
|||
|
|
AllianceChoice -- Yes --> FormParty["POST /api/parties<br/>(Higher strength leads)"]
|
|||
|
|
AllianceChoice -- No --> Pass1["POST /api/players/{id}/pass"]
|
|||
|
|
|
|||
|
|
TargetPartyCheck -- "Yes (Target in Party)" --> CompareLeaderStr{"Bot Strength <= Target Leader Strength?"}
|
|||
|
|
CompareLeaderStr -- Yes --> JoinSquad["Move into squad<br/>(Voluntary absorption)"]
|
|||
|
|
CompareLeaderStr -- No --> FightParty["POST /api/battles/fight<br/>(Mandatory battle: refused weak leader)"]
|
|||
|
|
|
|||
|
|
SoloCheck -- "No (In Party)" --> LeaderCheck{"Is bot the Party Leader?"}
|
|||
|
|
LeaderCheck -- No --> PassFollower["POST /api/players/{id}/pass<br/>(Follow leader command)"]
|
|||
|
|
LeaderCheck -- Yes --> PartyVsTarget{"Target has Party?"}
|
|||
|
|
PartyVsTarget -- Yes --> FightHostile["POST /api/battles/fight<br/>(Mandatory squad battle)"]
|
|||
|
|
PartyVsTarget -- No --> SoloTargetStr{"Solo target <= Leader Strength?"}
|
|||
|
|
SoloTargetStr -- Yes --> AbsorbSolo["Step toward target<br/>(Absorb solo follower)"]
|
|||
|
|
SoloTargetStr -- No --> FightSolo["POST /api/battles/fight<br/>(Mandatory battle: solo refused)"]
|
|||
|
|
|
|||
|
|
%% Navigation Path
|
|||
|
|
CheckAdj -- No --> FetchMoves["Fetch available moves & Board snapshot"]
|
|||
|
|
FetchMoves --> GenMap["_build_local_map<br/>(Generate 17x17 ASCII minimap)"]
|
|||
|
|
GenMap --> AskNav["Query Gemini via ask_json<br/>(Direction & Reasoning)"]
|
|||
|
|
AskNav --> ValidChoice{"Chosen direction in legal moves?"}
|
|||
|
|
ValidChoice -- Yes --> ExecMove["POST /api/players/{id}/move"]
|
|||
|
|
ValidChoice -- No --> FallbackMove["Fallback: Server recommended or nearest distance"]
|
|||
|
|
FallbackMove --> ExecMove
|
|||
|
|
|
|||
|
|
%% Outcome
|
|||
|
|
FormParty --> CheckEnd["Check Game Conclusion"]
|
|||
|
|
Pass1 --> CheckEnd
|
|||
|
|
JoinSquad --> CheckEnd
|
|||
|
|
FightParty --> CheckEnd
|
|||
|
|
PassFollower --> CheckEnd
|
|||
|
|
FightHostile --> CheckEnd
|
|||
|
|
AbsorbSolo --> CheckEnd
|
|||
|
|
FightSolo --> CheckEnd
|
|||
|
|
ExecMove --> CheckEnd
|
|||
|
|
CheckEnd --> Done(["End of Turn"])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Component Deep Dive
|
|||
|
|
|
|||
|
|
### A. Authentication & LLM Client (`VertexGeminiClient`)
|
|||
|
|
- **Module**: [`bot.py`](file:///home/isaac/Workspaces/botWebWars/botagent_gear/bot.py#L82-L269)
|
|||
|
|
- **Multi-Auth Strategy**:
|
|||
|
|
1. `google-auth` Python library using Application Default Credentials (ADC).
|
|||
|
|
2. `gcloud CLI` fallback via `gcloud auth print-access-token`.
|
|||
|
|
3. Direct OAuth token (`VERTEX_ACCESS_TOKEN` or `GOOGLE_OAUTH_ACCESS_TOKEN`).
|
|||
|
|
4. Service Account JSON key (`GOOGLE_APPLICATION_CREDENTIALS`).
|
|||
|
|
5. Direct Gemini API Key (`GEMINI_API_KEY` or `VERTEX_API_KEY`) routing to Google AI Studio.
|
|||
|
|
- **Token Caching**: Access tokens are cached for up to 50 minutes with automatic invalidation and single-retry on HTTP 401.
|
|||
|
|
- **Structured JSON Mode**: Uses `generationConfig.responseMimeType = "application/json"` with low temperature (`0.3`) for deterministic schema adherence.
|
|||
|
|
|
|||
|
|
### B. Perception Engine & Spatial Representation
|
|||
|
|
- **Minimap Generator** ([`_build_local_map`](file:///home/isaac/Workspaces/botWebWars/botagent_gear/bot.py#L542-L574)):
|
|||
|
|
- Generates a **17 × 17 ASCII grid** centered on the bot (`radius = 8`).
|
|||
|
|
- Legend: `@` = self, `A` = ally, `E` = enemy/neutral, `M` = mountain, `F` = forest, `V` = valley, `#` = boundary, `.` = open terrain.
|
|||
|
|
- **Radar & Move Analysis**:
|
|||
|
|
- Consumes `/api/players/{id}/radar` for target distance and party alignment.
|
|||
|
|
- Consumes `/api/players/{id}/available-moves` to account for diagonal obstacle squeeze penalties (`-0.1` solo, `-0.2` leader / `-0.1` follower).
|
|||
|
|
|
|||
|
|
### C. Hybrid Decision & Rules Engine
|
|||
|
|
- **Deterministic Rules Enforcer**:
|
|||
|
|
- Implements canonical rules from [GAME_RULES.md](file:///home/isaac/Workspaces/botWebWars/GAME_RULES.md).
|
|||
|
|
- Mandatory battles and joins bypass LLM invocation to guarantee engine compliance.
|
|||
|
|
- **LLM Discretionary Invocations**:
|
|||
|
|
- **Voluntary Alliances**: Solo bot meetings prompt Gemini to weigh party leadership vs. squad safety.
|
|||
|
|
- **Tactical Navigation**: Coordinates obstacle avoidance, frontier exploration, and hostile avoidance using the local minimap and radar summary.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Backend REST API Interactions
|
|||
|
|
|
|||
|
|
| Method | Endpoint | Usage in `botagent_gear` |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `POST` | `/api/players` | Register bot avatar or reconnect existing avatar |
|
|||
|
|
| `GET` | `/api/players/{id}` | Refresh player health, score, and party leader status |
|
|||
|
|
| `GET` | `/api/turn` | Turn polling loop to detect active player and round |
|
|||
|
|
| `GET` | `/api/players/{id}/radar` | Scans surrounding bots and nearest target |
|
|||
|
|
| `GET` | `/api/players/{id}/available-moves` | Evaluates passable directions & diagonal squeeze penalties |
|
|||
|
|
| `GET` | `/api/board` | Full board snapshot for ASCII minimap generation |
|
|||
|
|
| `POST` | `/api/players/{id}/move` | Execute cardinal / diagonal movement |
|
|||
|
|
| `POST` | `/api/parties` | Establish voluntary alliance party |
|
|||
|
|
| `POST` | `/api/battles/fight` | Initiate tactical 3-bout D20 confrontation |
|
|||
|
|
| `POST` | `/api/players/{id}/pass` | Yield turn (follower wait or skipped turn) |
|
|||
|
|
| `GET` | `/api/game/conclusion` | Check if single party remains (victory condition) |
|
|||
|
|
| `DELETE` | `/api/players/{id}` | Clean disconnection on `SIGINT` / Ctrl+C |
|