feat(coach): Phase 5 - add PodPresence, TempoAssessment, MetaMatchup models + isQuickDigest flag (#108)
This commit is contained in:
1 parent
6c03e56794
commit
864cefb8d1
1 file changed
+65
-26
+65
-26
@@ -4,11 +4,9 @@ Commander AI Lab — Coach Data Models
|
||||
Pydantic v2 models for deck reports, coach requests/responses,
|
||||
and coaching session persistence.
|
||||
"""
|
||||
|
||||
from typing import List, Optional, Dict
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# Deck Report Models (mirrors Java DeckReport)
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
@@ -145,48 +143,81 @@ class MulliganAnalysis(BaseModel):
|
||||
|
||||
class RemovalCoverage(BaseModel):
|
||||
"""Categorized removal package by permanent type."""
|
||||
creatures: str = "" # Assessment of creature removal
|
||||
artifacts: str = "" # Assessment of artifact removal
|
||||
enchantments: str = "" # Assessment of enchantment removal
|
||||
planeswalkers: str = "" # Assessment of planeswalker removal
|
||||
lands: str = "" # Assessment of land destruction
|
||||
massRemoval: str = "" # Assessment of board wipes / sweepers
|
||||
gaps: List[str] = Field(default_factory=list) # Permanent types with zero coverage
|
||||
creatures: str = ""
|
||||
artifacts: str = ""
|
||||
enchantments: str = ""
|
||||
planeswalkers: str = ""
|
||||
lands: str = ""
|
||||
massRemoval: str = ""
|
||||
gaps: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class RampQuality(BaseModel):
|
||||
"""Ramp package breakdown by subtype and fragility."""
|
||||
manaRocks: str = "" # 2-mana rocks, signets, etc.
|
||||
landFetch: str = "" # Cultivate, Kodama's Reach, etc.
|
||||
manaDorks: str = "" # Llanowar Elves, Birds of Paradise, etc.
|
||||
costReducers: str = "" # Medallions, Helm of Awakening, etc.
|
||||
fragility: str = "" # Overall fragility assessment (creature-heavy = fragile)
|
||||
canReachFourByTurnThree: str = "" # Whether the deck reliably hits 4 mana by turn 3
|
||||
manaRocks: str = ""
|
||||
landFetch: str = ""
|
||||
manaDorks: str = ""
|
||||
costReducers: str = ""
|
||||
fragility: str = ""
|
||||
canReachFourByTurnThree: str = ""
|
||||
|
||||
|
||||
class DrawEngineProfile(BaseModel):
|
||||
"""Card draw sustainability analysis."""
|
||||
burstDraw: List[str] = Field(default_factory=list) # One-time draw spells
|
||||
repeatableEngines: List[str] = Field(default_factory=list) # Sustained draw engines
|
||||
assessment: str = "" # Overall draw engine quality evaluation
|
||||
sustainability: str = "" # Whether draw is sustainable or burst-only
|
||||
burstDraw: List[str] = Field(default_factory=list)
|
||||
repeatableEngines: List[str] = Field(default_factory=list)
|
||||
assessment: str = ""
|
||||
sustainability: str = ""
|
||||
|
||||
|
||||
class WinCondition(BaseModel):
|
||||
"""A named win condition with independence rating."""
|
||||
name: str # e.g., "Craterhoof Behemoth + wide board"
|
||||
cards: List[str] = Field(default_factory=list) # Key cards involved
|
||||
independence: str = "" # How well it works without other combos (high/medium/low)
|
||||
description: str = "" # How this win con functions
|
||||
name: str
|
||||
cards: List[str] = Field(default_factory=list)
|
||||
independence: str = ""
|
||||
description: str = ""
|
||||
|
||||
|
||||
class AntiSynergyFlag(BaseModel):
|
||||
"""An internal conflict between cards in the deck."""
|
||||
cards: List[str] = Field(default_factory=list) # Cards that conflict
|
||||
conflict: str = "" # Description of the conflict
|
||||
severity: str = "" # high, medium, low
|
||||
cards: List[str] = Field(default_factory=list)
|
||||
conflict: str = ""
|
||||
severity: str = ""
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# Phase 5: Pod Politics & Meta Awareness Models
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
|
||||
class PodPresence(BaseModel):
|
||||
"""Commander pod politics and threat assessment."""
|
||||
threatLevel: str = "" # early/medium/late/low
|
||||
politicalTools: List[str] = Field(default_factory=list)
|
||||
adversarialRating: str = "" # low/medium/high
|
||||
recommendation: str = ""
|
||||
|
||||
|
||||
class TempoAssessment(BaseModel):
|
||||
"""When the deck 'comes online' and whether that's fast enough."""
|
||||
peakTurn: int = 0
|
||||
profile: str = "" # early/mid/late
|
||||
survivalWindow: str = "" # Assessment of whether it survives to peak
|
||||
assessment: str = ""
|
||||
|
||||
|
||||
class MetaMatchup(BaseModel):
|
||||
"""Strategic reasoning about deck vs a meta archetype."""
|
||||
archetype: str # fast-combo, stax, control, aggro, etc.
|
||||
assessment: str = ""
|
||||
keyThreats: List[str] = Field(default_factory=list)
|
||||
keyAnswers: List[str] = Field(default_factory=list)
|
||||
overallRating: str = "" # favored/even/unfavored
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# Coach Session (persisted result)
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
|
||||
class CoachSession(BaseModel):
|
||||
"""
|
||||
Complete coaching session result.
|
||||
@@ -205,10 +236,13 @@ class CoachSession(BaseModel):
|
||||
promptTokens: int = 0
|
||||
completionTokens: int = 0
|
||||
goals: Optional[CoachGoals] = None
|
||||
isQuickDigest: bool = False # True for quick digest, False for full analysis
|
||||
|
||||
# Phase 2: Structured analysis fields
|
||||
upgradePriority: List[UpgradePriorityItem] = Field(default_factory=list)
|
||||
commanderDependency: Optional[CommanderDependency] = None
|
||||
mulliganAnalysis: Optional[MulliganAnalysis] = None
|
||||
|
||||
# Phase 3: Qualitative analysis fields
|
||||
removalCoverage: Optional[RemovalCoverage] = None
|
||||
rampQuality: Optional[RampQuality] = None
|
||||
@@ -216,6 +250,11 @@ class CoachSession(BaseModel):
|
||||
winConditions: List[WinCondition] = Field(default_factory=list)
|
||||
antiSynergyFlags: List[AntiSynergyFlag] = Field(default_factory=list)
|
||||
|
||||
# Phase 5: Pod politics & meta
|
||||
podPresence: Optional[PodPresence] = None
|
||||
tempoAssessment: Optional[TempoAssessment] = None
|
||||
metaMatchups: List[MetaMatchup] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ApplyRequest(BaseModel):
|
||||
"""Request body for applying coach suggestions to a deck."""
|
||||
|
||||
Reference in new issue
Block a user