use LLM agent as fallback if player does not respond, fix various client bugs
This commit is contained in:
parent
580076335f
commit
f2185344b1
|
@ -5,6 +5,7 @@ from readline import add_history
|
||||||
from typing import Any, Callable, Dict, List, Sequence
|
from typing import Any, Callable, Dict, List, Sequence
|
||||||
|
|
||||||
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
|
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
|
||||||
|
from packit.agent import Agent
|
||||||
from packit.utils import could_be_json
|
from packit.utils import could_be_json
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
@ -111,13 +112,15 @@ class LocalPlayer(BasePlayer):
|
||||||
|
|
||||||
|
|
||||||
class RemotePlayer(BasePlayer):
|
class RemotePlayer(BasePlayer):
|
||||||
|
fallback_agent: Agent | None
|
||||||
input_queue: Queue[str]
|
input_queue: Queue[str]
|
||||||
send_prompt: Callable[[str, str], bool]
|
send_prompt: Callable[[str, str], bool]
|
||||||
|
|
||||||
def __init__(
|
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:
|
) -> None:
|
||||||
super().__init__(name, backstory)
|
super().__init__(name, backstory)
|
||||||
|
self.fallback_agent = fallback_agent
|
||||||
self.input_queue = Queue()
|
self.input_queue = Queue()
|
||||||
self.send_prompt = send_prompt
|
self.send_prompt = send_prompt
|
||||||
|
|
||||||
|
@ -138,4 +141,7 @@ class RemotePlayer(BasePlayer):
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("error getting reply from remote player")
|
logger.exception("error getting reply from remote player")
|
||||||
|
|
||||||
|
if self.fallback_agent:
|
||||||
|
return self.fallback_agent(prompt, **kwargs)
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -7,7 +7,6 @@ from typing import Dict
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import websockets
|
import websockets
|
||||||
from packit.agent import Agent
|
|
||||||
|
|
||||||
from adventure.context import get_actor_agent_for_name, set_actor_agent_for_name
|
from adventure.context import get_actor_agent_for_name, set_actor_agent_for_name
|
||||||
from adventure.models import Actor, Room, World
|
from adventure.models import Actor, Room, World
|
||||||
|
@ -18,7 +17,6 @@ logger = getLogger(__name__)
|
||||||
|
|
||||||
connected = set()
|
connected = set()
|
||||||
characters: Dict[str, RemotePlayer] = {}
|
characters: Dict[str, RemotePlayer] = {}
|
||||||
previous_agents: Dict[str, Agent] = {}
|
|
||||||
recent_events = deque(maxlen=100)
|
recent_events = deque(maxlen=100)
|
||||||
recent_world = None
|
recent_world = None
|
||||||
|
|
||||||
|
@ -63,7 +61,7 @@ async def handler(websocket):
|
||||||
try:
|
try:
|
||||||
# if this socket is attached to a character and that character's turn is active, wait for input
|
# if this socket is attached to a character and that character's turn is active, wait for input
|
||||||
message = await websocket.recv()
|
message = await websocket.recv()
|
||||||
logger.info(f"Received message: {message}")
|
logger.info(f"Received message for {id}: {message}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = loads(message)
|
data = loads(message)
|
||||||
|
@ -86,13 +84,12 @@ async def handler(websocket):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# player_name = data["player"]
|
# 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
|
characters[id] = player
|
||||||
logger.info(f"Client {websocket} is now character {character_name}")
|
logger.info(f"Client {websocket} is now character {character_name}")
|
||||||
|
|
||||||
# swap out the LLM agent
|
# swap out the LLM agent
|
||||||
set_actor_agent_for_name(actor.name, actor, player)
|
set_actor_agent_for_name(actor.name, actor, player)
|
||||||
previous_agents[actor.name] = llm_agent
|
|
||||||
|
|
||||||
# notify all clients that this character is now active
|
# notify all clients that this character is now active
|
||||||
send_and_append(
|
send_and_append(
|
||||||
|
@ -117,7 +114,7 @@ async def handler(websocket):
|
||||||
|
|
||||||
actor, _ = get_actor_agent_for_name(player.name)
|
actor, _ = get_actor_agent_for_name(player.name)
|
||||||
if actor:
|
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")
|
logger.info("Client disconnected")
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,7 @@ export function App(props: AppProps) {
|
||||||
const { lastMessage, readyState, sendMessage } = useWebSocket(props.socketUrl);
|
const { lastMessage, readyState, sendMessage } = useWebSocket(props.socketUrl);
|
||||||
|
|
||||||
function setPlayer(actor: Maybe<Actor>) {
|
function setPlayer(actor: Maybe<Actor>) {
|
||||||
setCharacter(actor);
|
// do not setCharacter until the server confirms the player change
|
||||||
|
|
||||||
if (doesExist(actor)) {
|
if (doesExist(actor)) {
|
||||||
sendMessage(JSON.stringify({ type: 'player', become: actor.name }));
|
sendMessage(JSON.stringify({ type: 'player', become: actor.name }));
|
||||||
}
|
}
|
||||||
|
@ -92,6 +91,7 @@ export function App(props: AppProps) {
|
||||||
function sendInput(input: string) {
|
function sendInput(input: string) {
|
||||||
if (doesExist(character)) {
|
if (doesExist(character)) {
|
||||||
sendMessage(JSON.stringify({ type: 'input', input }));
|
sendMessage(JSON.stringify({ type: 'input', input }));
|
||||||
|
setActiveTurn(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ export function PlayerPanel(props: PlayerPanelProps) {
|
||||||
|
|
||||||
return <Card>
|
return <Card>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
<Stack direction="column" spacing={2}>
|
||||||
{activeTurn && <Alert severity="warning">It's your turn!</Alert>}
|
{activeTurn && <Alert severity="warning">It's your turn!</Alert>}
|
||||||
<Typography variant="h6">Playing as: {actor.name}</Typography>
|
<Typography variant="h6">Playing as: {actor.name}</Typography>
|
||||||
<Typography variant="body1">{actor.backstory}</Typography>
|
<Typography variant="body1">{actor.backstory}</Typography>
|
||||||
|
@ -35,6 +36,7 @@ export function PlayerPanel(props: PlayerPanelProps) {
|
||||||
sendInput(input);
|
sendInput(input);
|
||||||
}}>Send</Button>
|
}}>Send</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</Stack>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>;
|
</Card>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export function ItemItem(props: { item: Item } & BaseEntityItemProps) {
|
||||||
export function ActorItem(props: { actor: Actor } & BaseEntityItemProps) {
|
export function ActorItem(props: { actor: Actor } & BaseEntityItemProps) {
|
||||||
const { actor, activeCharacter, setDetails, setPlayer } = props;
|
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);
|
const label = formatLabel(actor.name, active);
|
||||||
|
|
||||||
let playButton;
|
let playButton;
|
||||||
|
@ -79,7 +79,7 @@ export function ActorItem(props: { actor: Actor } & BaseEntityItemProps) {
|
||||||
export function RoomItem(props: { room: Room } & BaseEntityItemProps) {
|
export function RoomItem(props: { room: Room } & BaseEntityItemProps) {
|
||||||
const { room, activeCharacter, setDetails, setPlayer } = props;
|
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);
|
const label = formatLabel(room.name, active);
|
||||||
|
|
||||||
return <TreeItem itemId={room.name} label={label}>
|
return <TreeItem itemId={room.name} label={label}>
|
||||||
|
|
Loading…
Reference in New Issue