Behaviour prompt

Prototype of adjustable behaviour system prompt

frdel committed Oct 29, 2024 at 19:39 UTC 1c026ee75f6f2b3993bf97f44775460e7464335f
9 files changed +145 -3
prompts/default/agent.system.behaviour.md new
+2
@@ -0,0 +1,2 @@
1 +# Behavioral Rules
2 +{{rules}}
\ No newline at end of file
prompts/default/agent.system.behaviour_default.md new
+1
@@ -0,0 +1 @@
1 +- Use linux commands for simple tasks where possible instead of python
\ No newline at end of file
prompts/default/behaviour.merge.msg.md new
+5
@@ -0,0 +1,5 @@
1 +# Current ruleset
2 +{{current_rules}}
3 +
4 +# Adjustments
5 +{{adjustments}}
\ No newline at end of file
prompts/default/behaviour.merge.sys.md new
+17
@@ -0,0 +1,17 @@
1 +# Assistant's job
2 +1. The assistant receives a markdown ruleset of AGENT's behaviour and JSON array of adjustments to be implemented
3 +2. Assistant merges the ruleset with the instructions JSON array into a new markdown ruleset
4 +3. Assistant keeps the ruleset short, removing any duplicates or redundant information
5 +
6 +# Format
7 +- The response format is a markdown format of instructions for AI AGENT explaining how the AGENT is supposed to behave
8 +- No level 1 headings (#), only level 2 headings (##) and bullet points (*)
9 +
10 +# Example when instructions found (do not output this example):
11 +```json
12 +# Language
13 +- The user want to communicate in Spanish, always write responses for the user in Spanish.
14 +
15 +# Format
16 +- User asked for shorted responses, be short and to the point
17 +```
\ No newline at end of file
prompts/default/behaviour.search.sys.md new
+20
@@ -0,0 +1,20 @@
1 +# Assistant's job
2 +1. The assistant receives a history of conversation between USER and AGENT
3 +2. Assistant searches for USER's commands to update AGENT's behaviour
4 +3. Assistant responds with JSON array of instructions to update AGENT's behaviour or empty array if none
5 +
6 +# Format
7 +- The response format is a JSON array of instructions on how the agent should behave in the future
8 +- If the history does not contain any instructions, the response will be an empty JSON array
9 +
10 +# Example when instructions found (do not output this example):
11 +```json
12 +[
13 + "Never call the user by his name",
14 +]
15 +```
16 +
17 +# Example when no instructions:
18 +```json
19 +[]
20 +```
\ No newline at end of file
python/extensions/message_loop_prompts/_20_behaviour_prompt.py new
+24
@@ -0,0 +1,24 @@
1 +from datetime import datetime
2 +from python.helpers.extension import Extension
3 +from agent import Agent, LoopData
4 +from python.helpers import files, memory
5 +
6 +
7 +class BehaviourPrompt(Extension):
8 +
9 + async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
10 + prompt = read_rules(self.agent)
11 + loop_data.system.append(prompt)
12 +
13 +def get_custom_rules_file(agent: Agent):
14 + return memory.get_memory_subdir_abs(agent) + f"/behaviour.md"
15 +
16 +def read_rules(agent: Agent):
17 + rules_file = get_custom_rules_file(agent)
18 + if files.exists(rules_file):
19 + rules = files.read_file(rules_file)
20 + return agent.read_prompt("agent.system.behaviour.md", rules=rules)
21 + else:
22 + rules = agent.read_prompt("agent.system.behaviour_default.md")
23 + return agent.read_prompt("agent.system.behaviour.md", rules=rules)
24 +
\ No newline at end of file
python/extensions/monologue_start/_20_behaviour_update.py new
+73
@@ -0,0 +1,73 @@
1 +import asyncio
2 +from datetime import datetime
3 +import json
4 +from python.helpers.extension import Extension
5 +from agent import Agent, LoopData
6 +from python.helpers import dirty_json, files, memory
7 +from python.helpers.log import LogItem
8 +from python.extensions.message_loop_prompts import _20_behaviour_prompt
9 +
10 +
11 +
12 +class BehaviourUpdate(Extension):
13 +
14 + async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
15 + log_item = self.agent.context.log.log(
16 + type="util",
17 + heading="Updating behaviour",
18 + )
19 + asyncio.create_task(self.update_rules(self.agent, loop_data, log_item))
20 +
21 + async def update_rules(self, agent: Agent, loop_data: LoopData, log_item: LogItem, **kwargs):
22 + adjustments = await self.get_adjustments(agent, loop_data, log_item)
23 + if adjustments:
24 + await self.merge_rules(agent, adjustments, loop_data, log_item)
25 +
26 + async def get_adjustments(self, agent: Agent, loop_data: LoopData, log_item: LogItem, **kwargs) -> list[str] | None:
27 +
28 + # get system message and chat history for util llm
29 + system = self.agent.read_prompt("behaviour.search.sys.md")
30 + msgs_text = self.agent.concat_messages(self.agent.history)
31 +
32 + # log query streamed by LLM
33 + def log_callback(content):
34 + log_item.stream(content=content)
35 +
36 + # call util llm to find solutions in history
37 + adjustments_json = await self.agent.call_utility_llm(
38 + system=system,
39 + msg=msgs_text,
40 + callback=log_callback,
41 + )
42 +
43 + adjustments = dirty_json.DirtyJson.parse_string(adjustments_json)
44 +
45 + if adjustments:
46 + log_item.update(adjustments=adjustments)
47 + return adjustments # type: ignore # for now let's assume the model gets it right and outputs an array
48 + else:
49 + log_item.update(heading="No updates to behaviour")
50 + return None
51 +
52 + async def merge_rules(self, agent: Agent, adjustments: list[str], loop_data: LoopData, log_item: LogItem, **kwargs):
53 + # get system message and current ruleset
54 + system = self.agent.read_prompt("behaviour.merge.sys.md")
55 + current_rules = _20_behaviour_prompt.read_rules(agent)
56 +
57 + # log query streamed by LLM
58 + def log_callback(content):
59 + log_item.stream(ruleset=content)
60 +
61 + msg = self.agent.read_prompt("behaviour.merge.msg.md", current_rules=current_rules, adjustments=json.dumps(adjustments))
62 +
63 + # call util llm to find solutions in history
64 + adjustments_merge = await self.agent.call_utility_llm(
65 + system=system,
66 + msg=msg,
67 + callback=log_callback,
68 + )
69 +
70 + # update rules file
71 + rules_file = _20_behaviour_prompt.get_custom_rules_file(agent)
72 + files.write_file(rules_file, adjustments_merge)
73 + log_item.update(heading="Behaviour updated")
\ No newline at end of file
python/helpers/memory.py
+3
@@ -348,3 +348,6 @@ class Memory:
348 @staticmethod
349 def get_timestamp():
350 return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
351 +
352 +def get_memory_subdir_abs(agent: Agent) -> str:
353 + return files.get_abs_path("memory", agent.config.memory_subdir or "default")
\ No newline at end of file
python/helpers/settings.py
-3
@@ -20,7 +20,6 @@ class Settings(TypedDict):
20
21 embed_model_provider: str
22 embed_model_name: str
23 - embed_model_temperature: float
23 embed_model_kwargs: dict[str, str]
24
25
@@ -203,7 +202,6 @@ def get_embedding_model() -> Embeddings:
202 type=ModelType.EMBEDDING,
203 provider=ModelProvider[settings["embed_model_provider"]],
204 name=settings["embed_model_name"],
206 - temperature=settings["embed_model_temperature"],
205 **settings["embed_model_kwargs"],
206 )
207
@@ -232,7 +230,6 @@ def _get_default_settings() -> Settings:
230 util_model_kwargs={},
231 embed_model_provider=ModelProvider.OPENAI.name,
232 embed_model_name="text-embedding-3-small",
235 - embed_model_temperature=0,
233 embed_model_kwargs={},
234 )
235