File size: 2,547 Bytes
2f9cbc8 f566386 21c7651 f566386 2f9cbc8 1373c22 f566386 dfdde45 758a706 dfdde45 f566386 758a706 47b6f03 758a706 21c7651 758a706 f566386 758a706 dfdde45 758a706 f566386 dfdde45 2f9cbc8 dfdde45 2f9cbc8 dfdde45 f566386 dfdde45 2f9cbc8 dfdde45 2f9cbc8 dfdde45 2f9cbc8 dfdde45 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
from typing import Literal, List
from pydantic import BaseModel, computed_field, Field
MessageType = Literal["prompt", "info", "agent", "retry", "error", "format", "verbose", "debug", "system"]
message_number = 0
def next_message_number():
global message_number
current_message_number = message_number
message_number += 1
return current_message_number
class Message(BaseModel):
"""A generic message, these are used to communicate between the game and the players."""
type: MessageType
"""The type of the message."""
content: str
"""The content of the message."""
@property
def conversation_role(self) -> str:
"""The message type in the format used by the LLM."""
# Most LLMs expect the "prompt" to come from a "user" and the "response" to come from an "assistant"
# Since the agents are the ones responding to messages, take on the llm_type of "assistant"
# This can be counterintuitive since they can be controlled by either human or ai
# Further, The programmatic messages from the game are always "user"
if self.type != "system":
return "system"
elif self.type != "agent":
return "user"
else:
return "assistant"
@property
def requires_response(self) -> bool:
"""Returns True if the message requires a response."""
return self.type in ["prompt", "retry", "format"]
def to_openai(self) -> dict[str, str]:
"""Returns the message in an OpenAI API compatible format."""
return {"role": self.conversation_role, "content": self.content}
class AgentMessage(Message):
"""A message that has been sent to 1 or more agents."""
agent_ids: List[str]
"""The id/ids of the agent that the message was sent by/to."""
game_id: str
"""The id of the game the message was sent during."""
message_number: int = Field(default_factory=next_message_number)
"""The number of the message, indicating the order in which it was sent."""
@computed_field
def message_id(self) -> str:
"""Returns the message id in the format used by the LLM."""
return f"{self.game_id}-{self.message_number}"
@classmethod
def from_message(cls, message: Message, agent_ids: List[str], game_id: str) -> "AgentMessage":
"""Creates an AgentMessage from a Message."""
return cls(
type=message.type,
content=message.content,
agent_ids=agent_ids,
game_id=game_id
) |