From f2185344b105e765c43754212f05164c74371c0d Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Sun, 5 May 2024 14:11:41 -0500 Subject: [PATCH] use LLM agent as fallback if player does not respond, fix various client bugs --- adventure/player.py | 8 +++++++- adventure/server.py | 9 +++------ client/src/app.tsx | 4 ++-- client/src/player.tsx | 20 +++++++++++--------- client/src/world.tsx | 4 ++-- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/adventure/player.py b/adventure/player.py index c5184e5..3f6c9a6 100644 --- a/adventure/player.py +++ b/adventure/player.py @@ -5,6 +5,7 @@ from readline import add_history from typing import Any, Callable, Dict, List, Sequence from langchain_core.messages import AIMessage, BaseMessage, HumanMessage +from packit.agent import Agent from packit.utils import could_be_json logger = getLogger(__name__) @@ -111,13 +112,15 @@ class LocalPlayer(BasePlayer): class RemotePlayer(BasePlayer): + fallback_agent: Agent | None input_queue: Queue[str] send_prompt: Callable[[str, str], bool] def __init__( - self, name: str, backstory: str, send_prompt: Callable[[str, str], bool] + self, name: str, backstory: str, send_prompt: Callable[[str, str], bool], fallback_agent = None ) -> None: super().__init__(name, backstory) + self.fallback_agent = fallback_agent self.input_queue = Queue() self.send_prompt = send_prompt @@ -138,4 +141,7 @@ class RemotePlayer(BasePlayer): except Exception: logger.exception("error getting reply from remote player") + if self.fallback_agent: + return self.fallback_agent(prompt, **kwargs) + return "" diff --git a/adventure/server.py b/adventure/server.py index f49af21..dbc15f7 100644 --- a/adventure/server.py +++ b/adventure/server.py @@ -7,7 +7,6 @@ from typing import Dict from uuid import uuid4 import websockets -from packit.agent import Agent from adventure.context import get_actor_agent_for_name, set_actor_agent_for_name from adventure.models import Actor, Room, World @@ -18,7 +17,6 @@ logger = getLogger(__name__) connected = set() characters: Dict[str, RemotePlayer] = {} -previous_agents: Dict[str, Agent] = {} recent_events = deque(maxlen=100) recent_world = None @@ -63,7 +61,7 @@ async def handler(websocket): try: # if this socket is attached to a character and that character's turn is active, wait for input message = await websocket.recv() - logger.info(f"Received message: {message}") + logger.info(f"Received message for {id}: {message}") try: data = loads(message) @@ -86,13 +84,12 @@ async def handler(websocket): continue # player_name = data["player"] - player = RemotePlayer(actor.name, actor.backstory, sync_turn) + player = RemotePlayer(actor.name, actor.backstory, sync_turn, fallback_agent=llm_agent) characters[id] = player logger.info(f"Client {websocket} is now character {character_name}") # swap out the LLM agent set_actor_agent_for_name(actor.name, actor, player) - previous_agents[actor.name] = llm_agent # notify all clients that this character is now active send_and_append( @@ -117,7 +114,7 @@ async def handler(websocket): actor, _ = get_actor_agent_for_name(player.name) if actor: - set_actor_agent_for_name(player.name, actor, previous_agents[player.name]) + set_actor_agent_for_name(player.name, actor, player.fallback_agent) logger.info("Client disconnected") diff --git a/client/src/app.tsx b/client/src/app.tsx index 883268a..2ff9f9f 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -82,8 +82,7 @@ export function App(props: AppProps) { const { lastMessage, readyState, sendMessage } = useWebSocket(props.socketUrl); function setPlayer(actor: Maybe) { - setCharacter(actor); - + // do not setCharacter until the server confirms the player change if (doesExist(actor)) { sendMessage(JSON.stringify({ type: 'player', become: actor.name })); } @@ -92,6 +91,7 @@ export function App(props: AppProps) { function sendInput(input: string) { if (doesExist(character)) { sendMessage(JSON.stringify({ type: 'input', input })); + setActiveTurn(false); } } diff --git a/client/src/player.tsx b/client/src/player.tsx index df3c80a..e8f4379 100644 --- a/client/src/player.tsx +++ b/client/src/player.tsx @@ -25,15 +25,17 @@ export function PlayerPanel(props: PlayerPanelProps) { return - {activeTurn && It's your turn!} - Playing as: {actor.name} - {actor.backstory} - - setInput(event.target.value)} /> - + + {activeTurn && It's your turn!} + Playing as: {actor.name} + {actor.backstory} + + setInput(event.target.value)} /> + + ; diff --git a/client/src/world.tsx b/client/src/world.tsx index 8032100..ceada81 100644 --- a/client/src/world.tsx +++ b/client/src/world.tsx @@ -59,7 +59,7 @@ export function ItemItem(props: { item: Item } & BaseEntityItemProps) { export function ActorItem(props: { actor: Actor } & BaseEntityItemProps) { const { actor, activeCharacter, setDetails, setPlayer } = props; - const active = doesExist(activeCharacter) && actor === activeCharacter; + const active = doesExist(activeCharacter) && actor.name === activeCharacter.name; const label = formatLabel(actor.name, active); let playButton; @@ -79,7 +79,7 @@ export function ActorItem(props: { actor: Actor } & BaseEntityItemProps) { export function RoomItem(props: { room: Room } & BaseEntityItemProps) { const { room, activeCharacter, setDetails, setPlayer } = props; - const active = doesExist(activeCharacter) && room.actors.some((it) => it === activeCharacter); + const active = doesExist(activeCharacter) && room.actors.some((it) => it.name === activeCharacter.name); const label = formatLabel(room.name, active); return