Skip to content

Commit

Permalink
Merge pull request #68 from neph1/update-v0.24.2
Browse files Browse the repository at this point in the history
Update v0.24.2
  • Loading branch information
neph1 authored Feb 6, 2024
2 parents 372848f + 7407251 commit 47811d0
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 33 deletions.
27 changes: 16 additions & 11 deletions tale/cmds/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,32 +838,37 @@ def do_set_visible(player: Player, parsed: base.ParseResult, ctx: util.Context)
@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:
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])
arg1 = parsed.args[0]
object = player.location.search_living(arg1)
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.search_item(arg1, include_inventory=True, include_location=True)
if not object and player.location.name == arg1:
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]))
description = parsed.unparsed.replace(arg1, '').strip()
object.description = description
player.tell("%s description set to %s" % (object, description))
except ValueError as x:
raise ActionRefused(str(x))

@wizcmd("set_goal")
def do_set_goal(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
"""Set a goal for a LivingNpc."""
if len(parsed.args) != 2:
raise ParseError("You need to specify the character and the goal")
if not parsed.who_1:
raise ParseError("You need to specify a character")
if len(parsed.args) < 2:
raise ParseError("You need to specify a goal")
try:
character = player.location.search_living(parsed.args[0])
character = player.location.search_living(parsed.who_1.name)
if not character or not isinstance(character, LivingNpc):
raise ParseError("No LivingNpc found")
character.goal = parsed.args[1]
player.tell("%s goal set to %s" % (character, parsed.args[1]))
goal = parsed.unparsed.replace(parsed.who_1.name, '').strip()
character.goal = goal
player.tell("%s goal set to %s" % (character, goal))
except ValueError as x:
raise ActionRefused(str(x))

Expand Down
31 changes: 19 additions & 12 deletions tale/llm/LivingNpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def _do_react(self, parsed: ParseResult, actor: Living) -> None:
sentiment=self.sentiments.get(actor.name, '') if actor else '')
if action:
self.action_history.append(action)
self._defer_result(action, verb='idle-action')
self._defer_result(action, verb='reaction')

def handle_item_result(self, result: ItemHandlingResult, actor: Living) -> bool:
if result.to == self.title:
Expand Down Expand Up @@ -202,21 +202,30 @@ def idle_action(self):
if len(self.planned_actions) > 0:
action = self.planned_actions.pop(0)
if isinstance(action, list):
action = action[0]
self.action_history.append(action)
self._defer_result(action)
return action
action = action[0] if len(action) > 0 else ''
if action:
self.action_history.append(action)
self._defer_result(action)
return action
return None
#self.location.notify_action(result, actor=self)

def autonomous_action(self) -> str:
action = mud_context.driver.llm_util.free_form_action(character_card=self.character_card,
actions = mud_context.driver.llm_util.free_form_action(character_card=self.character_card,
character_name=self.title,
location=self.location,
event_history=llm_cache.get_events(self._observed_events)) # type: ActionResponse
if not action:
event_history=llm_cache.get_events(self._observed_events)) # type: list
if not actions:
return None

self.planned_actions.append(actions)

defered_actions = []
defered_actions.extend(self._parse_action(actions.pop(0)))

return '\n'.join(defered_actions)

def _parse_action(self, action):
defered_actions = []
if action.goal:
self.goal = action.goal
Expand All @@ -237,7 +246,7 @@ def autonomous_action(self) -> str:
self.tell_others('\n' + text, evoke=False)
defered_actions.append(f'"{text}"')
if not action.action:
return '\n'.join(defered_actions)
return defered_actions
if action.action == 'move':
try:
exit = self.location.exits[action.target]
Expand All @@ -263,9 +272,7 @@ def autonomous_action(self) -> str:
if item:
self.set_wearable(item)
defered_actions.append(f"{self.title} wears {item.title}")

return '\n'.join(defered_actions)

return defered_actions

def _defer_result(self, action: str, verb: str="idle-action"):
""" Defer an action to be performed at the next tick,
Expand Down
9 changes: 7 additions & 2 deletions tale/llm/character.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def perform_reaction(self, action: str, character_name: str, acting_character_na
text = self.io_util.synchronous_request(request_body, prompt=prompt)
return parse_utils.trim_response(text) + "\n"

def free_form_action(self, action_context: ActionContext) -> ActionResponse:
def free_form_action(self, action_context: ActionContext) -> list:
prompt = self.pre_prompt
prompt += self.free_form_action_prompt.format(
context = '{context}',
Expand All @@ -157,7 +157,12 @@ def free_form_action(self, action_context: ActionContext) -> ActionResponse:
if not text:
return None
response = json.loads(parse_utils.sanitize_json(text))
return ActionResponse(response)
if isinstance(response, dict):
return [ActionResponse(response)]
actions = []
for action in response:
actions.append(ActionResponse(action))
return actions
except Exception as exc:
print('Failed to parse action ' + str(exc))
return None
Expand Down
2 changes: 1 addition & 1 deletion tale/llm/llm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def on_complete():
target.avatar = image_name + '.jpg'
return result

def free_form_action(self, location: Location, character_name: str, character_card: str = '', event_history: str = '') -> ActionResponse:
def free_form_action(self, location: Location, character_name: str, character_card: str = '', event_history: str = '') -> list:
action_context = ActionContext(story_context=self.__story_context,
story_type=self.__story_type,
character_name=character_name,
Expand Down
19 changes: 16 additions & 3 deletions tests/test_llm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def test_free_form_action(self):
self.llm_util._character.io_util.response = '{"action":"test_action", "text":"test response", "target":"test target", "item":"test item"}'
location = Location(name='Test Location')
self.llm_util.set_story(self.story)
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='') # type: ActionResponse
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='')[0] # type: list
assert(result)
assert(result.action == 'test_action')
assert(result.text == 'test response')
Expand All @@ -122,7 +122,7 @@ def test_free_form_action_lists(self):
self.llm_util._character.io_util.response = '{"action":["test_action"], "text":["test response"], "target":["test target"], "item":["test item"]}'
location = Location(name='Test Location')
self.llm_util.set_story(self.story)
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='') # type: ActionResponse
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='')[0] # type: ActionResponse
assert(result)
assert(result.action == 'test_action')
assert(result.text == 'test response')
Expand All @@ -133,10 +133,23 @@ def test_free_form_action_dict(self):
self.llm_util._character.io_util.response = '{"action":{"action":"test_action"}, "target":{"name":"test target"}}'
location = Location(name='Test Location')
self.llm_util.set_story(self.story)
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='') # type: ActionResponse
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='')[0] # type: ActionResponse
assert(result.action == 'test_action')
assert(result.target == 'test target')

def test_free_form_action_multi(self):
self.llm_util._character.io_util.response = '[{"action":"test_action", "text":"test response", "target":"test target", "item":"test item"},{"action":"test_action2"},{"action":"test_action3"}]'
location = Location(name='Test Location')
self.llm_util.set_story(self.story)
result = self.llm_util.free_form_action(location=location, character_name='', character_card='', event_history='') # type: list
assert(len(result) == 3)
assert(result[0].action == 'test_action')
assert(result[0].text == 'test response')
assert(result[0].target == 'test target')
assert(result[0].item == 'test item')
assert(result[1].action == 'test_action2')
assert(result[2].action == 'test_action3')

def test_init_image_gen(self):
self.llm_util._init_image_gen("Automatic1111")
assert self.llm_util._image_gen.__class__ == Automatic1111().__class__
Expand Down
8 changes: 4 additions & 4 deletions tests/test_wizard_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ def test_set_description_location(self):
player = Player('test', 'f')
player.privileges.add('wizard')
location.init_inventory([player])
parse_result = ParseResult(verb='set_description', args=['test_room', 'test description'])
parse_result = ParseResult(verb='set_description', args=['test_room', 'test description'], unparsed='test_room test description')
wizard.do_set_description(player, parse_result, self.context)
assert(location.description == 'test description')

def test_set_description_item(self):
location = Location('test_room')
item = Item('test_item')
location.init_inventory([self.test_player, item])
parse_result = ParseResult(verb='set_description', args=['test_item', 'test description'])
parse_result = ParseResult(verb='set_description', args=['test_item', 'test description'], unparsed='test_item test description')
wizard.do_set_description(self.test_player, parse_result, self.context)
assert(item.description == 'test description')

Expand All @@ -79,15 +79,15 @@ def test_set_description_no_args(self):
def test_set_description_not_found(self):
location = Location('test_room')
location.init_inventory([self.test_player])
parse_result = ParseResult(verb='set_description', args=['unknown', 'test description'])
parse_result = ParseResult(verb='set_description', args=['unknown', 'test description'], unparsed='unknown test description')
with pytest.raises(ParseError, match="No object or location found"):
wizard.do_set_description(self.test_player, parse_result, self.context)

def test_set_goal(self):
location = Location('test_room')
npc = LivingNpc('test_npc', 'f')
location.init_inventory([self.test_player, npc])
parse_result = ParseResult(verb='set_goal', args=['test_npc', 'test goal'])
parse_result = ParseResult(verb='set_goal', args=['test_npc', 'test goal'], who_list=[npc], unparsed='test_npc test goal')
wizard.do_set_goal(self.test_player, parse_result, self.context)
assert(npc.goal == 'test goal')

Expand Down

0 comments on commit 47811d0

Please sign in to comment.