Skip to content

Commit

Permalink
add test for add_event and some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
neph1 committed Dec 3, 2023
1 parent 90e717b commit 0980382
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 66 deletions.
2 changes: 1 addition & 1 deletion llm_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ OPENAI_API_KEY: "OPENAI_API_KEY"
OPENAI_JSON_FORMAT: '{"type":"json_object"}'
ITEMS_PROMPT: "Add {items} of various type."
SPAWN_PROMPT: "Add a level {level}, {alignment} npc or mob."
IDLE_ACTION_PROMPT: "Sentiments towards characters: {sentiments}; History: {history}; Last action: {last_action}; Location: {location}; Acting character: {character}; [USER_START] Choose an item from: {items}, or a character from:{characters}, to interact with, or perform a solo action. Do not make up new characters. Don't contradict or repeat Last Action. [USER_START] Don't write what {character_name} thinks, or what the player (You) or anyone else does. Write what {character_name} does, in present tense third person point of view. Use less than 40 words. "
IDLE_ACTION_PROMPT: "Sentiments towards characters: {sentiments}; History: {history}; Location: {location}; Acting character: {character}; [USER_START] Choose an item from: {items}, or a character from:{characters}, to interact with, or perform a solo action. Do not make up new characters. The action should be a continuation of History, or a new one, but should not repeat or be similar. [USER_START] Don't write what {character_name} thinks, or what the player (You) or anyone else does. Write what {character_name} does, in present tense third person point of view. Use less than 40 words. "
TRAVEL_PROMPT: "[USER_START] For {character}: pick a location from [{locations}] they would like to travel to or a direction from [{directions}], or stay in the current location. Do not make up new locations. Write what {character_name} chooses. [USER_START] Write only the location name, direction, or write nothing to stay in the same location. Write nothing else."
REACTION_PROMPT: "Story context: {story_context}; History: {history}; [USER_START] Act as {character}. {acting_character_name} has performed the following action that involves {character_name}: {action}. {character_name}'s sentiment towards {acting_character_name}: {sentiment}. [USER_START] Respond with a suitable action for {character_name}, in present tense third person point of view. Use less than 40 words."
STORY_BACKGROUND_PROMPT: "[USER_START] For an RPG described as {story_type} set in a world described as {world_mood}, {world_info}, write a captivating background story that the player can interact with. Include a large scale plot conflict that the player will encounter. Use less than 400 words."
Expand Down
8 changes: 4 additions & 4 deletions tale/cmds/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,20 +753,20 @@ def do_enrich(player: Player, parsed: base.ParseResult, ctx: util.Context) -> No
player.tell("(generated: %s, items)" % (len(items)))
for item in items:
ctx.driver.story._catalogue.add_item(item)
return
return
if parsed.args[0] == "creatures":
creatures = ctx.driver.llm_util.generate_world_creatures()
if creatures:
player.tell("(generated: %s, creatures)" % (len(creatures)))
for creature in creatures:
ctx.driver.story._catalogue.add_living(creature)
return
ctx.driver.story._catalogue.add_creature(creature)
return

@wizcmd("add_event")
def do_add_event(player: Player, parsed: base.ParseResult, ctx: util.Context) -> None:
""" Add an event that happens in the current location. """
if len(parsed.args) < 1:
raise ParseError("You need to define an event inside ''")
raise ParseError("You need to define an event")
player.location._notify_action_all( base.ParseResult(verb='location-event', unparsed=parsed.unparsed, who_info=None), actor=None)
player.location.tell(parsed.unparsed, evoke=False)

2 changes: 1 addition & 1 deletion tale/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ def go_through_exit(self, player: player.Player, direction: str, evoke: bool=Tru
dynamic_story = typing.cast(DynamicStory, self.story)
zone = dynamic_story.find_zone(location=xt.target.name)
self.llm_util.generate_random_spawn(xt.target, zone.get_info())
else:
elif isinstance(self.story, DynamicStory):
dynamic_story = typing.cast(DynamicStory, self.story)
zone = dynamic_story.find_zone(location=player.location.name)
new_zone = dynamic_story.find_zone(location=xt.target.name)
Expand Down
4 changes: 2 additions & 2 deletions tale/lang.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,8 @@ def validate_gender_mf(value: str) -> str:
raise ValueError("That is not a valid gender.")

def gender_string(value: str) -> str:
if value == 'f':
if value.lower() == 'f':
return 'female'
if value == 'm':
if value.lower() == 'm':
return 'male'
return 'non-specified'
4 changes: 2 additions & 2 deletions tale/llm/world_building.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def generate_start_zone(self, location_desc: str, story_type: str, story_context


def generate_world_items(self, story_context: str, story_type: str, world_info: str, world_mood: int) -> dict:
""" Since 0.16.1 returns a json list, rather than a list of items"""
""" Since 0.16.1 returns a json array, rather than a list of items"""
prompt = self.world_items_prompt.format(story_context=story_context,
story_type=story_type,
world_info=world_info,
Expand All @@ -262,7 +262,7 @@ def generate_world_items(self, story_context: str, story_type: str, world_info:
return None

def generate_world_creatures(self, story_context: str, story_type: str, world_info: str, world_mood: int):
""" Since 0.16.1 returns a json list, rather than a list of creatures"""
""" Since 0.16.1 returns a json array, rather than a list of creatures"""
prompt = self.world_creatures_prompt.format(story_context=story_context,
story_type=story_type,
world_info=world_info,
Expand Down
6 changes: 3 additions & 3 deletions tale/parse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def load_npcs(json_npcs: [], locations = {}) -> dict:
if 'npc' in npc_type.lower():

new_npc = StationaryNpc(name=name,
gender=lang.validate_gender_mf(npc.get('gender', 'm')[0]),
gender=lang.validate_gender(npc.get('gender', 'm')[0]),
race=npc.get('race', 'human').lower(),
title=npc.get('title', name),
descr=npc.get('descr', ''),
Expand All @@ -163,7 +163,7 @@ def load_npcs(json_npcs: [], locations = {}) -> dict:
else:

new_npc = StationaryMob(name=npc['name'],
gender=lang.validate_gender_mf(npc.get('gender', 'm')[0]),
gender=lang.validate_gender(npc.get('gender', 'm')[0]),
race=npc.get('race', 'human').lower(),
title=npc.get('title', npc['name']),
descr=npc.get('descr', ''),
Expand Down Expand Up @@ -586,7 +586,7 @@ def save_npcs(creatures: []) -> dict:
stored_npc['type'] = 'Mob'
if npc.stats:
stored_npc['race'] = npc.stats.race
stored_npc['gender'] = npc.gender
stored_npc['gender'] = lang.gender_string(npc.gender)
stored_npc['title'] = npc.title
stored_npc['descr'] = npc.description
stored_npc['short_descr'] = npc.short_description
Expand Down
49 changes: 0 additions & 49 deletions tests/test_enrich_command.py

This file was deleted.

5 changes: 2 additions & 3 deletions tests/test_json_story.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ def test_load_anything_story(self):
assert(zone.level == 5)
assert(zone.mood == -5)



gas_station = story.get_location('The Cursed Swamp', 'Abandoned gas station')
assert(gas_station)
assert(gas_station.name == 'Abandoned gas station')
Expand Down Expand Up @@ -111,5 +109,6 @@ def test_load_anything_story(self):


print(story.get_catalogue.get_items())
assert(len(story.get_catalogue.get_items()) == 10) # 8 story items + 2 generic items

assert(len(story.get_catalogue.get_items()) == 8 + len(generic.generic_items.get(''))) # 8 story items + generic items
assert(len(story.get_catalogue.get_creatures()) == 5)
1 change: 0 additions & 1 deletion tests/test_mudobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ def test_exits(self):

def test_go_through_exit(self):
driver = FakeDriver()
driver.story = DynamicStory()
hall = Location("hall")
attic = Location("attic")
exit1 = Exit("ladder1", attic, "exit 1 to attic", enter_msg="entering the attic via exit 1")
Expand Down
91 changes: 91 additions & 0 deletions tests/test_wizard_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@



import pytest
import tale
from tale.base import Location, ParseResult
from tale.cmds import wizard, wizcmd
from tale.errors import ParseError
from tale.llm.LivingNpc import LivingNpc
from tale.llm.llm_ext import DynamicStory
from tale.llm.llm_utils import LlmUtil
from tale.player import Player
from tale.story import StoryConfig
from tests.supportstuff import FakeDriver, FakeIoUtil


class TestEnrichCommand():

context = tale._MudContext()
context.config = StoryConfig()
io_util = FakeIoUtil(response=['{"items":[{"name":"Enchanted Petals", "type":"Health", "value": 20, "description": "A handful of enchanted petals that can be used to heal wounds and cure ailments."}]}',
'{"creatures": [ { "name": "Whimsy Woozle", "description": "A gentle, ethereal creature with a penchant for gardening and poetry. They tend to the area\'s lush fields and forests, filling the air with sweet melodies and the scent of blooming wildflowers. They are friendly and welcoming to all visitors.", "level": 1 }, { "name": "Lunar Lopster", "description": "A mysterious crustacean with an affinity for the moon\'s gentle light. They roam the area at night, their glowing shells lighting the way through the darkness. They are neutral towards visitors, but may offer cryptic advice or guidance to those who seek it.", "level": 2 }, { "name": "Shadow Stag", "description": "A sleek and elusive creature with a mischievous grin. They roam the area\'s forests, their dark forms blending into the shadows. They are hostile towards intruders, and will not hesitate to attack those who threaten their home.", "level": 3 }, { "name": "Moonflower", "description": "A rare and beautiful flower that blooms only under the light of the full moon. They can be found in the area\'s forests, and are said to have powerful healing properties. They are very friendly towards visitors, and will offer their petals to those who show kindness and respect.", "level": 4 }, { "name": "Moonstone", "description": "A rare and valuable mineral that can be found in the area\'s mountains. It glows with a soft, ethereal light, and is said to have powerful magical properties. It is highly sought after by collectors, and can be found in both the earth and the water.", "level": 5 }]}'])
llm_util = LlmUtil(io_util)
story = DynamicStory()
llm_util.set_story(story)

test_player = Player('test', 'f')
test_player.privileges.add('wizard')

context.driver = FakeDriver()
context.driver.llm_util = llm_util
context.driver.story = story

def test_enrich_no_variable(self):
parse_result = ParseResult(verb='enrich', unparsed='')
with pytest.raises(ParseError, match="You need to define 'items' or 'creatures'."):
wizard.do_enrich(self.test_player, parse_result, self.context)

assert(len(self.story._catalogue._items) == 0)

def test_enrich_items(self):
self.context.driver.llm_util.io_util.set_response('{"items":[{"name":"Enchanted Petals", "type":"Health", "value": 20, "description": "A handful of enchanted petals that can be used to heal wounds and cure ailments."}]}')
parse_result = ParseResult(verb='enrich items', args=['items'])
wizard.do_enrich(self.test_player, parse_result, self.context)

assert(len(self.story._catalogue._items) == 1)

def test_enrich_creatures(self):
self.context.driver.llm_util.io_util.set_response('{"creatures": [ { "name": "Whimsy Woozle", "description": "A gentle, ethereal creature with a penchant for gardening and poetry. They tend to the area\'s lush fields and forests, filling the air with sweet melodies and the scent of blooming wildflowers. They are friendly and welcoming to all visitors.", "level": 1 }, { "name": "Lunar Lopster", "description": "A mysterious crustacean with an affinity for the moon\'s gentle light. They roam the area at night, their glowing shells lighting the way through the darkness. They are neutral towards visitors, but may offer cryptic advice or guidance to those who seek it.", "level": 2 }, { "name": "Shadow Stag", "description": "A sleek and elusive creature with a mischievous grin. They roam the area\'s forests, their dark forms blending into the shadows. They are hostile towards intruders, and will not hesitate to attack those who threaten their home.", "level": 3 }, { "name": "Moonflower", "description": "A rare and beautiful flower that blooms only under the light of the full moon. They can be found in the area\'s forests, and are said to have powerful healing properties. They are very friendly towards visitors, and will offer their petals to those who show kindness and respect.", "level": 4 }, { "name": "Moonstone", "description": "A rare and valuable mineral that can be found in the area\'s mountains. It glows with a soft, ethereal light, and is said to have powerful magical properties. It is highly sought after by collectors, and can be found in both the earth and the water.", "level": 5 }]}')
parse_result = ParseResult(verb='enrich creatures', args=['creatures'])
wizard.do_enrich(self.test_player, parse_result, self.context)

assert(len(self.story._catalogue._creatures) == 5)

class TestEvents():

context = tale._MudContext()
context.config = StoryConfig()
io_util = FakeIoUtil(response='')
llm_util = LlmUtil(io_util)
story = DynamicStory()
llm_util.set_story(story)

test_player = Player('test', 'f')
test_player.privileges.add('wizard')

context.driver = FakeDriver()
context.driver.llm_util = llm_util
context.driver.story = story

def test_add_event_no_parse(self):
parse_result = ParseResult(verb='add_event', args=[])
with pytest.raises(ParseError, match="You need to define an event"):
wizard.do_add_event(self.test_player, parse_result, self.context)

def test_add_event(self):
event_string = 'a foreboding storm approaches'
test_location = Location('test_location')
self.story.add_location(test_location)
test_npc = LivingNpc('test_npc', 'f', age=30)
test_location.insert(test_npc, actor=None)
test_location.insert(self.test_player, actor=None)
parse_result = ParseResult(verb='add_event', args=[event_string], unparsed=event_string)
wizard.do_add_event(self.test_player, parse_result, self.context)
dumped = tale.llm.llm_cache.json_dump()
events = dumped['events'].values()
for event in events:
if event == event_string:
assert(True)
return
assert(False)

0 comments on commit 0980382

Please sign in to comment.