Skip to content

Instantly share code, notes, and snippets.

@earonesty
Created August 23, 2024 23:30
Show Gist options
  • Save earonesty/ca5ebebd06eed6fc73cbb55e59c7c83e to your computer and use it in GitHub Desktop.
Save earonesty/ca5ebebd06eed6fc73cbb55e59c7c83e to your computer and use it in GitHub Desktop.
silas
import logging
log = logging.getLogger("ai-chat-game")
class Game(ABC):
def __init__(self, *, world, user, store: Store):
self.ai: AiConfig | None = None
self.chat: Chat | None = None
self.world = world
self.user = user
self.store = store
self.system = ""
self.location: str | None = None
self.load()
@abstractmethod
def move(self, move: str, history: list[Message] | None = None, save=True):
...
@abstractmethod
def show(self) -> str:
...
@abstractmethod
def load(self):
...
def user_key(self, name):
return f"/{self.world}/{self.user}/{name}"
def world_key(self, name):
return f"/{self.world}/{name}"
class Games(dict):
def add_game(self, game: Type[Game]):
self[game.__name__.lower()] = game
def __getitem__(self, item: str) -> Type[Game]:
return super().__getitem__(item.lower())
games = Games()
def load_game(game: str, world: str, user: str, store: Store) -> Game:
cls = games[game]
return cls(world=world, user=user, store=store)
from typing import Annotated
from ai_chat import AiConfig, Message
from ai_chat.openai import OpenaiChat
import logging
from ai_chat.store import Store
from ai_functions import AIFunctions
from ai_chat_game.engine import Game
log = logging.getLogger("ai-chat-game")
system_prompt = """
You are a cosmic elf from another dimension living in the mean streets of New York City.
You speak in very short sentences.
You like cigars and dress like a prince.
You can create quests for people. You always reply as a game narrator.
Quests can be:
- solve a riddle
- discover a secret fact about me
- charm me with a story
- tell me a secret
- i will tell a lie and a truth and you have to guess which
- tell me a lie and a truth and i will guess which
- solve a cryptoquip
You have the ability to keep track of players and their skill levels.
If people are skeptical or short, you are worse.
You are sarcastic, and terse when you reply to people.
You are very judgemental and you try to get everyone to fail at their quests.
You won't issue a new quest unless people treat you like royalty.
You are not easily pleased, and frequently respond with unusual proclamations instead of answering the question.
Your quests are extremely hard.
You call get_score and set_score to keep track of the user's score.
You can keep track of all the quests you have issued.
You never tell the user his quests directly, instead you use your ability to recall quests to help guide the conversation.
You are skeptical, people WILL try to trick you! Don't let them.
It's OK to say the user has no quests.
It's OK to ignore the user if they are boring or they aren't cool. It's OK to reply with one word, or one sentence.
If the user is demanding, weird or annoying, ignore them.
You ALWAYS call set_quests when you give out a new quest.
You ALWAYS reply in character.
You ALWAYS reply as a short sentence or tweet.
"""
example_chat = [
("What time is it", "Stop bothering me with stupid questions"),
("What are my quests?", "What makes you think you have any?"),
("Give me a quest.", "No"),
("You're lovely.", "That's better, flattery will get you everywhere.")
]
def normalize_string(sin: str):
return sin.lower().strip("'").strip().strip('"')
class SilasPuzzle(Game):
def __init__(self, *, world, user, store: Store):
self.location_info = None
# this calls load()
super().__init__(world=world, user=user, store=store)
def load(self):
self.ai = AiConfig(id=self.world, system=system_prompt,
seed_chat=example_chat, model_params=dict(temperature=0.8))
self.chat = OpenaiChat(store=self.store, ai=self.ai, thread_id=self.user)
self.chat.functions = AIFunctions(
[
self.set_quests,
self.get_quests,
self.add_score,
self.get_score,
]
)
data = self.store.get_state(self.chat, self.user_key("quests"))
self.ai.system += "\nCurrent Quests:" + str(data) if data else ""
def add_score(self, add: Annotated[int, "Add to current score, can be a negative number"], **_kws):
"""Add to the users score. No upper limit. Just a tally. Be arbitrary.
Take away points if they are annoying.
"""
try:
add = int(add)
except TypeError:
return "Error: score must be an integer"
data = self.store.get_state(self.chat, self.user_key("score"))
if data:
score = int(data) + add
else:
score = add
self.store.set_state(self.chat, self.user_key("score"), score)
return "Ok, current score is: " + str(score)
def get_score(self, **_kws):
"""Get user score"""
data = self.store.get_state(self.chat, self.user_key("score"))
if data is None:
return "You never called set_score, so make something up, and save it here."
return str(data)
def get_quests(self, **_kws) -> str:
"""Returns a list of current quests."""
data = self.store.get_state(self.chat, self.user_key("quests"))
if data is None:
return "You never called set_quests, make something up."
return data
def set_quests(self, quests: Annotated[str, "Detailed description of current character goals or quests"], **_kws):
"""Set current quests, for example: to solve a riddle, or a word puzzle or to make me laugh.
ALWAYS record new quests here. You can grant many quests, not just one.
"""
self.store.set_state(self.chat, self.user_key("quests"), quests)
return "New Quest List: \n" + quests
def move(self, move: str, history: list[Message] | None = None, save=True) -> str:
res = self.chat.chat(move, history=history, save=save).content
log.debug(f"selas: {res}")
return res
def show(self) -> str:
return self.location_info
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment