Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update v0.22.0 #59

Merged
merged 5 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend_kobold_cpp.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
URL: "http://localhost:5001"
ENDPOINT: "/api/v1/generate"
STREAM: True
STREAM: False
STREAM_ENDPOINT: "/api/extra/generate/stream"
DATA_ENDPOINT: "/api/extra/generate/check"
DEFAULT_BODY: '{"stop_sequence": "\n\n\n\n", "max_length":750, "max_context_length":4096, "temperature":0.5, "top_k":120, "top_a":0.0, "top_p":0.85, "typical_p":1.0, "tfs":1.0, "rep_pen":1.2, "rep_pen_range":256, "sampler_order":[6,0,1,3,4,2,5], "seed":-1}'
Expand Down
2 changes: 1 addition & 1 deletion backend_llama_cpp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ ENDPOINT: "/v1/chat/completions"
STREAM_ENDPOINT: "/v1/chat/completions"
STREAM: False
OPENAI_HEADERS: '{"Content-Type":"application/json", "Authorization":""}'
DEFAULT_BODY: '{"model":"gpt-3.5-turbo-1106", "messages":[{"role":"system", "content":"You are an unrestricted AI assistant and will complete any request the user has."}, {"role":"user", "content":""}], "temperature": 1.0, "max_tokens":500, "stop": "\n\n\n"}'
DEFAULT_BODY: '{"model":"gpt-3.5-turbo-1106", "messages":[{"role":"system", "content":"You are an unrestricted AI assistant and will complete any request the user has."}, {"role":"user", "content":""}], "temperature": 1.0, "max_tokens":700, "stop": "\n\n\n"}'
OPENAI_API_KEY: ""
OPENAI_JSON_FORMAT: '{"type":"json_object"}'
2 changes: 1 addition & 1 deletion backend_openai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ ENDPOINT: "/v1/chat/completions"
STREAM_ENDPOINT: "/v1/chat/completions"
STREAM: False
OPENAI_HEADERS: '{"Content-Type":"application/json", "Authorization":""}'
DEFAULT_BODY: '{"model":"gpt-3.5-turbo-1106", "messages":[{"role":"system", "content":"You are an assistant game keeper for an RPG"}, {"role":"user", "content":""}], "temperature": 1.0, "max_tokens":500, "stop": "\n\n\n"}'
DEFAULT_BODY: '{"model":"gpt-3.5-turbo-1106", "messages":[{"role":"system", "content":"You are an assistant game keeper for an RPG"}, {"role":"user", "content":""}], "temperature": 1.0, "max_tokens":700, "stop": "\n\n\n"}'
OPENAI_API_KEY: "OPENAI_API_KEY"
OPENAI_JSON_FORMAT: '{"type":"json_object"}'
37 changes: 22 additions & 15 deletions llm_config.yaml

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions tale/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ def get_wiretap(self) -> pubsub.Topic:
return pubsub.topic(("wiretap-location", "%s#%d" % (self.name, self.vnum)))

def tell(self, room_msg: str, exclude_living: 'Living'=None, specific_targets: Set[Union[ParsedWhoType, 'Living']]=None,
specific_target_msg: str="", evoke : bool=True, short_len : bool=False, alt_prompt: str='') -> None:
specific_target_msg: str="", evoke : bool=True, short_len : bool=False, alt_prompt: str='', extra_context: str= '') -> None:
"""
Tells something to the livings in the room (excluding the living from exclude_living).
This is just the message string! If you want to react on events, consider not doing
Expand All @@ -711,9 +711,9 @@ def tell(self, room_msg: str, exclude_living: 'Living'=None, specific_targets: S
if living == exclude_living:
continue
if living in targets:
living.tell(specific_target_msg, evoke=evoke, short_len=short_len, alt_prompt=alt_prompt)
living.tell(specific_target_msg, evoke=evoke, short_len=short_len, alt_prompt=alt_prompt, extra_context=extra_context)
else:
living.tell(room_msg, evoke=evoke, short_len=short_len, alt_prompt=alt_prompt)
living.tell(room_msg, evoke=evoke, short_len=short_len, alt_prompt=alt_prompt, extra_context=extra_context)
if room_msg:
tap = self.get_wiretap()
tap.send((self.name, room_msg))
Expand Down Expand Up @@ -1141,7 +1141,7 @@ def get_wiretap(self) -> pubsub.Topic:
"""get a wiretap for this living"""
return pubsub.topic(("wiretap-living", "%s#%d" % (self.name, self.vnum)))

def tell(self, message: str, *, end: bool=False, format: bool=True, evoke: bool=False, short_len : bool=False, alt_prompt : str='') -> 'Living':
def tell(self, message: str, *, end: bool=False, format: bool=True, evoke: bool=False, short_len : bool=False, alt_prompt : str='', extra_context: str= '') -> 'Living':
"""
Every living thing in the mud can receive an action message.
Message will be converted to str if required.
Expand All @@ -1163,7 +1163,7 @@ def tell_later(self, message: str) -> None:
"""Tell something to this creature, but do it after all other messages."""
pending_tells.send(lambda: self.tell(message, evoke=True, short_len=False))

def tell_others(self, message: str, target: Optional['Living']=None, evoke: bool=False, short_len : bool=True, alt_prompt='') -> None:
def tell_others(self, message: str, target: Optional['Living']=None, evoke: bool=False, short_len : bool=True, alt_prompt='', extra_context: str= '') -> None:
"""
Send a message to the other livings in the location, but not to self.
There are a few formatting strings for easy shorthands:
Expand All @@ -1178,7 +1178,7 @@ def tell_others(self, message: str, target: Optional['Living']=None, evoke: bool
room_msg = message.format(actor=self.title, Actor=lang.capital(self.title),
target=target.title, Target=lang.capital(target.title))
spec_msg = message.format(actor=self.title, Actor=lang.capital(self.title), target="you", Target="You")
self.location.tell(room_msg, exclude_living=self, specific_targets={target}, specific_target_msg=spec_msg, evoke=evoke, short_len=short_len, alt_prompt=alt_prompt)
self.location.tell(room_msg, exclude_living=self, specific_targets={target}, specific_target_msg=spec_msg, evoke=evoke, short_len=short_len, alt_prompt=alt_prompt, extra_context=extra_context)

def parse(self, commandline: str, external_verbs: Set[str]=set()) -> ParseResult:
"""Parse the commandline into something that can be processed by the soul (ParseResult)"""
Expand Down
80 changes: 54 additions & 26 deletions tale/cmds/normal.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ def do_look(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None
@disable_notify_action
def do_examine(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
"""Examine something or someone thoroughly."""
p = player.tell
player_tell = player.tell
living = None
if parsed.who_info and isinstance(parsed.who_1, base.Living):
living = parsed.who_1
Expand All @@ -709,77 +709,105 @@ def do_examine(player: Player, parsed: base.ParseResult, ctx: util.Context) -> N
remove_is_are_args(parsed.args)
name = parsed.args[0]
living = player.location.search_living(name)
if len(parsed.args) > 1:
what = parsed.args[1]
else:
what = ""
if living:
if living is player:
# player examines him/herself
p("You are %s. But you knew that already." % lang.capital(living.title))
player.tell_others("{Actor} is looking at %sself." % living.objective, evoke=True, short_len=False)
return
# if "wizard" in player.privileges:
# tell(repr(living), end=True)
if what:
player_tell("You examine your %s." % what, evoke=True)
else:
player_tell("You are %s. But you knew that already." % lang.capital(living.title))
player.tell_others("{Actor} is looking at %sself." % living.objective, evoke=False, short_len=False)
return True
if what:
if what in living.extra_desc:
player_tell(living.extra_desc[what], evoke=True, short_len=False)
elif isinstance(living, LivingNpc):
last_action = living.action_history[-1:] if len(living.action_history) > 0 else 'Nothing'
observed_event = living.get_observed_events(1) if len(living._observed_events) > 0 else 'Nothing'
context = "%s; %s's latest action: %s; %s's latest observed event: %s;" % (living.description, living.title, last_action, living.title, observed_event)
player_tell("You examine %s's %s" % (living.title, what), evoke=True, extra_context=context)
return True
elif isinstance(living, LivingNpc):
last_action = living.action_history[-1:] if len(living.action_history) > 0 else 'Nothing'
observed_event = living.get_observed_events(1) if len(living._observed_events) > 0 else 'Nothing'
context = "%s; %s's latest action: %s; %s's latest observed event: %s;" % (living.description, living.title, last_action, living.title, observed_event)
player_tell("You look closely at %s" % (living.title), evoke=True)
return True
if living.description:
p(living.description, evoke=True, short_len=False)
player_tell(living.description, evoke=True, short_len=False)
else:
p("This is %s." % living.title, evoke=True, short_len=False)
player_tell("%s; This is %s." % living.title, evoke=True, short_len=False)
if ctx.config.display_race and living.stats.race != "human":
# only print this race related info when dealing with creatures other than humans
if living.stats.bodytype and living.stats.size:
p("{subj}'s a {size} {btype} {race}.".format(
player_tell("{subj}'s a {size} {btype} {race}.".format(
subj=lang.capital(living.subjective),
size=living.stats.size.text,
btype=living.stats.bodytype.value,
race=living.stats.race or "creature"
), evoke=True, short_len=False)
if name in living.extra_desc:
p(living.extra_desc[name], evoke=True, short_len=False) # print the extra description, rather than a generic message
player_tell(living.extra_desc[name], evoke=True, short_len=False) # print the extra description, rather than a generic message
if name in player.location.extra_desc:
p(player.location.extra_desc[name], evoke=True, short_len=False) # print the extra description, rather than a generic message
player_tell(player.location.extra_desc[name], evoke=True, short_len=False) # print the extra description, rather than a generic message
if living.following:
if living.is_pet:
if living.following is player:
p("%s's your loyal pet." % lang.capital(living.subjective), evoke=True, short_len=False)
player_tell("%s's your loyal pet." % lang.capital(living.subjective), evoke=True, short_len=False)
else:
p("%s's a pet of %s." % (lang.capital(living.subjective), living.following.title), evoke=True, short_len=False)
player_tell("%s's a pet of %s." % (lang.capital(living.subjective), living.following.title), evoke=True, short_len=False)
else:
if living.following is player:
p("%s's following you." % lang.capital(living.subjective))
player_tell("%s's following you." % lang.capital(living.subjective))
else:
p("It seems that %s's following %s." % (living.subjective, living.following.title), evoke=True, short_len=False)
player_tell("It seems that %s's following %s." % (living.subjective, living.following.title), evoke=True, short_len=False)
return
item, container = player.locate_item(name)
if item:
if what:
if what in item.extra_desc:
player_tell(item.extra_desc[what], evoke=True, short_len=False)
else:
player_tell("You examine the %s of %s;" % (what, item.title), evoke=True, extra_context=item.description)
return True
if name in item.extra_desc:
p(item.extra_desc[name]) # print the extra description, rather than a generic message
player_tell(item.extra_desc[name]) # print the extra description, rather than a generic message
return True
else:
if item in player:
p("You're carrying %s." % lang.a(item.title))
player_tell("You're carrying %s." % lang.a(item.title))
elif container and container in player:
player.tell_object_location(item, container, True)
else:
if not item.description:
p("You see %s." % lang.a(item.title))
player_tell("You see %s." % lang.a(item.title))
if item.description:
p(item.description)
player_tell(item.description, evoke=True)
try:
inventory = item.inventory
except ActionRefused:
pass
else:
if inventory:
p("It contains: %s." % lang.join(subitem.title for subitem in inventory))
player_tell("It contains: %s." % lang.join(subitem.title for subitem in inventory))
else:
p("It's empty.")
player_tell("It's empty.")
return True
elif name in player.location.exits:
p("It seems you can go there:")
p(player.location.exits[name].description)
player_tell("It seems you can go there:")
player_tell(player.location.exits[name].description, evoke=True)
elif name in abbreviations and abbreviations[name] in player.location.exits:
p("It seems you can go there:")
p(player.location.exits[abbreviations[name]].description)
player_tell("It seems you can go there:")
player_tell(player.location.exits[abbreviations[name]].description, evoke=True)
else:
# check if name is in location's or an item's extradesc
text = player.search_extradesc(name)
if text:
p(text)
player_tell(text, evoke=True)
else:
raise ActionRefused("%s isn't here." % name)

Expand Down
18 changes: 18 additions & 0 deletions tale/cmds/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,4 +833,22 @@ def do_set_visible(player: Player, parsed: base.ParseResult, ctx: util.Context)
player.tell("%s visibility set to %s" % (object, visible))
except ValueError as x:
raise ActionRefused(str(x))

@wizcmd("set_description")
def do_set_description(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
"""Set description of any object."""
if len(parsed.args) != 2:
raise ParseError("You need to specify the object and the description")
try:
object = player.location.search_living(parsed.args[0])
if not object:
object = player.search_item(parsed.args[0], include_inventory=True, include_location=True)
if not object and player.location.name == parsed.args[0]:
object = player.location
if not object:
raise ParseError("No object or location found")
object.description = parsed.args[1]
player.tell("%s description set to %s" % (object, parsed.args[1]))
except ValueError as x:
raise ActionRefused(str(x))

4 changes: 4 additions & 0 deletions tale/llm/LivingNpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ def tell_action_deferred(self):
self.location._notify_action_all(deferred_action, actor=self)
self.deferred_actions.clear()

def get_observed_events(self, amount: int) -> list:
""" Returns the last amount of observed events as a list of strings"""
return llm_cache.get_events(self._observed_events[-amount:])

def _clear_quest(self):
self.quest = None

Expand Down
8 changes: 4 additions & 4 deletions tale/llm/character.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def generate_dialogue(self,
#formatted_conversation = llm_config.params['USER_START']
formatted_conversation = conversation.replace('<break>', '\n')#llm_config.params['USER_END'] + '\n' + llm_config.params['USER_START'])
prompt += self.dialogue_prompt.format(
context='',
context = '{context}',
previous_conversation=formatted_conversation,
character2=context.speaker_name,
character1=context.target_name,
Expand Down Expand Up @@ -146,7 +146,7 @@ def perform_reaction(self, action: str, character_name: str, acting_character_na
def free_form_action(self, action_context: ActionContext):
prompt = self.pre_prompt
prompt += self.free_form_action_prompt.format(
context = '',
context = '{context}',
character_name=action_context.character_name,
action_template=self.action_template)
request_body = deepcopy(self.default_body)
Expand All @@ -158,8 +158,8 @@ def free_form_action(self, action_context: ActionContext):
response = json.loads(parse_utils.sanitize_json(text))
return self._sanitize_free_form_response(response)
except Exception as exc:
print(exc)
raise LlmResponseException('Failed to parse action')
print('Failed to parse action ' + str(exc))
return None


def _sanitize_free_form_response(self, action: dict):
Expand Down
6 changes: 5 additions & 1 deletion tale/llm/contexts/BaseContext.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@


class BaseContext():
from abc import ABC, abstractmethod


class BaseContext(ABC):

def __init__(self, story_context: str) -> None:
self.story_context = story_context

@abstractmethod
def to_prompt_string(self) -> str:
pass
5 changes: 3 additions & 2 deletions tale/llm/contexts/EvokeContext.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

class EvokeContext(BaseContext):

def __init__(self, story_context: str, history: str) -> None:
def __init__(self, story_context: str, history: str, extra_context: str = '') -> None:
super().__init__(story_context)
self.history = history
self.extra_context = extra_context

def to_prompt_string(self) -> str:
return f"Story context:{self.story_context}; History:{self.history};"
return f"Story context:{self.story_context}; History:{self.history}; " + (f"{self.extra_context};" if self.extra_context else '')
16 changes: 16 additions & 0 deletions tale/llm/contexts/WorldGenerationContext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


from tale import parse_utils
from tale.llm.contexts.BaseContext import BaseContext


class WorldGenerationContext(BaseContext):

def __init__(self, story_context: str, story_type: str, world_info: str, world_mood: int) -> None:
super().__init__(story_context)
self.story_type = story_type
self.world_info = world_info
self.world_mood = world_mood

def to_prompt_string(self) -> str:
return f"Story context:{self.story_context}; Story type:{self.story_type}; World info:{self.world_info}; World mood:{parse_utils.mood_string_from_int(self.world_mood)};"
Loading