forked from Rockachopa/Timmy-time-dashboard
fix: Timmy startup crashes and clean initialization
- Remove show_tool_calls kwarg (not in Agno 2.5.3), which crashed Agent.__init__ - Guard memory_search against top_k=None from model, return formatted string - Skip Telegram/Discord startup silently when no token configured - Replace placeholder MEMORY.md with proper structured hot memory document Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
72
MEMORY.md
72
MEMORY.md
@@ -1 +1,71 @@
|
|||||||
Good morning, I hope you had a great night.
|
# Timmy Hot Memory
|
||||||
|
|
||||||
|
> Working RAM — always loaded, ~300 lines max, pruned monthly
|
||||||
|
> Last updated: 2026-02-26
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Status
|
||||||
|
|
||||||
|
**Agent State:** Operational
|
||||||
|
**Mode:** Development
|
||||||
|
**Model:** llama3.2 (local via Ollama)
|
||||||
|
**Backend:** Ollama on localhost:11434
|
||||||
|
**Dashboard:** http://localhost:8000
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Standing Rules
|
||||||
|
|
||||||
|
1. **Sovereignty First** — No cloud AI dependencies
|
||||||
|
2. **Local-Only Inference** — Ollama on localhost
|
||||||
|
3. **Privacy by Design** — Telemetry disabled
|
||||||
|
4. **Tool Minimalism** — Use tools only when necessary
|
||||||
|
5. **Memory Discipline** — Write handoffs at session end
|
||||||
|
6. **Clean Output** — Never show JSON, tool calls, or function syntax
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Architecture
|
||||||
|
|
||||||
|
**Memory Tiers:**
|
||||||
|
- Tier 1 (Hot): This file (MEMORY.md) — always in context
|
||||||
|
- Tier 2 (Vault): memory/ directory — notes, profiles, AARs
|
||||||
|
- Tier 3 (Semantic): Vector search over vault content
|
||||||
|
|
||||||
|
**Swarm Agents:** Echo (research), Forge (code), Seer (data)
|
||||||
|
**Dashboard Pages:** Briefing, Swarm, Spark, Market, Tools, Events, Ledger, Memory, Router, Upgrades, Creative
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Agent Roster
|
||||||
|
|
||||||
|
| Agent | Role | Status |
|
||||||
|
|-------|------|--------|
|
||||||
|
| Timmy | Core AI | Active |
|
||||||
|
| Echo | Research & Summarization | Active |
|
||||||
|
| Forge | Coding & Debugging | Active |
|
||||||
|
| Seer | Analytics & Prediction | Active |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## User Profile
|
||||||
|
|
||||||
|
**Name:** (not set)
|
||||||
|
**Interests:** (to be learned)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
|
||||||
|
(none yet)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pending Actions
|
||||||
|
|
||||||
|
- [ ] Learn user's name and preferences
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Prune date: 2026-03-25*
|
||||||
|
|||||||
@@ -121,15 +121,21 @@ async def lifespan(app: FastAPI):
|
|||||||
if spark_engine.enabled:
|
if spark_engine.enabled:
|
||||||
logger.info("Spark Intelligence active — event capture enabled")
|
logger.info("Spark Intelligence active — event capture enabled")
|
||||||
|
|
||||||
# Auto-start Telegram bot if a token is configured
|
# Auto-start chat integrations (skip silently if unconfigured)
|
||||||
from telegram_bot.bot import telegram_bot
|
from telegram_bot.bot import telegram_bot
|
||||||
await telegram_bot.start()
|
|
||||||
|
|
||||||
# Auto-start Discord bot and register in platform registry
|
|
||||||
from chat_bridge.vendors.discord import discord_bot
|
from chat_bridge.vendors.discord import discord_bot
|
||||||
from chat_bridge.registry import platform_registry
|
from chat_bridge.registry import platform_registry
|
||||||
platform_registry.register(discord_bot)
|
platform_registry.register(discord_bot)
|
||||||
await discord_bot.start()
|
|
||||||
|
if settings.telegram_token:
|
||||||
|
await telegram_bot.start()
|
||||||
|
else:
|
||||||
|
logger.debug("Telegram: no token configured, skipping")
|
||||||
|
|
||||||
|
if settings.discord_token or discord_bot.load_token():
|
||||||
|
await discord_bot.start()
|
||||||
|
else:
|
||||||
|
logger.debug("Discord: no token configured, skipping")
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ def create_timmy(
|
|||||||
num_history_runs=20,
|
num_history_runs=20,
|
||||||
markdown=True,
|
markdown=True,
|
||||||
tools=[tools] if tools else None,
|
tools=[tools] if tools else None,
|
||||||
show_tool_calls=False,
|
|
||||||
telemetry=settings.telemetry_enabled,
|
telemetry=settings.telemetry_enabled,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,25 @@ semantic_memory = SemanticMemory()
|
|||||||
memory_searcher = MemorySearcher()
|
memory_searcher = MemorySearcher()
|
||||||
|
|
||||||
|
|
||||||
def memory_search(query: str, top_k: int = 5) -> list[tuple[str, float]]:
|
def memory_search(query: str, top_k: int = 5) -> str:
|
||||||
"""Simple interface for memory search."""
|
"""Search past conversations and notes for relevant context.
|
||||||
return semantic_memory.search(query, top_k)
|
|
||||||
|
Args:
|
||||||
|
query: What to search for (e.g. "Bitcoin strategy", "server setup").
|
||||||
|
top_k: Number of results to return (default 5).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Formatted string of relevant memory results.
|
||||||
|
"""
|
||||||
|
# Guard: model sometimes passes None for top_k
|
||||||
|
if top_k is None:
|
||||||
|
top_k = 5
|
||||||
|
results = semantic_memory.search(query, top_k)
|
||||||
|
if not results:
|
||||||
|
return "No relevant memories found."
|
||||||
|
parts = []
|
||||||
|
for content, score in results:
|
||||||
|
if score < 0.2:
|
||||||
|
continue
|
||||||
|
parts.append(f"[score {score:.2f}] {content[:300]}")
|
||||||
|
return "\n\n".join(parts) if parts else "No relevant memories found."
|
||||||
|
|||||||
@@ -267,8 +267,8 @@ def test_create_timmy_includes_tools_for_large_model():
|
|||||||
assert kwargs["tools"] == [mock_toolkit]
|
assert kwargs["tools"] == [mock_toolkit]
|
||||||
|
|
||||||
|
|
||||||
def test_create_timmy_show_tool_calls_false():
|
def test_create_timmy_no_show_tool_calls():
|
||||||
"""show_tool_calls should always be False to prevent raw JSON in output."""
|
"""show_tool_calls must NOT be passed — Agno 2.5.3 doesn't support it."""
|
||||||
with patch("timmy.agent.Agent") as MockAgent, \
|
with patch("timmy.agent.Agent") as MockAgent, \
|
||||||
patch("timmy.agent.Ollama"), \
|
patch("timmy.agent.Ollama"), \
|
||||||
patch("timmy.agent.SqliteDb"):
|
patch("timmy.agent.SqliteDb"):
|
||||||
@@ -277,4 +277,4 @@ def test_create_timmy_show_tool_calls_false():
|
|||||||
create_timmy()
|
create_timmy()
|
||||||
|
|
||||||
kwargs = MockAgent.call_args.kwargs
|
kwargs = MockAgent.call_args.kwargs
|
||||||
assert kwargs["show_tool_calls"] is False
|
assert "show_tool_calls" not in kwargs
|
||||||
|
|||||||
Reference in New Issue
Block a user