feat: add available advice options and list functionality
Browse files- app.py +31 -1
- src/unpredictable_lord/game_state.py +59 -0
app.py
CHANGED
|
@@ -12,8 +12,10 @@ import spaces
|
|
| 12 |
|
| 13 |
from unpredictable_lord.chat import chat_with_llm_stream
|
| 14 |
from unpredictable_lord.game_state import (
|
|
|
|
| 15 |
PERSONALITY_DESCRIPTIONS,
|
| 16 |
create_session,
|
|
|
|
| 17 |
get_session,
|
| 18 |
)
|
| 19 |
|
|
@@ -55,6 +57,7 @@ def init_game(personality: str = "cautious") -> dict:
|
|
| 55 |
"session_id": session_id,
|
| 56 |
"message": f"New game started! You are now the advisor to a {personality} lord.",
|
| 57 |
"personality_description": PERSONALITY_DESCRIPTIONS[personality],
|
|
|
|
| 58 |
"game_state": state.to_dict(),
|
| 59 |
}
|
| 60 |
|
|
@@ -87,6 +90,24 @@ def get_game_state(session_id: str) -> dict:
|
|
| 87 |
}
|
| 88 |
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
# Gradio UI
|
| 91 |
with gr.Blocks(title="Unpredictable Lord") as demo:
|
| 92 |
gr.Markdown("# Unpredictable Lord\nLord Advisor AI Simulation")
|
|
@@ -170,8 +191,9 @@ Add the following to your MCP settings configuration:
|
|
| 170 |
|
| 171 |
| Tool | Description |
|
| 172 |
|------|-------------|
|
| 173 |
-
| `init_game` | Initialize a new game session. Returns a session_id
|
| 174 |
| `get_game_state` | Get the current game state for a session. |
|
|
|
|
| 175 |
|
| 176 |
### Usage Flow
|
| 177 |
|
|
@@ -208,6 +230,14 @@ Add the following to your MCP settings configuration:
|
|
| 208 |
fn=get_game_state, inputs=session_id_input, outputs=state_output
|
| 209 |
)
|
| 210 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
|
| 212 |
if __name__ == "__main__":
|
| 213 |
demo.launch(mcp_server=True)
|
|
|
|
| 12 |
|
| 13 |
from unpredictable_lord.chat import chat_with_llm_stream
|
| 14 |
from unpredictable_lord.game_state import (
|
| 15 |
+
ADVICE_DESCRIPTIONS,
|
| 16 |
PERSONALITY_DESCRIPTIONS,
|
| 17 |
create_session,
|
| 18 |
+
get_available_advice,
|
| 19 |
get_session,
|
| 20 |
)
|
| 21 |
|
|
|
|
| 57 |
"session_id": session_id,
|
| 58 |
"message": f"New game started! You are now the advisor to a {personality} lord.",
|
| 59 |
"personality_description": PERSONALITY_DESCRIPTIONS[personality],
|
| 60 |
+
"available_advice": ADVICE_DESCRIPTIONS,
|
| 61 |
"game_state": state.to_dict(),
|
| 62 |
}
|
| 63 |
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
|
| 93 |
+
def list_available_advice() -> dict:
|
| 94 |
+
"""
|
| 95 |
+
Get all available advice options that can be given to the lord.
|
| 96 |
+
|
| 97 |
+
This MCP tool returns a list of all possible advice types that can be
|
| 98 |
+
used with execute_turn(). The Lord AI should interpret the user's
|
| 99 |
+
free-form suggestion and map it to one of these options.
|
| 100 |
+
|
| 101 |
+
Returns:
|
| 102 |
+
dict: Dictionary containing all available advice options with
|
| 103 |
+
their names, descriptions, and expected effects.
|
| 104 |
+
"""
|
| 105 |
+
return {
|
| 106 |
+
"advice_options": get_available_advice(),
|
| 107 |
+
"usage": "Interpret the user's advice and select the most appropriate option from the list above.",
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
|
| 111 |
# Gradio UI
|
| 112 |
with gr.Blocks(title="Unpredictable Lord") as demo:
|
| 113 |
gr.Markdown("# Unpredictable Lord\nLord Advisor AI Simulation")
|
|
|
|
| 191 |
|
| 192 |
| Tool | Description |
|
| 193 |
|------|-------------|
|
| 194 |
+
| `init_game` | Initialize a new game session. Returns a session_id and available advice options. |
|
| 195 |
| `get_game_state` | Get the current game state for a session. |
|
| 196 |
+
| `list_available_advice` | Get all available advice options for execute_turn. |
|
| 197 |
|
| 198 |
### Usage Flow
|
| 199 |
|
|
|
|
| 230 |
fn=get_game_state, inputs=session_id_input, outputs=state_output
|
| 231 |
)
|
| 232 |
|
| 233 |
+
gr.Markdown("### Test: List Available Advice")
|
| 234 |
+
list_advice_btn = gr.Button("List Advice Options")
|
| 235 |
+
advice_output = gr.JSON(label="Available Advice Options")
|
| 236 |
+
|
| 237 |
+
list_advice_btn.click(
|
| 238 |
+
fn=list_available_advice, inputs=[], outputs=advice_output
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
|
| 242 |
if __name__ == "__main__":
|
| 243 |
demo.launch(mcp_server=True)
|
src/unpredictable_lord/game_state.py
CHANGED
|
@@ -16,6 +16,65 @@ PERSONALITY_DESCRIPTIONS = {
|
|
| 16 |
"populist": "A popularity-focused lord who prioritizes public approval over long-term planning.",
|
| 17 |
}
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
@dataclass
|
| 21 |
class GameState:
|
|
|
|
| 16 |
"populist": "A popularity-focused lord who prioritizes public approval over long-term planning.",
|
| 17 |
}
|
| 18 |
|
| 19 |
+
# Available advice options that the Lord AI can choose from
|
| 20 |
+
AdviceType = Literal[
|
| 21 |
+
"increase_tax",
|
| 22 |
+
"decrease_tax",
|
| 23 |
+
"expand_territory",
|
| 24 |
+
"improve_diplomacy",
|
| 25 |
+
"public_festival",
|
| 26 |
+
"build_infrastructure",
|
| 27 |
+
"do_nothing",
|
| 28 |
+
]
|
| 29 |
+
|
| 30 |
+
ADVICE_DESCRIPTIONS: dict[str, dict[str, str]] = {
|
| 31 |
+
"increase_tax": {
|
| 32 |
+
"name": "Increase Tax",
|
| 33 |
+
"description": "Raise taxes to increase treasury, but decrease public satisfaction.",
|
| 34 |
+
"effects": "Treasury β, Satisfaction β",
|
| 35 |
+
},
|
| 36 |
+
"decrease_tax": {
|
| 37 |
+
"name": "Decrease Tax",
|
| 38 |
+
"description": "Lower taxes to improve public satisfaction, but decrease treasury.",
|
| 39 |
+
"effects": "Treasury β, Satisfaction β",
|
| 40 |
+
},
|
| 41 |
+
"expand_territory": {
|
| 42 |
+
"name": "Expand Territory",
|
| 43 |
+
"description": "Launch a military campaign to expand territory. Risky but rewarding.",
|
| 44 |
+
"effects": "Territory β, Treasury β, Royal Trust Β±, Risk involved",
|
| 45 |
+
},
|
| 46 |
+
"improve_diplomacy": {
|
| 47 |
+
"name": "Improve Diplomacy",
|
| 48 |
+
"description": "Strengthen diplomatic relations with the kingdom.",
|
| 49 |
+
"effects": "Royal Trust β, Treasury β",
|
| 50 |
+
},
|
| 51 |
+
"public_festival": {
|
| 52 |
+
"name": "Hold Public Festival",
|
| 53 |
+
"description": "Organize a festival to boost public morale.",
|
| 54 |
+
"effects": "Satisfaction β, Treasury β",
|
| 55 |
+
},
|
| 56 |
+
"build_infrastructure": {
|
| 57 |
+
"name": "Build Infrastructure",
|
| 58 |
+
"description": "Invest in infrastructure to support population growth.",
|
| 59 |
+
"effects": "Population β, Treasury β, Long-term Treasury β",
|
| 60 |
+
},
|
| 61 |
+
"do_nothing": {
|
| 62 |
+
"name": "Do Nothing",
|
| 63 |
+
"description": "Maintain the current state without any action.",
|
| 64 |
+
"effects": "No change (turn passes)",
|
| 65 |
+
},
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def get_available_advice() -> dict[str, dict[str, str]]:
|
| 70 |
+
"""
|
| 71 |
+
Get all available advice options with their descriptions.
|
| 72 |
+
|
| 73 |
+
Returns:
|
| 74 |
+
dict: Dictionary of advice types and their descriptions.
|
| 75 |
+
"""
|
| 76 |
+
return ADVICE_DESCRIPTIONS
|
| 77 |
+
|
| 78 |
|
| 79 |
@dataclass
|
| 80 |
class GameState:
|