summaryrefslogtreecommitdiff
path: root/personal_agent/agent.py
diff options
context:
space:
mode:
Diffstat (limited to 'personal_agent/agent.py')
-rw-r--r--personal_agent/agent.py128
1 files changed, 128 insertions, 0 deletions
diff --git a/personal_agent/agent.py b/personal_agent/agent.py
new file mode 100644
index 0000000..73cc422
--- /dev/null
+++ b/personal_agent/agent.py
@@ -0,0 +1,128 @@
+import json
+
+from personal_agent.context import ContextBuilder
+from personal_agent.identity import AgentIdentity, UserProfile
+from personal_agent.llm import LLM
+from personal_agent.memory.models import WorkingMemory
+from personal_agent.tools import (
+ MemoryAddFactTool,
+ MemoryAddNoteTool,
+ MemoryRemoveFactTool,
+ MemoryRemoveNoteTool,
+ TaskStartTool,
+ ToolError,
+ ToolRegistry,
+)
+
+
+class Agent:
+ def __init__(
+ self,
+ llm: LLM,
+ agent_identity: AgentIdentity,
+ user_profile: UserProfile,
+ tools: ToolRegistry,
+ ) -> None:
+ self.llm = llm
+ self.tools = tools
+
+ self.context = ContextBuilder(
+ agent_identity,
+ user_profile,
+ )
+
+ self.working_memory = WorkingMemory()
+
+ self.tools.register(MemoryAddFactTool(self.working_memory))
+ self.tools.register(MemoryRemoveFactTool(self.working_memory))
+ self.tools.register(MemoryRemoveNoteTool(self.working_memory))
+ self.tools.register(MemoryAddNoteTool(self.working_memory))
+ self.tools.register(TaskStartTool(self.working_memory))
+
+ self.messages: list[dict[str, object]] = []
+
+ def chat(self, user_input: str) -> str:
+ print(f"\n[memory: {self.working_memory}]")
+ self.messages.append(
+ {
+ "role": "user",
+ "content": user_input,
+ }
+ )
+
+ for _ in range(5):
+ response = self.llm.chat(
+ self.context.build_messages(
+ self.messages,
+ self.working_memory,
+ ),
+ tools=self.tools.schemas(),
+ )
+
+ if response.tool_calls:
+ print(f"\n[tool call: {response.tool_calls}]\n")
+
+ if not response.tool_calls:
+ answer = response.content or ""
+
+ self.messages.append(
+ {
+ "role": "assistant",
+ "content": answer,
+ }
+ )
+
+ return answer
+
+ self.messages.append(
+ {
+ "role": "assistant",
+ "content": response.content,
+ "tool_calls": [
+ {
+ "id": call.id,
+ "type": "function",
+ "function": {
+ "name": call.name,
+ "arguments": json.dumps(call.arguments),
+ },
+ }
+ for call in response.tool_calls
+ ],
+ }
+ )
+
+ for call in response.tool_calls:
+ tool = self.tools.get(call.name)
+
+ if tool is None:
+ result = f"Unknown tool: {call.name}"
+ else:
+ try:
+ result = tool.execute(call.arguments).content
+ except ToolError as error:
+ result = f"Tool error: {error}"
+
+ self.messages.append(
+ {
+ "role": "tool",
+ "tool_call_id": call.id,
+ "content": result,
+ }
+ )
+ raise RuntimeError("Tool call limit exceeded")
+
+ def end_task(self) -> None:
+ self.working_memory.end_task()
+
+ def start_task(self, objective: str) -> None:
+ self.working_memory.start_task(objective)
+
+ def pause_task(self) -> None:
+ self.working_memory.pause_task()
+
+ def resume_task(self) -> None:
+ self.working_memory.resume_task()
+
+ def complete_task(self) -> None:
+ self.working_memory.complete_task()