main
py 100 lines 3 KB
Raw
1 from helpers import files
2 from helpers.tool import Tool, Response
3 from agent import Agent
4 from helpers.log import LogItem
5 from plugins._memory.helpers import memory
6
7
8 class UpdateBehaviour(Tool):
9
10 async def execute(self, adjustments="", **kwargs):
11
12 # stringify adjustments if needed
13 if not isinstance(adjustments, str):
14 adjustments = str(adjustments)
15
16 await update_behaviour(self.agent, self.log, adjustments)
17 return Response(
18 message=self.agent.read_prompt("behaviour.updated.md"), break_loop=False
19 )
20
21
22 async def update_behaviour(agent: Agent, log_item: LogItem, adjustments: str):
23
24 # get system message and current ruleset
25 system = agent.read_prompt("behaviour.merge.sys.md")
26 current_rules = read_rules(agent)
27
28 # log query streamed by LLM
29 async def log_callback(content):
30 log_item.stream(ruleset=content)
31
32 msg = agent.read_prompt(
33 "behaviour.merge.msg.md", current_rules=current_rules, adjustments=adjustments
34 )
35
36 # call util llm to find solutions in history
37 adjustments_merge = await agent.call_utility_model(
38 system=system,
39 message=msg,
40 callback=log_callback,
41 )
42 adjustments_merge = normalize_ruleset(adjustments_merge)
43
44 # update rules file
45 rules_file = get_custom_rules_file(agent)
46 files.write_file(rules_file, adjustments_merge)
47 log_item.update(ruleset=adjustments_merge, result="Behaviour updated")
48
49
50 def get_custom_rules_file(agent: Agent):
51 return files.get_abs_path(memory.get_memory_subdir_abs(agent), "behaviour.md")
52
53
54 def read_rules(agent: Agent):
55 rules_file = get_custom_rules_file(agent)
56 if files.exists(rules_file):
57 return agent.read_prompt(rules_file)
58 else:
59 return agent.read_prompt("agent.system.behaviour_default.md")
60
61
62 def normalize_ruleset(ruleset: str):
63 text = str(ruleset or "").strip()
64
65 if text.startswith("```") and text.endswith("```"):
66 lines = text.splitlines()
67 text = "\n".join(lines[1:-1]).strip()
68
69 text = text.replace("\r\n", "\n").replace("\r", "\n")
70 text = text.replace("!!!", "")
71 text = text.replace(".## ", ".\n## ")
72
73 normalized_lines = []
74 seen_structural_lines = set()
75 previous_blank = False
76
77 for raw_line in text.splitlines():
78 line = raw_line.rstrip()
79 stripped = line.strip()
80
81 if not stripped:
82 if normalized_lines and not previous_blank:
83 normalized_lines.append("")
84 previous_blank = True
85 continue
86
87 if stripped.startswith("# ") and not stripped.startswith("## "):
88 stripped = "#" + stripped
89 line = stripped
90
91 dedupe_key = stripped.casefold()
92 if stripped.startswith(("## ", "* ")) and dedupe_key in seen_structural_lines:
93 continue
94 if stripped.startswith(("## ", "* ")):
95 seen_structural_lines.add(dedupe_key)
96
97 normalized_lines.append(line)
98 previous_blank = False
99
100 return "\n".join(normalized_lines).strip() + "\n"