Skip to content

Commit 88d4c97

Browse files
Added option to output the raw json additionally to the output.
1 parent cdf86b3 commit 88d4c97

File tree

5 files changed

+56
-31
lines changed

5 files changed

+56
-31
lines changed

examples/07_Memory/VirtualGameMaster/main.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from llama_cpp_agent.llm_agent import SystemPromptModule, SystemPromptModulePosition
88
from llama_cpp_agent.providers import LlamaCppServerProvider
99
from memory import output_settings, agent_core_memory, agent_retrieval_memory, agent_event_memory, update_memory_section
10-
from prompts import game_master_prompt, examples, memory_prompt, wrap_function_response_in_xml_tags_json_mode, generate_fake_write_message, generate_write_message_with_examples, wrap_player_message_in_xml_tags_json_mode
10+
from prompts import game_master_prompt, examples, memory_prompt, wrap_function_response_in_xml_tags_json_mode, \
11+
generate_fake_write_message, generate_write_message_with_examples, wrap_player_message_in_xml_tags_json_mode
1112

1213
provider = LlamaCppServerProvider("http://localhost:8080")
1314

@@ -29,46 +30,53 @@
2930
date_time_section = SystemPromptModule("current_date_time", "The following section shows the current date and time:")
3031

3132
example_section = SystemPromptModule("examples",
32-
"The following examples show you which kind of responses you should write to the user based on the current scenario:", suffix="Always remember to never write actions or dialogue for the user! Always let the user decide on actions or dialogue!")
33+
"The following examples show you which kind of responses you should write to the user based on the current scenario:",
34+
suffix="Always remember to never write actions or dialogue for the user! Always let the user decide on actions or dialogue!")
3335
example_section.set_content(examples)
3436
memory_intro_section = SystemPromptModule("memory_intro",
3537
"To support you in your task as a game master and to help you remembering things, you have access to 3 different types of memory.",
3638
position=SystemPromptModulePosition.after_system_instructions)
3739
memory_intro_section.set_content(memory_prompt)
40+
output_settings.output_structured_output_and_raw_json_string = True
3841
while True:
3942
user_input = input(">")
4043
if user_input == "exit":
4144
break
4245
update_memory_section(memory_section)
4346
date_time_section.set_content(datetime.datetime.now().strftime("%d.%m.%Y") + "\nFormat: dd.mm.yyyy")
4447

45-
agent_event_memory.add_event_to_queue(Roles.user, wrap_player_message_in_xml_tags_json_mode(user_input))
46-
agent_output = agent.get_chat_response(
48+
agent_event_memory.add_event(Roles.user, wrap_player_message_in_xml_tags_json_mode(user_input))
49+
agent_output, json_output = agent.get_chat_response(
4750
chat_history=agent_event_memory.get_event_memory_manager().build_chat_history(),
4851
llm_sampling_settings=settings,
4952
system_prompt_modules=[memory_intro_section, memory_section, date_time_section],
5053
structured_output_settings=output_settings)
5154

55+
agent_event_memory.add_event(Roles.assistant, json_output)
5256
while True:
5357
update_memory_section(memory_section)
5458
date_time_section.set_content(datetime.datetime.now().strftime("%d.%m.%Y") + "\nFormat: dd.mm.yyyy")
5559

5660
if agent_output[0]["function"] == "write_message_to_player":
57-
agent_event_memory.add_event_to_queue(Roles.tool, generate_write_message_with_examples(examples=example_section.get_formatted_content()))
5861
output = agent.get_chat_response(
62+
generate_write_message_with_examples(examples=example_section.get_formatted_content()),
63+
role=Roles.tool,
5964
chat_history=agent_event_memory.get_event_memory_manager().build_chat_history(),
6065
add_message_to_chat_history=False, add_response_to_chat_history=False,
6166
system_prompt_modules=[memory_intro_section, memory_section, date_time_section],
6267
llm_sampling_settings=settings)
63-
agent_event_memory.add_event_to_queue(Roles.tool, generate_fake_write_message())
64-
agent_event_memory.add_event_to_queue(Roles.assistant, output)
68+
agent_event_memory.add_event(Roles.tool, generate_fake_write_message())
69+
agent_event_memory.add_event(Roles.assistant, output)
6570

6671
print(output)
6772
break
6873

69-
agent_event_memory.add_event_to_queue(Roles.tool, wrap_function_response_in_xml_tags_json_mode(agent_output[0]["return_value"]))
70-
agent_output = agent.get_chat_response(chat_history=agent_event_memory.get_event_memory_manager().build_chat_history(),
71-
llm_sampling_settings=settings,
72-
system_prompt_modules=[memory_intro_section, memory_section,
73-
date_time_section],
74-
structured_output_settings=output_settings)
74+
agent_event_memory.add_event(Roles.tool, wrap_function_response_in_xml_tags_json_mode(
75+
agent_output[0]["return_value"]))
76+
agent_output, json_output = agent.get_chat_response(
77+
chat_history=agent_event_memory.get_event_memory_manager().build_chat_history(),
78+
llm_sampling_settings=settings,
79+
system_prompt_modules=[memory_intro_section, memory_section,
80+
date_time_section],
81+
structured_output_settings=output_settings)
82+
agent_event_memory.add_event(Roles.assistant, json_output)

src/llama_cpp_agent/agent_memory/event_memory_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from sqlalchemy.orm import Session
2-
from .event_memory import Event, EventType
2+
from .event_memory import Event
33
import datetime
44
import json
55

@@ -24,7 +24,7 @@ def build_chat_history(self):
2424
messages = self.build_event_memory_context()
2525
for message in messages:
2626
history.add_message(message)
27-
return messages
27+
return history
2828

2929
def add_event_to_queue(self, event_type: Roles, content: str, metadata: dict):
3030
new_event = Event(

src/llama_cpp_agent/agent_memory/memory_tools.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
from sqlalchemy import create_engine
77
from sqlalchemy.orm import sessionmaker, scoped_session
88

9-
from .event_memory import EventType, Base
9+
from .event_memory import Base
1010
from .event_memory_manager import EventMemoryManager
11+
from ..chat_history.messages import Roles
1112
from ..function_calling import LlamaCppFunctionTool
1213
from .core_memory_manager import CoreMemoryManager
1314
from .retrieval_memory_manager import RetrievalMemoryManager, RetrievalMemory
@@ -39,10 +40,10 @@ def run(self, event_memory_manager: EventMemoryManager):
3940
self.page = 0
4041
return event_memory_manager.query_events(
4142
event_types=[
42-
EventType.UserMessage,
43-
EventType.AgentMessage,
44-
EventType.SystemMessage,
45-
EventType.FunctionMessage,
43+
Roles.user,
44+
Roles.assistant,
45+
Roles.system,
46+
Roles.tool,
4647
],
4748
content_keywords=self.keywords,
4849
start_date=parsed_start_datetime,
@@ -83,10 +84,10 @@ def run(self, event_memory_manager: EventMemoryManager):
8384

8485
return event_memory_manager.query_events(
8586
event_types=[
86-
EventType.UserMessage,
87-
EventType.AgentMessage,
88-
EventType.SystemMessage,
89-
EventType.FunctionMessage,
87+
Roles.user,
88+
Roles.assistant,
89+
Roles.system,
90+
Roles.tool,
9091
],
9192
start_date=parsed_start_datetime,
9293
end_date=parsed_end_datetime,
@@ -279,6 +280,8 @@ def __init__(self, event_queue_file=None, db_path="sqlite:///events.db"):
279280
conversation_search_date, event_memory_manager=self.event_memory_manager
280281
)
281282

283+
def add_event(self, role: Roles, content:str):
284+
self.event_memory_manager.add_event_to_queue(role, content, {})
282285
def get_event_memory_manager(self):
283286
return self.event_memory_manager
284287

src/llama_cpp_agent/llm_agent.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,17 @@ def get_response_role_and_completion(
427427
"content": message,
428428
},
429429
)
430+
430431
if system_prompt:
431-
messages[0]["content"] = system_prompt
432+
if messages[0]["role"] != Roles.system:
433+
messages.insert(0, {"role": Roles.system, "content": system_prompt})
434+
else:
435+
messages[0]["content"] = system_prompt
432436
else:
433-
messages[0]["content"] = self.system_prompt
437+
if messages[0]["role"] != Roles.system:
438+
messages.insert(0, {"role": Roles.system, "content": self.system_prompt})
439+
else:
440+
messages[0]["content"] = self.system_prompt
434441

435442
additional_suffix = ""
436443
if self.add_tools_and_structures_documentation_to_system_prompt:

src/llama_cpp_agent/llm_output_settings/settings.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ class LlmStructuredOutputSettings(BaseModel):
111111
False,
112112
description="If the output should be just the generated JSON string by the LLM",
113113
)
114-
114+
output_structured_output_and_raw_json_string: Optional[bool] = Field(
115+
False,
116+
description="If the output should be a tuple of the output and the generated JSON string by the LLM",
117+
)
115118
class Config:
116119
arbitrary_types_allowed = True
117120

@@ -144,7 +147,8 @@ def from_llama_cpp_function_tools(
144147

145148
@staticmethod
146149
def from_pydantic_models(
147-
models: List[type[BaseModel]], output_type: LlmStructuredOutputType, add_thoughts_and_reasoning_field: bool = False
150+
models: List[type[BaseModel]], output_type: LlmStructuredOutputType,
151+
add_thoughts_and_reasoning_field: bool = False
148152
):
149153
"""
150154
Create settings from a list of Pydantic models with a specific output type.
@@ -612,22 +616,21 @@ def add_all_current_functions_to_heartbeat_list(self, excluded: list[str] = None
612616
[tool.model.__name__ for tool in self.function_tools if tool.model.__name__ not in excluded]
613617
)
614618

615-
616619
def handle_structured_output(self, llm_output: str, prompt_suffix: str = None):
617620
if self.output_raw_json_string:
618621
return llm_output
619622

620623
if prompt_suffix:
621624
llm_output = llm_output.replace(prompt_suffix, "", 1)
622625

623-
624626
if (
625627
self.output_type is LlmStructuredOutputType.function_calling
626628
or self.output_type is LlmStructuredOutputType.parallel_function_calling
627629
):
628630
output = parse_json_response(llm_output)
629631
output = self.clean_keys(output)
630-
632+
if self.output_structured_output_and_raw_json_string:
633+
return self.handle_function_call(output), llm_output
631634
return self.handle_function_call(output)
632635
elif self.output_type == LlmStructuredOutputType.object_instance:
633636
output = parse_json_response(llm_output)
@@ -636,6 +639,8 @@ def handle_structured_output(self, llm_output: str, prompt_suffix: str = None):
636639
model_attributes = output[self.output_model_attributes_field_name]
637640
for model in self.pydantic_models:
638641
if model_name == model.__name__:
642+
if self.output_structured_output_and_raw_json_string:
643+
return model(**model_attributes), llm_output
639644
return model(**model_attributes)
640645

641646
elif self.output_type == LlmStructuredOutputType.list_of_objects:
@@ -648,6 +653,8 @@ def handle_structured_output(self, llm_output: str, prompt_suffix: str = None):
648653
model_attributes = out[self.output_model_attributes_field_name]
649654
if model_name == model.__name__:
650655
models.append(model(**model_attributes))
656+
if self.output_structured_output_and_raw_json_string:
657+
return models, llm_output
651658
return models
652659
return llm_output
653660

0 commit comments

Comments
 (0)