fix: patch bug in system prompt formatter that was triggering if you … (#785)
This commit is contained in:
@@ -118,6 +118,27 @@ def compile_memory_metadata_block(
|
||||
return memory_metadata_block
|
||||
|
||||
|
||||
class PreserveMapping(dict):
|
||||
"""Used to preserve (do not modify) undefined variables in the system prompt"""
|
||||
|
||||
def __missing__(self, key):
|
||||
return "{" + key + "}"
|
||||
|
||||
|
||||
def safe_format(template: str, variables: dict) -> str:
|
||||
"""
|
||||
Safely formats a template string, preserving empty {} and {unknown_vars}
|
||||
while substituting known variables.
|
||||
|
||||
If we simply use {} in format_map, it'll be treated as a positional field
|
||||
"""
|
||||
# First escape any empty {} by doubling them
|
||||
escaped = template.replace("{}", "{{}}")
|
||||
|
||||
# Now use format_map with our custom mapping
|
||||
return escaped.format_map(PreserveMapping(variables))
|
||||
|
||||
|
||||
def compile_system_message(
|
||||
system_prompt: str,
|
||||
in_context_memory: Memory,
|
||||
@@ -169,7 +190,8 @@ def compile_system_message(
|
||||
|
||||
# render the variables using the built-in templater
|
||||
try:
|
||||
formatted_prompt = system_prompt.format_map(variables)
|
||||
formatted_prompt = safe_format(system_prompt, variables)
|
||||
print(f"Formatted system prompt:\n{formatted_prompt}")
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to format system prompt - {str(e)}. System prompt value:\n{system_prompt}")
|
||||
|
||||
|
||||
59
tests/test_system_prompt_compiler.py
Normal file
59
tests/test_system_prompt_compiler.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from letta.services.helpers.agent_manager_helper import safe_format
|
||||
|
||||
CORE_MEMORY_VAR = "My core memory is that I like to eat bananas"
|
||||
VARS_DICT = {"CORE_MEMORY": CORE_MEMORY_VAR}
|
||||
|
||||
|
||||
def test_formatter():
|
||||
|
||||
# Example system prompt that has no vars
|
||||
NO_VARS = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
"""
|
||||
|
||||
assert NO_VARS == safe_format(NO_VARS, VARS_DICT)
|
||||
|
||||
# Example system prompt that has {CORE_MEMORY}
|
||||
CORE_MEMORY_VAR = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
{CORE_MEMORY}
|
||||
"""
|
||||
|
||||
CORE_MEMORY_VAR_SOL = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
My core memory is that I like to eat bananas
|
||||
"""
|
||||
|
||||
assert CORE_MEMORY_VAR_SOL == safe_format(CORE_MEMORY_VAR, VARS_DICT)
|
||||
|
||||
# Example system prompt that has {CORE_MEMORY} and {USER_MEMORY} (latter doesn't exist)
|
||||
UNUSED_VAR = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
{USER_MEMORY}
|
||||
{CORE_MEMORY}
|
||||
"""
|
||||
|
||||
UNUSED_VAR_SOL = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
{USER_MEMORY}
|
||||
My core memory is that I like to eat bananas
|
||||
"""
|
||||
|
||||
assert UNUSED_VAR_SOL == safe_format(UNUSED_VAR, VARS_DICT)
|
||||
|
||||
# Example system prompt that has {CORE_MEMORY} and {USER_MEMORY} (latter doesn't exist), AND an empty {}
|
||||
UNUSED_AND_EMPRY_VAR = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
{}
|
||||
{USER_MEMORY}
|
||||
{CORE_MEMORY}
|
||||
"""
|
||||
|
||||
UNUSED_AND_EMPRY_VAR_SOL = """
|
||||
THIS IS A SYSTEM PROMPT WITH NO VARS
|
||||
{}
|
||||
{USER_MEMORY}
|
||||
My core memory is that I like to eat bananas
|
||||
"""
|
||||
|
||||
assert UNUSED_AND_EMPRY_VAR_SOL == safe_format(UNUSED_AND_EMPRY_VAR, VARS_DICT)
|
||||
Reference in New Issue
Block a user