Add initial work log.

This commit is contained in:
user 2024-12-23 11:36:28 -05:00
parent 243cd55615
commit 87ec7c0268
2 changed files with 127 additions and 9 deletions

View File

@ -1,4 +1,8 @@
from typing import Dict, List, Any, Union, TypedDict, Optional, Sequence, Set
from typing import Dict, List, Any, Union, TypedDict, Optional, Sequence, Set, TypeVar, Literal
class WorkLogEntry(TypedDict):
timestamp: str
event: str
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
@ -15,7 +19,7 @@ class SnippetInfo(TypedDict):
console = Console()
# Global memory store
_global_memory: Dict[str, Union[List[Any], Dict[int, str], Dict[int, SnippetInfo], int, Set[str], bool, str, int]] = {
_global_memory: Dict[str, Union[List[Any], Dict[int, str], Dict[int, SnippetInfo], int, Set[str], bool, str, int, List[WorkLogEntry]]] = {
'research_notes': [],
'plans': [],
'tasks': {}, # Dict[int, str] - ID to task mapping
@ -30,7 +34,8 @@ _global_memory: Dict[str, Union[List[Any], Dict[int, str], Dict[int, SnippetInfo
'related_files': {}, # Dict[int, str] - ID to filepath mapping
'related_file_id_counter': 1, # Counter for generating unique file IDs
'plan_completed': False,
'research_depth': 0
'research_depth': 0,
'work_log': [] # List[WorkLogEntry] - Timestamped work events
}
@tool("emit_research_notes")
@ -59,6 +64,7 @@ def emit_plan(plan: str) -> str:
"""
_global_memory['plans'].append(plan)
console.print(Panel(Markdown(plan), title="📋 Plan"))
log_work_event(f"Added plan step: {plan}")
return plan
@tool("emit_task")
@ -79,6 +85,7 @@ def emit_task(task: str) -> str:
_global_memory['tasks'][task_id] = task
console.print(Panel(Markdown(task), title=f"✅ Task #{task_id}"))
log_work_event(f"Task #{task_id} added: {task}")
return f"Task #{task_id} stored."
@ -107,7 +114,8 @@ def emit_key_facts(facts: List[str]) -> str:
# Add result message
results.append(f"Stored fact #{fact_id}: {fact}")
log_work_event(f"Stored {len(facts)} key facts")
return "Facts stored."
@ -130,7 +138,8 @@ def delete_key_facts(fact_ids: List[int]) -> str:
success_msg = f"Successfully deleted fact #{fact_id}: {deleted_fact}"
console.print(Panel(Markdown(success_msg), title="Fact Deleted", border_style="green"))
results.append(success_msg)
log_work_event(f"Deleted facts {fact_ids}")
return "Facts deleted."
@tool("delete_tasks")
@ -154,7 +163,8 @@ def delete_tasks(task_ids: List[int]) -> str:
title="Task Deleted",
border_style="green"))
results.append(success_msg)
log_work_event(f"Deleted tasks {task_ids}")
return "Tasks deleted."
@tool("request_implementation")
@ -172,6 +182,7 @@ def request_implementation() -> str:
"""
_global_memory['implementation_requested'] = True
console.print(Panel("🚀 Implementation Requested", style="yellow", padding=0))
log_work_event("Implementation requested")
return ""
@ -223,7 +234,8 @@ def emit_key_snippets(snippets: List[SnippetInfo]) -> str:
border_style="bright_cyan"))
results.append(f"Stored snippet #{snippet_id}")
log_work_event(f"Stored {len(snippets)} code snippets")
return "Snippets stored."
@tool("delete_key_snippets")
@ -247,7 +259,8 @@ def delete_key_snippets(snippet_ids: List[int]) -> str:
title="Snippet Deleted",
border_style="green"))
results.append(success_msg)
log_work_event(f"Deleted snippets {snippet_ids}")
return "Snippets deleted."
@tool("swap_task_order")
@ -297,6 +310,7 @@ def one_shot_completed(message: str) -> str:
_global_memory['task_completed'] = True
_global_memory['completion_message'] = message
console.print(Panel(Markdown(message), title="✅ Task Completed"))
log_work_event(f"Task completed: {message}")
return "Completion noted."
@tool("task_completed")
@ -327,6 +341,7 @@ def plan_implementation_completed(message: str) -> str:
_global_memory['plan_completed'] = True
_global_memory['completion_message'] = message
console.print(Panel(Markdown(message), title="✅ Plan Executed"))
log_work_event(f"Plan execution completed: {message}")
return "Plan completion noted."
def get_related_files() -> List[str]:
@ -384,6 +399,50 @@ def emit_related_files(files: List[str]) -> str:
return '\n'.join(results)
@tool("log_work_event")
def log_work_event(event: str) -> str:
"""Add timestamped entry to work log.
Args:
event: Description of the event
Returns:
Confirmation message
"""
from datetime import datetime
entry = WorkLogEntry(
timestamp=datetime.now().isoformat(),
event=event
)
_global_memory['work_log'].append(entry)
return f"Event logged: {event}"
def get_work_log() -> str:
"""Return formatted markdown table of work log entries.
Returns:
Formatted markdown table with timestamps and events
"""
if not _global_memory['work_log']:
return "No work log entries"
header = "| Timestamp | Event |\n|-----------|--------|"
rows = [f"| {entry['timestamp']} | {entry['event']} |"
for entry in _global_memory['work_log']]
return header + "\n".join(rows)
def reset_work_log() -> str:
"""Clear the work log.
Returns:
Confirmation message
"""
_global_memory['work_log'].clear()
return "Work log cleared"
@tool("deregister_related_files")
def deregister_related_files(file_ids: List[int]) -> str:
"""Delete multiple related files from global memory by their IDs.

View File

@ -11,7 +11,9 @@ from ra_aid.tools.memory import (
deregister_related_files,
emit_task,
delete_tasks,
swap_task_order
swap_task_order,
log_work_event,
reset_work_log
)
@pytest.fixture
@ -28,6 +30,7 @@ def reset_memory():
_global_memory['related_file_id_counter'] = 0
_global_memory['tasks'] = {}
_global_memory['task_id_counter'] = 0
_global_memory['work_log'] = []
yield
# Clean up after test
_global_memory['key_facts'] = {}
@ -40,6 +43,7 @@ def reset_memory():
_global_memory['related_file_id_counter'] = 0
_global_memory['tasks'] = {}
_global_memory['task_id_counter'] = 0
_global_memory['work_log'] = []
def test_emit_key_facts_single_fact(reset_memory):
"""Test emitting a single key fact using emit_key_facts"""
@ -97,6 +101,61 @@ def test_get_memory_value_other_types(reset_memory):
# Test with non-existent key
assert get_memory_value('nonexistent') == ""
def test_log_work_event(reset_memory):
"""Test logging work events with timestamps"""
# Log some events
log_work_event("Started task")
log_work_event("Made progress")
log_work_event("Completed task")
# Verify events are stored
assert len(_global_memory['work_log']) == 3
# Check event structure
event = _global_memory['work_log'][0]
assert isinstance(event['timestamp'], str)
assert event['event'] == "Started task"
# Verify order
assert _global_memory['work_log'][1]['event'] == "Made progress"
assert _global_memory['work_log'][2]['event'] == "Completed task"
def test_get_work_log(reset_memory):
"""Test work log formatting in markdown"""
# Add some events
log_work_event("First event")
log_work_event("Second event")
# Get formatted log
log = get_memory_value('work_log')
# Verify events and timestamps exist
for event in _global_memory['work_log']:
assert isinstance(event['timestamp'], str)
assert isinstance(event['event'], str)
# Verify events in chronological order
assert _global_memory['work_log'][0]['event'] == "First event"
assert _global_memory['work_log'][1]['event'] == "Second event"
def test_reset_work_log(reset_memory):
"""Test resetting the work log"""
# Add some events
log_work_event("Test event")
assert len(_global_memory['work_log']) == 1
# Reset log
reset_work_log()
# Verify log is empty
assert len(_global_memory['work_log']) == 0
assert get_memory_value('work_log') == ""
def test_empty_work_log(reset_memory):
"""Test empty work log behavior"""
# Fresh work log should return empty string
assert get_memory_value('work_log') == ""
def test_emit_key_facts(reset_memory):
"""Test emitting multiple key facts at once"""
# Test emitting multiple facts