feat: add Phase F.2 - The Biographer (memory agent)
Add The Biographer household member for user memory management: Memory Service (direct access layer): - src/core/memory_service.py for fast, LLM-free lookups - Profile, preference, and fact management - Session context with Redis caching - Steward integration via prefetch_context() The Biographer Agent: - src/agents/biographer/ package with PydanticAI agent - Discreet chronicler personality for privacy - Tools: recall_semantic, list_memories, store_insight, update_profile, update_preference, forget_memory - Registered with Household Registry on startup Steward Integration: - Memory context pre-fetch during analysis - Profile/preferences included in Butler note - Keyword-based context determination Also includes: - delegate_to_biographer() wrapper - 34 new tests (capability + memory service) - Version bump to 1.2.0 Documentation cleanup: - Removed obsolete PHASE2_COMPLETE.md, PHASE2_PLAN.md - Removed docs/library-desk-requirements.md - Moved ORCHESTRATION_SCENARIOS.md to project root 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -146,7 +146,84 @@ async def delegate_to_librarian(
|
||||
)
|
||||
|
||||
|
||||
async def delegate_to_biographer(
|
||||
task: str,
|
||||
context: str = "",
|
||||
) -> DelegationResult:
|
||||
"""
|
||||
Delegate a memory task to The Biographer.
|
||||
|
||||
The Biographer handles:
|
||||
- Semantic recall ("What car do I drive?", "What's my job?")
|
||||
- Recording new facts from conversation
|
||||
- Profile updates (name, location, timezone)
|
||||
- Preference updates (units, theme)
|
||||
- Memory management (forget, list)
|
||||
|
||||
For direct key-based lookups (get location, get timezone), use
|
||||
memory_service directly - it's faster and doesn't require LLM.
|
||||
|
||||
Args:
|
||||
task: Clear description of what needs to be done.
|
||||
Include the action verb (recall, remember, forget, etc.)
|
||||
Example: "What car do I drive?"
|
||||
Example: "Remember that I work at Acme Corp"
|
||||
context: Additional context from the user's request or
|
||||
conversation history
|
||||
|
||||
Returns:
|
||||
DelegationResult with The Biographer's response
|
||||
|
||||
Example:
|
||||
>>> result = await delegate_to_biographer(
|
||||
... task="What do you know about my preferences?",
|
||||
... context="User is asking about stored information",
|
||||
... )
|
||||
>>> if result.success:
|
||||
... print(result.output)
|
||||
"""
|
||||
from src.agents.biographer.agent import run_biographer
|
||||
|
||||
logger.info(
|
||||
"delegation_to_biographer_started",
|
||||
task=task[:100],
|
||||
has_context=bool(context),
|
||||
)
|
||||
|
||||
try:
|
||||
# Use run() not run_stream() - avoids Ollama bug
|
||||
output = await run_biographer(task=task, context=context)
|
||||
|
||||
logger.info(
|
||||
"delegation_to_biographer_completed",
|
||||
task=task[:50],
|
||||
output_length=len(output),
|
||||
)
|
||||
|
||||
return DelegationResult(
|
||||
expert_name="biographer",
|
||||
task=task,
|
||||
success=True,
|
||||
output=output,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"delegation_to_biographer_error",
|
||||
task=task[:50],
|
||||
error=str(e),
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
return DelegationResult(
|
||||
expert_name="biographer",
|
||||
task=task,
|
||||
success=False,
|
||||
output="",
|
||||
error=str(e),
|
||||
)
|
||||
|
||||
|
||||
# Future expert delegation wrappers will be added here:
|
||||
# - delegate_to_memory(task, context) -> DelegationResult
|
||||
# - delegate_to_home_automation(task, context) -> DelegationResult
|
||||
# - delegate_to_developer(task, context) -> DelegationResult
|
||||
|
||||
Reference in New Issue
Block a user