summaryrefslogtreecommitdiff
path: root/personal_agent
diff options
context:
space:
mode:
Diffstat (limited to 'personal_agent')
-rw-r--r--personal_agent/agent.py23
-rw-r--r--personal_agent/database/migrations/001_create_memories.sql3
-rw-r--r--personal_agent/llm.py7
-rw-r--r--personal_agent/memory/models.py13
-rw-r--r--personal_agent/memory/store.py23
-rw-r--r--personal_agent/tools/memory.py22
6 files changed, 76 insertions, 15 deletions
diff --git a/personal_agent/agent.py b/personal_agent/agent.py
index 8efe949..1f51c18 100644
--- a/personal_agent/agent.py
+++ b/personal_agent/agent.py
@@ -1,4 +1,5 @@
import json
+import logging
from personal_agent.context import ContextBuilder
from personal_agent.identity import AgentIdentity, UserProfile
@@ -18,6 +19,8 @@ from personal_agent.tools import (
ToolRegistry,
)
+logger = logging.getLogger(__name__)
+
class Agent:
def __init__(
@@ -49,9 +52,10 @@ class Agent:
self.tools.register(LongTermMemoryDeleteTool(self.long_term_memory_store))
self.messages: list[dict[str, object]] = []
+ logger.info("Agent initialized")
def chat(self, user_input: str) -> str:
- print(f"\n[memory: {self.working_memory}]")
+ logger.info("User message received")
self.messages.append(
{
"role": "user",
@@ -71,7 +75,15 @@ class Agent:
)
if response.tool_calls:
- print(f"\n[tool call: {response.tool_calls}]\n")
+ for call in response.tool_calls:
+ if call.name == "long_term_memory_save":
+ logger.info(
+ "Memory save requested: category=%s, importance=%s",
+ call.arguments.get("category"),
+ call.arguments.get("importance"),
+ )
+ else:
+ logger.info("Tool call requested: %s", call.name)
if not response.tool_calls:
answer = response.content or ""
@@ -111,8 +123,10 @@ class Agent:
else:
try:
result = tool.execute(call.arguments).content
+ logger.info("Tool execution completed: %s", call.name)
except ToolError as error:
result = f"Tool error: {error}"
+ logger.info("Tool execution failed: %s", call.name)
self.messages.append(
{
@@ -125,15 +139,20 @@ class Agent:
def end_task(self) -> None:
self.working_memory.end_task()
+ logger.info("Task ended")
def start_task(self, objective: str) -> None:
self.working_memory.start_task(objective)
+ logger.info("Task started")
def pause_task(self) -> None:
self.working_memory.pause_task()
+ logger.info("Task paused")
def resume_task(self) -> None:
self.working_memory.resume_task()
+ logger.info("Task resumed")
def complete_task(self) -> None:
self.working_memory.complete_task()
+ logger.info("Taks completed")
diff --git a/personal_agent/database/migrations/001_create_memories.sql b/personal_agent/database/migrations/001_create_memories.sql
index e79c907..066fcf4 100644
--- a/personal_agent/database/migrations/001_create_memories.sql
+++ b/personal_agent/database/migrations/001_create_memories.sql
@@ -2,5 +2,6 @@ CREATE TABLE IF NOT EXISTS memories (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
category TEXT NOT NULL,
- created_at TEXT NOT NULL
+ created_at TEXT NOT NULL,
+ importance INTEGER NOT NULL DEFAULT 2
);
diff --git a/personal_agent/llm.py b/personal_agent/llm.py
index cd35676..4a0274a 100644
--- a/personal_agent/llm.py
+++ b/personal_agent/llm.py
@@ -39,6 +39,7 @@ class LLM:
if tools is not None:
payload["tools"] = tools
+ logger.info("LLM request started")
response = requests.post(
self.url,
json=payload, # type: ignore[arg-type]
@@ -65,6 +66,12 @@ class LLM:
)
)
+ logger.info(
+ "LLM response received: tool_calls=%d, content_present=%s",
+ len(tool_calls),
+ content is not None,
+ )
+
return LLMResponse(
content=content,
tool_calls=tool_calls,
diff --git a/personal_agent/memory/models.py b/personal_agent/memory/models.py
index aab2064..957f16e 100644
--- a/personal_agent/memory/models.py
+++ b/personal_agent/memory/models.py
@@ -15,11 +15,20 @@ class LongTermMemory:
content: str
category: MemoryCategory
created_at: datetime
+ importance: int
@classmethod
- def create(cls, content: str, category: MemoryCategory) -> LongTermMemory:
+ def create(
+ cls, content: str, category: MemoryCategory, importance: int = 2
+ ) -> LongTermMemory:
+ if importance not in (1, 2, 3):
+ raise ValueError("importance must be between 1 and 3")
return cls(
- id=uuid7(), content=content, category=category, created_at=datetime.now(UTC)
+ id=uuid7(),
+ content=content,
+ category=category,
+ created_at=datetime.now(UTC),
+ importance=importance,
)
diff --git a/personal_agent/memory/store.py b/personal_agent/memory/store.py
index 164d11f..5666a73 100644
--- a/personal_agent/memory/store.py
+++ b/personal_agent/memory/store.py
@@ -15,10 +15,16 @@ class LongTermMemoryStore:
with self.database.connect() as connection:
connection.execute(
"""
- INSERT INTO memories (id, content, category, created_at)
- VALUES (?, ?, ?, ?)
+ INSERT INTO memories (id, content, category, created_at, importance)
+ VALUES (?, ?, ?, ?, ?)
""",
- (str(memory.id), memory.content, memory.category.value, created_at),
+ (
+ str(memory.id),
+ memory.content,
+ memory.category.value,
+ created_at,
+ memory.importance,
+ ),
)
connection.execute(
@@ -35,7 +41,7 @@ class LongTermMemoryStore:
with self.database.connect() as connection:
row = connection.execute(
"""
- SELECT id, content, category, created_at
+ SELECT id, content, category, created_at, importance
FROM memories
WHERE id = ?
""",
@@ -51,7 +57,7 @@ class LongTermMemoryStore:
with self.database.connect() as connection:
rows = connection.execute(
"""
- SELECT id, content, category, created_at
+ SELECT id, content, category, created_at, importance
FROM memories
ORDER BY id
"""
@@ -96,7 +102,7 @@ class LongTermMemoryStore:
)
sql = """
- SELECT m.id, m.content, m.category, m.created_at
+ SELECT m.id, m.content, m.category, m.created_at, m.importance
FROM memories_fts as f
JOIN memories AS m ON m.rowid = f.rowid
WHERE memories_fts MATCH ?
@@ -116,12 +122,13 @@ class LongTermMemoryStore:
return [self._from_row(row) for row in rows]
@staticmethod
- def _from_row(row: tuple[str, str, str, str]) -> LongTermMemory:
- memory_id, content, category, created_at = row
+ def _from_row(row: tuple[str, str, str, str, int]) -> LongTermMemory:
+ memory_id, content, category, created_at, importance = row
return LongTermMemory(
id=UUID(memory_id),
content=content,
category=MemoryCategory(category),
created_at=datetime.fromisoformat(created_at),
+ importance=importance,
)
diff --git a/personal_agent/tools/memory.py b/personal_agent/tools/memory.py
index c84202f..ff91234 100644
--- a/personal_agent/tools/memory.py
+++ b/personal_agent/tools/memory.py
@@ -252,13 +252,25 @@ class LongTermMemorySaveTool(Tool):
"episodic for meaningful past events."
),
},
+ "importance": {
+ "type": "integer",
+ "enum": [1, 2, 3],
+ "description": (
+ "How useful this memory is likely to be in future "
+ "conversations: 1 = useful but minor, "
+ "2 = normally useful, "
+ "3 = especially important for future behavior. "
+ "Importance measure future usefullness, not emotional intensity."
+ ),
+ },
},
- "required": ["content", "category"],
+ "required": ["content", "category", "importance"],
}
def execute(self, arguments: dict[str, object]) -> ToolResult:
content = arguments.get("content")
category = arguments.get("category")
+ importance = arguments.get("importance")
if not isinstance(content, str):
raise ToolError("content must be a string")
@@ -269,12 +281,18 @@ class LongTermMemorySaveTool(Tool):
if not isinstance(category, str):
raise ToolError("category must be a string")
+ if not isinstance(importance, int) or isinstance(importance, bool):
+ raise ToolError("importance must be an integer")
+
+ if importance not in (1, 2, 3):
+ raise ToolError("importance must be between 1 and 3")
+
try:
memory_category = MemoryCategory(category)
except ValueError:
raise ToolError("category must be 'semantic' or 'episodic'")
- memory = LongTermMemory.create(content, memory_category)
+ memory = LongTermMemory.create(content, memory_category, importance)
self.store.add(memory)
return ToolResult(content=f"Saved memory: {memory.id}")