Skip to content

Commit

Permalink
Merge pull request #59 from neph1/update-v0.22.0
Browse files Browse the repository at this point in the history
Update v0.22.0
  • Loading branch information
neph1 authored Jan 20, 2024
2 parents dd7a3bb + 907745d commit 6fc646d
Show file tree
Hide file tree
Showing 31 changed files with 503 additions and 346 deletions.
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

0 comments on commit 6fc646d

Please sign in to comment.