2026-02-28 11:07:19 -05:00
|
|
|
"""Optimized dashboard app with improved async handling and non-blocking startup.
|
|
|
|
|
|
|
|
|
|
Key improvements:
|
|
|
|
|
1. Background tasks use asyncio.create_task() to avoid blocking startup
|
|
|
|
|
2. Persona spawning is moved to a background task
|
|
|
|
|
3. MCP bootstrap is non-blocking
|
|
|
|
|
4. Chat integrations start in background
|
|
|
|
|
5. All startup operations complete quickly
|
|
|
|
|
"""
|
|
|
|
|
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
import asyncio
|
2026-02-19 19:31:48 +00:00
|
|
|
import logging
|
feat: swarm E2E, MCP tools, timmy-serve L402, tests, notifications
Major Features:
- Auto-spawn persona agents (Echo, Forge, Seer) on app startup
- WebSocket broadcasts for real-time swarm UI updates
- MCP tool integration: web search, file I/O, shell, Python execution
- New /tools dashboard page showing agent capabilities
- Real timmy-serve start with L402 payment gating middleware
- Browser push notifications for briefings and task events
Tests:
- test_docker_agent.py: 9 tests for Docker agent runner
- test_swarm_integration_full.py: 18 E2E lifecycle tests
- Fixed all pytest warnings (436 tests, 0 warnings)
Improvements:
- Fixed coroutine warnings in coordinator broadcasts
- Fixed ResourceWarning for unclosed process pipes
- Added pytest-asyncio config to pyproject.toml
- Test isolation with proper event loop cleanup
2026-02-22 19:01:04 -05:00
|
|
|
import os
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
from contextlib import asynccontextmanager
|
2026-02-19 19:05:01 +00:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
2026-02-28 12:18:18 -05:00
|
|
|
from fastapi import FastAPI, Request, WebSocket
|
feat: replace GitHub page with embedded Timmy chat interface
Replaces the marketing landing page with a minimal, full-screen chat
interface that connects to a running Timmy instance. Mobile-first design
with single vertical scroll direction, looping scroll, no zoom, no
buttons — just type and press Enter to talk to Timmy.
- docs/index.html: full rewrite as a clean chat UI with dark terminal
theme, looping infinite scroll, markdown rendering, connection status,
and /connect, /clear, /help slash commands
- src/dashboard/app.py: add CORS middleware so the GitHub Pages site can
reach a local Timmy server cross-origin
- src/config.py: add cors_origins setting (defaults to ["*"])
https://claude.ai/code/session_01AWLxg6KDWsfCATiuvsRMGr
2026-02-27 00:35:33 +00:00
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
2026-02-19 19:05:01 +00:00
|
|
|
from fastapi.responses import HTMLResponse
|
|
|
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
|
from fastapi.templating import Jinja2Templates
|
|
|
|
|
|
2026-02-19 19:31:48 +00:00
|
|
|
from config import settings
|
2026-02-19 19:05:01 +00:00
|
|
|
from dashboard.routes.agents import router as agents_router
|
|
|
|
|
from dashboard.routes.health import router as health_router
|
feat: Mission Control v2 — swarm, L402, voice, marketplace, React dashboard
Major expansion of the Timmy Time Dashboard:
Backend modules:
- Swarm subsystem: registry, manager, bidder, coordinator, agent_runner, swarm_node, tasks, comms
- L402/Lightning: payment_handler, l402_proxy with HMAC macaroons
- Voice NLU: regex-based intent detection (chat, status, swarm, task, help, voice)
- Notifications: push notifier for swarm events
- Shortcuts: Siri Shortcuts iOS integration endpoints
- WebSocket: live dashboard event manager
- Inter-agent: agent-to-agent messaging layer
Dashboard routes:
- /swarm/* — swarm management and agent registry
- /marketplace — agent catalog with sat pricing
- /voice/* — voice command processing
- /mobile — mobile status endpoint
- /swarm/live — WebSocket live feed
React web dashboard (dashboard-web/):
- Sovereign Terminal design — dark theme with Bitcoin orange accents
- Three-column layout: status sidebar, workspace tabs, context panel
- Chat, Swarm, Tasks, Marketplace tab views
- JetBrains Mono typography, terminal aesthetic
- Framer Motion animations throughout
Tests: 228 passing (expanded from 93)
Includes Kimi's additional templates and QA work.
2026-02-21 12:57:38 -05:00
|
|
|
from dashboard.routes.swarm import router as swarm_router
|
2026-02-26 21:30:39 +00:00
|
|
|
from dashboard.routes.swarm import internal_router as swarm_internal_router
|
feat: Mission Control v2 — swarm, L402, voice, marketplace, React dashboard
Major expansion of the Timmy Time Dashboard:
Backend modules:
- Swarm subsystem: registry, manager, bidder, coordinator, agent_runner, swarm_node, tasks, comms
- L402/Lightning: payment_handler, l402_proxy with HMAC macaroons
- Voice NLU: regex-based intent detection (chat, status, swarm, task, help, voice)
- Notifications: push notifier for swarm events
- Shortcuts: Siri Shortcuts iOS integration endpoints
- WebSocket: live dashboard event manager
- Inter-agent: agent-to-agent messaging layer
Dashboard routes:
- /swarm/* — swarm management and agent registry
- /marketplace — agent catalog with sat pricing
- /voice/* — voice command processing
- /mobile — mobile status endpoint
- /swarm/live — WebSocket live feed
React web dashboard (dashboard-web/):
- Sovereign Terminal design — dark theme with Bitcoin orange accents
- Three-column layout: status sidebar, workspace tabs, context panel
- Chat, Swarm, Tasks, Marketplace tab views
- JetBrains Mono typography, terminal aesthetic
- Framer Motion animations throughout
Tests: 228 passing (expanded from 93)
Includes Kimi's additional templates and QA work.
2026-02-21 12:57:38 -05:00
|
|
|
from dashboard.routes.marketplace import router as marketplace_router
|
|
|
|
|
from dashboard.routes.voice import router as voice_router
|
|
|
|
|
from dashboard.routes.mobile import router as mobile_router
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
from dashboard.routes.briefing import router as briefing_router
|
2026-02-22 17:16:12 +00:00
|
|
|
from dashboard.routes.telegram import router as telegram_router
|
feat: swarm E2E, MCP tools, timmy-serve L402, tests, notifications
Major Features:
- Auto-spawn persona agents (Echo, Forge, Seer) on app startup
- WebSocket broadcasts for real-time swarm UI updates
- MCP tool integration: web search, file I/O, shell, Python execution
- New /tools dashboard page showing agent capabilities
- Real timmy-serve start with L402 payment gating middleware
- Browser push notifications for briefings and task events
Tests:
- test_docker_agent.py: 9 tests for Docker agent runner
- test_swarm_integration_full.py: 18 E2E lifecycle tests
- Fixed all pytest warnings (436 tests, 0 warnings)
Improvements:
- Fixed coroutine warnings in coordinator broadcasts
- Fixed ResourceWarning for unclosed process pipes
- Added pytest-asyncio config to pyproject.toml
- Test isolation with proper event loop cleanup
2026-02-22 19:01:04 -05:00
|
|
|
from dashboard.routes.tools import router as tools_router
|
feat: integrate Spark Intelligence into Timmy swarm system
Adds a self-evolving cognitive layer inspired by vibeship-spark-intelligence,
adapted for Timmy's agent architecture. Spark captures swarm events, runs
EIDOS prediction-evaluation loops, consolidates memories, and generates
advisory recommendations — all backed by SQLite consistent with existing
patterns.
New modules:
- spark/memory.py — event capture with importance scoring + memory consolidation
- spark/eidos.py — EIDOS cognitive loop (predict → observe → evaluate → learn)
- spark/advisor.py — ranked advisory generation from accumulated intelligence
- spark/engine.py — top-level API wiring all subsystems together
Dashboard:
- /spark/ui — full Spark Intelligence dashboard (3-column: status/advisories,
predictions/memories, event timeline) with HTMX auto-refresh
- /spark — JSON API for programmatic access
- SPARK link added to navigation header
Integration:
- Coordinator hooks emit Spark events on task post, bid, assign, complete, fail
- EIDOS predictions generated when tasks are posted, evaluated on completion
- Memory consolidation triggers when agents accumulate enough outcomes
- SPARK_ENABLED config toggle (default: true)
Tests: 47 new tests covering all Spark subsystems + dashboard routes.
Full suite: 538 tests passing.
https://claude.ai/code/session_01KJm6jQkNi3aA3yoQJn636c
2026-02-24 15:51:15 +00:00
|
|
|
from dashboard.routes.spark import router as spark_router
|
feat: add full creative studio + DevOps tools (Pixel, Lyra, Reel personas)
Adds 3 new personas (Pixel, Lyra, Reel) and 5 new tool modules:
- Git/DevOps tools (GitPython): clone, status, diff, log, blame, branch,
add, commit, push, pull, stash — wired to Forge and Helm personas
- Image generation (FLUX via diffusers): text-to-image, storyboards,
variations — Pixel persona
- Music generation (ACE-Step 1.5): full songs with vocals+instrumentals,
instrumental tracks, vocal-only tracks — Lyra persona
- Video generation (Wan 2.1 via diffusers): text-to-video, image-to-video
clips — Reel persona
- Creative Director pipeline: multi-step orchestration that chains
storyboard → music → video → assembly into 3+ minute final videos
- Video assembler (MoviePy + FFmpeg): stitch clips, overlay audio,
title cards, subtitles, final export
Also includes:
- Spark Intelligence tool-level + creative pipeline event capture
- Creative Studio dashboard page (/creative/ui) with 4 tabs
- Config settings for all new models and output directories
- pyproject.toml creative optional extra for GPU dependencies
- 107 new tests covering all modules (624 total, all passing)
https://claude.ai/code/session_01KJm6jQkNi3aA3yoQJn636c
2026-02-24 16:31:47 +00:00
|
|
|
from dashboard.routes.creative import router as creative_router
|
2026-02-25 01:11:14 +00:00
|
|
|
from dashboard.routes.discord import router as discord_router
|
feat: complete Event Log, Ledger, Memory, Cascade Router, Upgrade Queue, Activity Feed
This commit implements six major features:
1. Event Log System (src/swarm/event_log.py)
- SQLite-based audit trail for all swarm events
- Task lifecycle tracking (created, assigned, completed, failed)
- Agent lifecycle tracking (joined, left, status changes)
- Integrated with coordinator for automatic logging
- Dashboard page at /swarm/events
2. Lightning Ledger (src/lightning/ledger.py)
- Transaction tracking for Lightning Network payments
- Balance calculations (incoming, outgoing, net, available)
- Integrated with payment_handler for automatic logging
- Dashboard page at /lightning/ledger
3. Semantic Memory / Vector Store (src/memory/vector_store.py)
- Embedding-based similarity search for Echo agent
- Fallback to keyword matching if sentence-transformers unavailable
- Personal facts storage and retrieval
- Dashboard page at /memory
4. Cascade Router Integration (src/timmy/cascade_adapter.py)
- Automatic LLM failover between providers (Ollama → AirLLM → API)
- Circuit breaker pattern for failing providers
- Metrics tracking per provider (latency, error rates)
- Dashboard status page at /router/status
5. Self-Upgrade Approval Queue (src/upgrades/)
- State machine for self-modifications: proposed → approved/rejected → applied/failed
- Human approval required before applying changes
- Git integration for branch management
- Dashboard queue at /self-modify/queue
6. Real-Time Activity Feed (src/events/broadcaster.py)
- WebSocket-based live activity streaming
- Bridges event_log to dashboard clients
- Activity panel on /swarm/live
Tests:
- 101 unit tests passing
- 4 new E2E test files for Selenium testing
- Run with: SELENIUM_UI=1 pytest tests/functional/ -v --headed
Documentation:
- 6 ADRs (017-022) documenting architecture decisions
- Implementation summary in docs/IMPLEMENTATION_SUMMARY.md
- Architecture diagram in docs/architecture-v2.md
2026-02-26 08:01:01 -05:00
|
|
|
from dashboard.routes.events import router as events_router
|
|
|
|
|
from dashboard.routes.ledger import router as ledger_router
|
|
|
|
|
from dashboard.routes.memory import router as memory_router
|
|
|
|
|
from dashboard.routes.router import router as router_status_router
|
|
|
|
|
from dashboard.routes.upgrades import router as upgrades_router
|
2026-02-26 10:27:08 -05:00
|
|
|
from dashboard.routes.work_orders import router as work_orders_router
|
|
|
|
|
from dashboard.routes.tasks import router as tasks_router
|
2026-02-26 17:06:00 +00:00
|
|
|
from dashboard.routes.scripture import router as scripture_router
|
2026-02-26 12:19:27 -05:00
|
|
|
from dashboard.routes.self_coding import router as self_coding_router
|
2026-02-26 21:30:39 +00:00
|
|
|
from dashboard.routes.self_coding import self_modify_router
|
2026-02-26 12:46:48 -05:00
|
|
|
from dashboard.routes.hands import router as hands_router
|
feat: add Grok (xAI) as opt-in premium backend with monetization
- Add GrokBackend class in src/timmy/backends.py with full sync/async
support, health checks, usage stats, and cost estimation in sats
- Add consult_grok tool to Timmy's toolkit for proactive Grok queries
- Extend cascade router with Grok provider type for failover chain
- Add Grok Mode toggle card to Mission Control dashboard (HTMX live)
- Add "Ask Grok" button on chat input for direct Grok queries
- Add /grok/* routes: status, toggle, chat, stats endpoints
- Integrate Lightning invoice generation for Grok usage monetization
- Add GROK_ENABLED, XAI_API_KEY, GROK_DEFAULT_MODEL, GROK_MAX_SATS_PER_QUERY,
GROK_FREE config settings via pydantic-settings
- Update .env.example and docker-compose.yml with Grok env vars
- Add 21 tests covering backend, tools, and route endpoints (all green)
Local-first ethos preserved: Grok is premium augmentation only,
disabled by default, and Lightning-payable when enabled.
https://claude.ai/code/session_01FygwN8wS8J6WGZ8FPb7XGV
2026-02-27 01:12:51 +00:00
|
|
|
from dashboard.routes.grok import router as grok_router
|
feat: add custom weights, model registry, per-agent models, and reward scoring
Inspired by OpenClaw-RL's multi-model orchestration, this adds four
features for custom model management:
1. Custom model registry (infrastructure/models/registry.py) — SQLite-backed
registry for GGUF, safetensors, HF checkpoint, and Ollama models with
role-based lookups (general, reward, teacher, judge).
2. Per-agent model assignment — each swarm persona can use a different model
instead of sharing the global default. Resolved via registry assignment >
persona default > global default.
3. Runtime model management API (/api/v1/models) — REST endpoints to register,
list, assign, enable/disable, and remove custom models without restart.
Includes a dashboard page at /models.
4. Reward model scoring (PRM-style) — majority-vote quality evaluation of
agent outputs using a configurable reward model. Scores persist in SQLite
and feed into the swarm learner.
New config settings: custom_weights_dir, reward_model_enabled,
reward_model_name, reward_model_votes.
54 new tests covering registry CRUD, API endpoints, agent assignments,
role lookups, and reward scoring.
https://claude.ai/code/session_01V4iTozMwcE2gjfnCJdCugC
2026-02-27 01:08:03 +00:00
|
|
|
from dashboard.routes.models import router as models_router
|
|
|
|
|
from dashboard.routes.models import api_router as models_api_router
|
2026-02-26 23:58:53 -05:00
|
|
|
from dashboard.routes.chat_api import router as chat_api_router
|
2026-02-27 01:00:11 -05:00
|
|
|
from dashboard.routes.thinking import router as thinking_router
|
2026-02-27 19:51:37 -05:00
|
|
|
from dashboard.routes.bugs import router as bugs_router
|
2026-02-26 22:07:41 +00:00
|
|
|
from infrastructure.router.api import router as cascade_router
|
2026-02-19 19:05:01 +00:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
|
2026-02-27 19:51:37 -05:00
|
|
|
def _configure_logging() -> None:
|
|
|
|
|
"""Configure logging with console and optional rotating file handler."""
|
|
|
|
|
root_logger = logging.getLogger()
|
|
|
|
|
root_logger.setLevel(logging.INFO)
|
|
|
|
|
|
|
|
|
|
console = logging.StreamHandler()
|
|
|
|
|
console.setLevel(logging.INFO)
|
|
|
|
|
console.setFormatter(
|
|
|
|
|
logging.Formatter(
|
|
|
|
|
"%(asctime)s %(levelname)-8s %(name)s — %(message)s",
|
|
|
|
|
datefmt="%H:%M:%S",
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
root_logger.addHandler(console)
|
|
|
|
|
|
|
|
|
|
if settings.error_log_enabled:
|
|
|
|
|
from logging.handlers import RotatingFileHandler
|
|
|
|
|
|
|
|
|
|
log_dir = Path(settings.repo_root) / settings.error_log_dir
|
|
|
|
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
error_file = log_dir / "errors.log"
|
|
|
|
|
|
|
|
|
|
file_handler = RotatingFileHandler(
|
|
|
|
|
error_file,
|
|
|
|
|
maxBytes=settings.error_log_max_bytes,
|
|
|
|
|
backupCount=settings.error_log_backup_count,
|
|
|
|
|
)
|
|
|
|
|
file_handler.setLevel(logging.ERROR)
|
|
|
|
|
file_handler.setFormatter(
|
|
|
|
|
logging.Formatter(
|
|
|
|
|
"%(asctime)s %(levelname)-8s %(name)s — %(message)s\n"
|
|
|
|
|
" File: %(pathname)s:%(lineno)d\n"
|
|
|
|
|
" Function: %(funcName)s",
|
|
|
|
|
datefmt="%Y-%m-%d %H:%M:%S",
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
root_logger.addHandler(file_handler)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_configure_logging()
|
2026-02-19 19:31:48 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
2026-02-19 19:05:01 +00:00
|
|
|
BASE_DIR = Path(__file__).parent
|
|
|
|
|
PROJECT_ROOT = BASE_DIR.parent.parent
|
|
|
|
|
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
_BRIEFING_INTERVAL_HOURS = 6
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def _briefing_scheduler() -> None:
|
2026-02-28 11:07:19 -05:00
|
|
|
"""Background task: regenerate Timmy's briefing every 6 hours."""
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
from timmy.briefing import engine as briefing_engine
|
2026-02-26 22:07:41 +00:00
|
|
|
from infrastructure.notifications.push import notify_briefing_ready
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
await asyncio.sleep(2)
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
|
|
|
|
if briefing_engine.needs_refresh():
|
|
|
|
|
logger.info("Generating morning briefing…")
|
|
|
|
|
briefing = briefing_engine.generate()
|
|
|
|
|
await notify_briefing_ready(briefing)
|
|
|
|
|
else:
|
|
|
|
|
logger.info("Briefing is fresh; skipping generation.")
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.error("Briefing scheduler error: %s", exc)
|
2026-02-27 19:51:37 -05:00
|
|
|
try:
|
|
|
|
|
from infrastructure.error_capture import capture_error
|
|
|
|
|
capture_error(exc, source="briefing_scheduler")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
|
|
|
|
|
await asyncio.sleep(_BRIEFING_INTERVAL_HOURS * 3600)
|
|
|
|
|
|
|
|
|
|
|
2026-02-27 01:00:11 -05:00
|
|
|
async def _thinking_loop() -> None:
|
2026-02-28 11:07:19 -05:00
|
|
|
"""Background task: Timmy's default thinking thread."""
|
2026-02-27 01:52:42 -05:00
|
|
|
from swarm.task_queue.models import create_task
|
|
|
|
|
from datetime import datetime
|
2026-02-27 01:00:11 -05:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
await asyncio.sleep(10)
|
2026-02-27 01:00:11 -05:00
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
2026-02-27 01:52:42 -05:00
|
|
|
now = datetime.now()
|
|
|
|
|
create_task(
|
|
|
|
|
title=f"Thought: {now.strftime('%A %B %d, %I:%M %p')}",
|
|
|
|
|
description="Continue thinking about your existence, recent events, scripture, creative ideas, or a previous thread of thought.",
|
|
|
|
|
assigned_to="timmy",
|
2026-02-28 11:07:19 -05:00
|
|
|
created_by="timmy",
|
2026-02-27 01:52:42 -05:00
|
|
|
priority="low",
|
|
|
|
|
requires_approval=False,
|
|
|
|
|
auto_approve=True,
|
|
|
|
|
task_type="thought",
|
|
|
|
|
)
|
|
|
|
|
logger.debug("Created thought task in queue")
|
2026-02-27 01:00:11 -05:00
|
|
|
except Exception as exc:
|
|
|
|
|
logger.error("Thinking loop error: %s", exc)
|
2026-02-27 19:51:37 -05:00
|
|
|
try:
|
|
|
|
|
from infrastructure.error_capture import capture_error
|
|
|
|
|
capture_error(exc, source="thinking_loop")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2026-02-27 01:00:11 -05:00
|
|
|
|
|
|
|
|
await asyncio.sleep(settings.thinking_interval_seconds)
|
|
|
|
|
|
|
|
|
|
|
2026-02-28 21:15:53 -05:00
|
|
|
def handle_bug_report(task):
|
|
|
|
|
"""Process a bug report: log the decision and dispatch a fix task to Forge.
|
|
|
|
|
|
|
|
|
|
Timmy receives the bug report, decides it needs fixing, and creates
|
|
|
|
|
a code_fix task assigned to Forge. Every decision is logged to the
|
|
|
|
|
event log so there is a full audit trail of what Timmy decided and why.
|
|
|
|
|
"""
|
|
|
|
|
from swarm.event_log import EventType, log_event
|
|
|
|
|
from swarm.task_queue.models import create_task
|
|
|
|
|
|
|
|
|
|
decision = {
|
|
|
|
|
"action": "dispatch_to_forge",
|
|
|
|
|
"reason": f"Bug report received, dispatching fix to Forge: {task.title}",
|
|
|
|
|
"priority": task.priority.value,
|
|
|
|
|
"source_task_id": task.id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Dispatch a fix task to Forge
|
|
|
|
|
try:
|
|
|
|
|
fix_task = create_task(
|
|
|
|
|
title=f"[Fix] {task.title}",
|
|
|
|
|
description=(
|
|
|
|
|
f"## Bug Report\n\n{task.description or task.title}\n\n"
|
|
|
|
|
f"## Task\n\nImplement a fix for this bug and write a test proving the fix."
|
|
|
|
|
),
|
|
|
|
|
assigned_to="forge",
|
|
|
|
|
created_by="timmy",
|
|
|
|
|
priority=task.priority.value,
|
|
|
|
|
task_type="code_fix",
|
|
|
|
|
requires_approval=False,
|
|
|
|
|
auto_approve=True,
|
|
|
|
|
parent_task_id=task.id,
|
|
|
|
|
)
|
|
|
|
|
decision["outcome"] = "fix_dispatched"
|
|
|
|
|
decision["fix_task_id"] = fix_task.id
|
|
|
|
|
except Exception as e:
|
|
|
|
|
decision["outcome"] = "dispatch_failed"
|
|
|
|
|
decision["error"] = str(e)
|
|
|
|
|
|
|
|
|
|
# Log the decision trail to the event log
|
|
|
|
|
try:
|
|
|
|
|
log_event(
|
|
|
|
|
EventType.BUG_REPORT_CREATED,
|
|
|
|
|
source="bug_report_handler",
|
|
|
|
|
task_id=task.id,
|
|
|
|
|
agent_id="timmy",
|
|
|
|
|
data=decision,
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Return structured result (stored in task.result)
|
|
|
|
|
if decision.get("fix_task_id"):
|
|
|
|
|
return (
|
|
|
|
|
f"Fix dispatched to Forge (task {decision['fix_task_id']}) | "
|
|
|
|
|
f"Decision: {decision['reason']}"
|
|
|
|
|
)
|
|
|
|
|
return (
|
|
|
|
|
f"Bug tracked internally (dispatch failed) | "
|
|
|
|
|
f"Decision: {decision['reason']} | Error: {decision.get('error', 'unknown')}"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2026-02-27 01:52:42 -05:00
|
|
|
async def _task_processor_loop() -> None:
|
2026-02-28 11:07:19 -05:00
|
|
|
"""Background task: Timmy's task queue processor."""
|
2026-02-27 01:52:42 -05:00
|
|
|
from swarm.task_processor import task_processor
|
2026-02-28 12:18:18 -05:00
|
|
|
from swarm.task_queue.models import update_task_status, list_tasks, TaskStatus
|
2026-02-27 01:52:42 -05:00
|
|
|
from timmy.session import chat as timmy_chat
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
import json
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
await asyncio.sleep(5)
|
2026-02-27 01:52:42 -05:00
|
|
|
|
|
|
|
|
def handle_chat_response(task):
|
|
|
|
|
try:
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
context = f"[System: Current date/time is {now.strftime('%A, %B %d, %Y at %I:%M %p')}]\n\n"
|
|
|
|
|
response = timmy_chat(context + task.description)
|
|
|
|
|
|
2026-02-28 20:22:47 -05:00
|
|
|
# Log the real agent response to chat history
|
|
|
|
|
try:
|
|
|
|
|
from dashboard.store import message_log
|
|
|
|
|
timestamp = now.strftime("%H:%M:%S")
|
feat: Phase 1 autonomy upgrades — introspection, heartbeat, source tagging, Discord auto-detect (#101)
UC-01: Live System Introspection Tool
- Add get_task_queue_status(), get_agent_roster(), get_live_system_status()
to timmy/tools_intro with graceful degradation
- Enhanced get_memory_status() with line counts, section headers, vault
directory listing, semantic memory row count, self-coding journal stats
- Register system_status MCP tool (creative/tools/system_status.py)
- Add system_status to Timmy's tool list + Hard Rule #7
UC-02: Fix Offline Status Bug
- Add registry.heartbeat() calls in task_processor run_loop() and
process_single_task() so health endpoint reflects actual agent status
- health.py now consults swarm registry instead of Ollama connectivity
UC-03: Message Source Tagging
- Add source field to Message dataclass (default "browser")
- Tag all message_log.append() calls: browser, api, system
- Include source in /api/chat/history response
UC-04: Discord Token Auto-Detection & Docker Fix
- Add _discord_token_watcher() background coroutine that polls every 30s
for DISCORD_TOKEN in env vars, .env file, or state file
- Add --extras discord to all three Dockerfiles (main, dashboard, test)
All 26 Phase 1 tests pass in Docker (make test-docker).
Full suite: 1889 passed, 77 skipped, 0 failed.
Co-authored-by: Alexander Payne <apayne@MM.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:49:24 -05:00
|
|
|
message_log.append(role="agent", content=response, timestamp=timestamp, source="system")
|
2026-02-28 20:22:47 -05:00
|
|
|
except Exception as e:
|
|
|
|
|
logger.debug("Failed to log response to message_log: %s", e)
|
|
|
|
|
|
|
|
|
|
# Push response to chat UI via WebSocket
|
2026-02-27 01:52:42 -05:00
|
|
|
try:
|
|
|
|
|
from infrastructure.ws_manager.handler import ws_manager
|
|
|
|
|
asyncio.create_task(
|
|
|
|
|
ws_manager.broadcast(
|
|
|
|
|
"timmy_response",
|
|
|
|
|
{
|
|
|
|
|
"task_id": task.id,
|
|
|
|
|
"response": response,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.debug("Failed to push response via WS: %s", e)
|
|
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error("Chat response failed: %s", e)
|
2026-02-27 19:51:37 -05:00
|
|
|
try:
|
|
|
|
|
from infrastructure.error_capture import capture_error
|
|
|
|
|
capture_error(e, source="chat_response_handler")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2026-02-27 01:52:42 -05:00
|
|
|
return f"Error: {str(e)}"
|
|
|
|
|
|
|
|
|
|
def handle_thought(task):
|
|
|
|
|
from timmy.thinking import thinking_engine
|
|
|
|
|
try:
|
fix: Docker-first test suite, UX improvements, and bug fixes (#100)
Dashboard UX:
- Restructure nav from 22 flat links to 6 core + MORE dropdown
- Add mobile nav section labels (Core, Intelligence, Agents, System, Commerce)
- Defer marked.js and dompurify.js loading, consolidate CDN to jsdelivr
- Optimize font weights (drop unused 300/500), bump style.css cache buster
- Remove duplicate HTMX load triggers from sidebar and health panels
Bug fixes:
- Fix Timmy showing OFFLINE by registering after swarm recovery sweep
- Fix ThinkingEngine await bug with asyncio.run_coroutine_threadsafe
- Fix chat auto-scroll by calling scrollChat() after history partial loads
- Add missing /voice/button page and /voice/command endpoint
- Fix Grok api_key="" treated as falsy falling through to env key
- Fix self_modify PROJECT_ROOT using settings.repo_root instead of __file__
Docker test infrastructure:
- Bind-mount hands/, docker/, Dockerfiles, and compose files into test container
- Add fontconfig + fonts-dejavu-core for creative/assembler TextClip tests
- Initialize minimal git repo in Dockerfile.test for GitSafety compatibility
- Fix introspection and path resolution tests for Docker /app context
All 1863 tests pass in Docker (0 failures, 77 skipped).
Co-authored-by: Alexander Payne <apayne@MM.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:14:37 -05:00
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
|
future = asyncio.run_coroutine_threadsafe(
|
|
|
|
|
thinking_engine.think_once(), loop
|
|
|
|
|
)
|
|
|
|
|
result = future.result(timeout=120)
|
2026-02-27 01:52:42 -05:00
|
|
|
return str(result) if result else "Thought completed"
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error("Thought processing failed: %s", e)
|
2026-02-27 19:51:37 -05:00
|
|
|
try:
|
|
|
|
|
from infrastructure.error_capture import capture_error
|
|
|
|
|
capture_error(e, source="thought_handler")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2026-02-27 01:52:42 -05:00
|
|
|
return f"Error: {str(e)}"
|
|
|
|
|
|
2026-02-28 07:39:31 -05:00
|
|
|
def handle_task_request(task):
|
|
|
|
|
try:
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
context = (
|
|
|
|
|
f"[System: Current date/time is {now.strftime('%A, %B %d, %Y at %I:%M %p')}]\n"
|
|
|
|
|
f"[System: You have been assigned a task from the queue. "
|
|
|
|
|
f"Complete it and provide your response.]\n\n"
|
|
|
|
|
f"Task: {task.title}\n"
|
|
|
|
|
)
|
|
|
|
|
if task.description and task.description != task.title:
|
|
|
|
|
context += f"Details: {task.description}\n"
|
|
|
|
|
|
|
|
|
|
response = timmy_chat(context)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from infrastructure.ws_manager.handler import ws_manager
|
|
|
|
|
asyncio.create_task(
|
|
|
|
|
ws_manager.broadcast(
|
2026-02-28 11:07:19 -05:00
|
|
|
"task_response",
|
2026-02-28 07:39:31 -05:00
|
|
|
{
|
|
|
|
|
"task_id": task.id,
|
|
|
|
|
"response": response,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except Exception as e:
|
2026-02-28 11:07:19 -05:00
|
|
|
logger.debug("Failed to push task response via WS: %s", e)
|
2026-02-28 07:39:31 -05:00
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
except Exception as e:
|
2026-02-28 11:07:19 -05:00
|
|
|
logger.error("Task request processing failed: %s", e)
|
2026-02-28 07:39:31 -05:00
|
|
|
try:
|
|
|
|
|
from infrastructure.error_capture import capture_error
|
|
|
|
|
capture_error(e, source="task_request_handler")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
return f"Error: {str(e)}"
|
|
|
|
|
|
2026-02-28 13:12:14 -05:00
|
|
|
# Register handlers for all known task types
|
2026-02-28 12:18:18 -05:00
|
|
|
task_processor.register_handler("chat_response", handle_chat_response)
|
|
|
|
|
task_processor.register_handler("thought", handle_thought)
|
|
|
|
|
task_processor.register_handler("internal", handle_thought)
|
|
|
|
|
task_processor.register_handler("bug_report", handle_bug_report)
|
|
|
|
|
task_processor.register_handler("task_request", handle_task_request)
|
2026-02-28 13:12:14 -05:00
|
|
|
task_processor.register_handler("escalation", handle_task_request)
|
|
|
|
|
task_processor.register_handler("external", handle_task_request)
|
2026-02-28 12:18:18 -05:00
|
|
|
|
|
|
|
|
# ── Reconcile zombie tasks from previous crash ──
|
|
|
|
|
zombie_count = task_processor.reconcile_zombie_tasks()
|
|
|
|
|
if zombie_count:
|
|
|
|
|
logger.info("Recycled %d zombie task(s) back to approved", zombie_count)
|
|
|
|
|
|
|
|
|
|
# ── Re-approve tasks backlogged due to missing handlers ──
|
|
|
|
|
stale = list_tasks(status=TaskStatus.BACKLOGGED, assigned_to="timmy")
|
|
|
|
|
requeued = 0
|
|
|
|
|
for t in stale:
|
|
|
|
|
if t.backlog_reason and "No handler for task type" in t.backlog_reason:
|
|
|
|
|
update_task_status(t.id, TaskStatus.APPROVED, result=None)
|
|
|
|
|
requeued += 1
|
|
|
|
|
if requeued:
|
|
|
|
|
logger.info("Re-queued %d task(s) that were backlogged due to missing handlers", requeued)
|
|
|
|
|
|
|
|
|
|
# ── Startup drain: iterate through all pending tasks immediately ──
|
|
|
|
|
logger.info("Draining task queue on startup...")
|
|
|
|
|
try:
|
|
|
|
|
summary = await task_processor.drain_queue()
|
|
|
|
|
if summary["processed"] or summary["backlogged"]:
|
|
|
|
|
logger.info(
|
|
|
|
|
"Startup drain: %d processed, %d backlogged, %d skipped, %d failed",
|
|
|
|
|
summary["processed"],
|
|
|
|
|
summary["backlogged"],
|
|
|
|
|
summary["skipped"],
|
|
|
|
|
summary["failed"],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Notify via WebSocket so the dashboard updates
|
|
|
|
|
try:
|
|
|
|
|
from infrastructure.ws_manager.handler import ws_manager
|
|
|
|
|
|
|
|
|
|
asyncio.create_task(
|
|
|
|
|
ws_manager.broadcast_json(
|
|
|
|
|
{
|
|
|
|
|
"type": "task_event",
|
|
|
|
|
"event": "startup_drain_complete",
|
|
|
|
|
"summary": summary,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.error("Startup drain failed: %s", exc)
|
|
|
|
|
try:
|
|
|
|
|
from infrastructure.error_capture import capture_error
|
|
|
|
|
capture_error(exc, source="task_processor_startup")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# ── Steady-state: poll for new tasks ──
|
2026-02-28 11:07:19 -05:00
|
|
|
logger.info("Task processor entering steady-state loop")
|
|
|
|
|
await task_processor.run_loop(interval_seconds=3.0)
|
2026-02-27 01:52:42 -05:00
|
|
|
|
2026-02-28 06:57:51 -05:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
async def _spawn_persona_agents_background() -> None:
|
|
|
|
|
"""Background task: spawn persona agents without blocking startup."""
|
|
|
|
|
from swarm.coordinator import coordinator as swarm_coordinator
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(1) # Let server fully start
|
|
|
|
|
|
|
|
|
|
if os.environ.get("TIMMY_TEST_MODE") != "1":
|
|
|
|
|
logger.info("Auto-spawning persona agents: Echo, Forge, Seer...")
|
|
|
|
|
try:
|
|
|
|
|
swarm_coordinator.spawn_persona("echo", agent_id="persona-echo")
|
|
|
|
|
swarm_coordinator.spawn_persona("forge", agent_id="persona-forge")
|
|
|
|
|
swarm_coordinator.spawn_persona("seer", agent_id="persona-seer")
|
|
|
|
|
logger.info("Persona agents spawned successfully")
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.error("Failed to spawn persona agents: %s", exc)
|
2026-02-27 01:52:42 -05:00
|
|
|
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
async def _bootstrap_mcp_background() -> None:
|
|
|
|
|
"""Background task: bootstrap MCP tools without blocking startup."""
|
|
|
|
|
from mcp.bootstrap import auto_bootstrap
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(0.5) # Let server start
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
registered = auto_bootstrap()
|
|
|
|
|
if registered:
|
|
|
|
|
logger.info("MCP auto-bootstrap: %d tools registered", len(registered))
|
2026-02-27 01:52:42 -05:00
|
|
|
except Exception as exc:
|
2026-02-28 11:07:19 -05:00
|
|
|
logger.warning("MCP auto-bootstrap failed: %s", exc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def _start_chat_integrations_background() -> None:
|
|
|
|
|
"""Background task: start chat integrations without blocking startup."""
|
|
|
|
|
from integrations.telegram_bot.bot import telegram_bot
|
|
|
|
|
from integrations.chat_bridge.vendors.discord import discord_bot
|
2026-02-28 15:01:48 -05:00
|
|
|
from integrations.chat_bridge.registry import platform_registry
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
await asyncio.sleep(0.5)
|
2026-02-28 15:01:48 -05:00
|
|
|
|
|
|
|
|
# Register Discord in the platform registry
|
|
|
|
|
platform_registry.register(discord_bot)
|
2026-02-28 11:07:19 -05:00
|
|
|
|
|
|
|
|
if settings.telegram_token:
|
2026-02-27 19:51:37 -05:00
|
|
|
try:
|
2026-02-28 11:07:19 -05:00
|
|
|
await telegram_bot.start()
|
|
|
|
|
logger.info("Telegram bot started")
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.warning("Failed to start Telegram bot: %s", exc)
|
|
|
|
|
else:
|
|
|
|
|
logger.debug("Telegram: no token configured, skipping")
|
2026-02-27 01:52:42 -05:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
if settings.discord_token or discord_bot.load_token():
|
|
|
|
|
try:
|
|
|
|
|
await discord_bot.start()
|
|
|
|
|
logger.info("Discord bot started")
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.warning("Failed to start Discord bot: %s", exc)
|
|
|
|
|
else:
|
|
|
|
|
logger.debug("Discord: no token configured, skipping")
|
2026-02-27 01:52:42 -05:00
|
|
|
|
feat: Phase 1 autonomy upgrades — introspection, heartbeat, source tagging, Discord auto-detect (#101)
UC-01: Live System Introspection Tool
- Add get_task_queue_status(), get_agent_roster(), get_live_system_status()
to timmy/tools_intro with graceful degradation
- Enhanced get_memory_status() with line counts, section headers, vault
directory listing, semantic memory row count, self-coding journal stats
- Register system_status MCP tool (creative/tools/system_status.py)
- Add system_status to Timmy's tool list + Hard Rule #7
UC-02: Fix Offline Status Bug
- Add registry.heartbeat() calls in task_processor run_loop() and
process_single_task() so health endpoint reflects actual agent status
- health.py now consults swarm registry instead of Ollama connectivity
UC-03: Message Source Tagging
- Add source field to Message dataclass (default "browser")
- Tag all message_log.append() calls: browser, api, system
- Include source in /api/chat/history response
UC-04: Discord Token Auto-Detection & Docker Fix
- Add _discord_token_watcher() background coroutine that polls every 30s
for DISCORD_TOKEN in env vars, .env file, or state file
- Add --extras discord to all three Dockerfiles (main, dashboard, test)
All 26 Phase 1 tests pass in Docker (make test-docker).
Full suite: 1889 passed, 77 skipped, 0 failed.
Co-authored-by: Alexander Payne <apayne@MM.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:49:24 -05:00
|
|
|
# If Discord isn't connected yet, start a watcher that polls for the
|
|
|
|
|
# token to appear in the environment or .env file.
|
|
|
|
|
if discord_bot.state.name != "CONNECTED":
|
|
|
|
|
asyncio.create_task(_discord_token_watcher())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def _discord_token_watcher() -> None:
|
|
|
|
|
"""Poll for DISCORD_TOKEN appearing in env or .env and auto-start Discord bot."""
|
|
|
|
|
from integrations.chat_bridge.vendors.discord import discord_bot
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
await asyncio.sleep(30)
|
|
|
|
|
|
|
|
|
|
if discord_bot.state.name == "CONNECTED":
|
|
|
|
|
return # Already running — stop watching
|
|
|
|
|
|
|
|
|
|
# 1. Check live environment variable
|
|
|
|
|
token = os.environ.get("DISCORD_TOKEN", "")
|
|
|
|
|
|
|
|
|
|
# 2. Re-read .env file for hot-reload
|
|
|
|
|
if not token:
|
|
|
|
|
try:
|
|
|
|
|
from dotenv import dotenv_values
|
|
|
|
|
|
|
|
|
|
env_path = Path(settings.repo_root) / ".env"
|
|
|
|
|
if env_path.exists():
|
|
|
|
|
vals = dotenv_values(env_path)
|
|
|
|
|
token = vals.get("DISCORD_TOKEN", "")
|
|
|
|
|
except ImportError:
|
|
|
|
|
pass # python-dotenv not installed
|
|
|
|
|
|
|
|
|
|
# 3. Check state file (written by /discord/setup)
|
|
|
|
|
if not token:
|
|
|
|
|
token = discord_bot.load_token() or ""
|
|
|
|
|
|
|
|
|
|
if token:
|
|
|
|
|
try:
|
|
|
|
|
success = await discord_bot.start(token=token)
|
|
|
|
|
if success:
|
|
|
|
|
logger.info("Discord bot auto-started (token detected)")
|
|
|
|
|
return # Done — stop watching
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.warning("Discord auto-start failed: %s", exc)
|
|
|
|
|
|
2026-02-27 01:52:42 -05:00
|
|
|
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
@asynccontextmanager
|
|
|
|
|
async def lifespan(app: FastAPI):
|
2026-02-28 11:07:19 -05:00
|
|
|
"""Application lifespan manager with non-blocking startup."""
|
|
|
|
|
|
|
|
|
|
# Create all background tasks without waiting for them
|
|
|
|
|
briefing_task = asyncio.create_task(_briefing_scheduler())
|
|
|
|
|
|
fix: Docker-first test suite, UX improvements, and bug fixes (#100)
Dashboard UX:
- Restructure nav from 22 flat links to 6 core + MORE dropdown
- Add mobile nav section labels (Core, Intelligence, Agents, System, Commerce)
- Defer marked.js and dompurify.js loading, consolidate CDN to jsdelivr
- Optimize font weights (drop unused 300/500), bump style.css cache buster
- Remove duplicate HTMX load triggers from sidebar and health panels
Bug fixes:
- Fix Timmy showing OFFLINE by registering after swarm recovery sweep
- Fix ThinkingEngine await bug with asyncio.run_coroutine_threadsafe
- Fix chat auto-scroll by calling scrollChat() after history partial loads
- Add missing /voice/button page and /voice/command endpoint
- Fix Grok api_key="" treated as falsy falling through to env key
- Fix self_modify PROJECT_ROOT using settings.repo_root instead of __file__
Docker test infrastructure:
- Bind-mount hands/, docker/, Dockerfiles, and compose files into test container
- Add fontconfig + fonts-dejavu-core for creative/assembler TextClip tests
- Initialize minimal git repo in Dockerfile.test for GitSafety compatibility
- Fix introspection and path resolution tests for Docker /app context
All 1863 tests pass in Docker (0 failures, 77 skipped).
Co-authored-by: Alexander Payne <apayne@MM.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:14:37 -05:00
|
|
|
# Run swarm recovery first (offlines all stale agents)
|
2026-02-22 16:21:32 -05:00
|
|
|
from swarm.coordinator import coordinator as swarm_coordinator
|
2026-02-28 15:01:48 -05:00
|
|
|
swarm_coordinator.initialize()
|
2026-02-22 16:21:32 -05:00
|
|
|
rec = swarm_coordinator._recovery_summary
|
|
|
|
|
if rec["tasks_failed"] or rec["agents_offlined"]:
|
|
|
|
|
logger.info(
|
|
|
|
|
"Swarm recovery on startup: %d task(s) → FAILED, %d agent(s) → offline",
|
|
|
|
|
rec["tasks_failed"],
|
|
|
|
|
rec["agents_offlined"],
|
|
|
|
|
)
|
|
|
|
|
|
fix: Docker-first test suite, UX improvements, and bug fixes (#100)
Dashboard UX:
- Restructure nav from 22 flat links to 6 core + MORE dropdown
- Add mobile nav section labels (Core, Intelligence, Agents, System, Commerce)
- Defer marked.js and dompurify.js loading, consolidate CDN to jsdelivr
- Optimize font weights (drop unused 300/500), bump style.css cache buster
- Remove duplicate HTMX load triggers from sidebar and health panels
Bug fixes:
- Fix Timmy showing OFFLINE by registering after swarm recovery sweep
- Fix ThinkingEngine await bug with asyncio.run_coroutine_threadsafe
- Fix chat auto-scroll by calling scrollChat() after history partial loads
- Add missing /voice/button page and /voice/command endpoint
- Fix Grok api_key="" treated as falsy falling through to env key
- Fix self_modify PROJECT_ROOT using settings.repo_root instead of __file__
Docker test infrastructure:
- Bind-mount hands/, docker/, Dockerfiles, and compose files into test container
- Add fontconfig + fonts-dejavu-core for creative/assembler TextClip tests
- Initialize minimal git repo in Dockerfile.test for GitSafety compatibility
- Fix introspection and path resolution tests for Docker /app context
All 1863 tests pass in Docker (0 failures, 77 skipped).
Co-authored-by: Alexander Payne <apayne@MM.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:14:37 -05:00
|
|
|
# Register Timmy AFTER recovery sweep so status sticks as "idle"
|
|
|
|
|
from swarm import registry as swarm_registry
|
|
|
|
|
swarm_registry.register(
|
|
|
|
|
name="Timmy",
|
|
|
|
|
capabilities="chat,reasoning,research,planning",
|
|
|
|
|
agent_id="timmy",
|
|
|
|
|
)
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Spawn persona agents in background
|
|
|
|
|
persona_task = asyncio.create_task(_spawn_persona_agents_background())
|
feat: swarm E2E, MCP tools, timmy-serve L402, tests, notifications
Major Features:
- Auto-spawn persona agents (Echo, Forge, Seer) on app startup
- WebSocket broadcasts for real-time swarm UI updates
- MCP tool integration: web search, file I/O, shell, Python execution
- New /tools dashboard page showing agent capabilities
- Real timmy-serve start with L402 payment gating middleware
- Browser push notifications for briefings and task events
Tests:
- test_docker_agent.py: 9 tests for Docker agent runner
- test_swarm_integration_full.py: 18 E2E lifecycle tests
- Fixed all pytest warnings (436 tests, 0 warnings)
Improvements:
- Fixed coroutine warnings in coordinator broadcasts
- Fixed ResourceWarning for unclosed process pipes
- Added pytest-asyncio config to pyproject.toml
- Test isolation with proper event loop cleanup
2026-02-22 19:01:04 -05:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Log system startup event
|
2026-02-26 10:27:08 -05:00
|
|
|
try:
|
|
|
|
|
from swarm.event_log import log_event, EventType
|
|
|
|
|
log_event(
|
|
|
|
|
EventType.SYSTEM_INFO,
|
|
|
|
|
source="coordinator",
|
|
|
|
|
data={"message": "Timmy Time system started"},
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Bootstrap MCP tools in background
|
|
|
|
|
mcp_task = asyncio.create_task(_bootstrap_mcp_background())
|
2026-02-26 21:30:39 +00:00
|
|
|
|
2026-02-28 19:27:48 -05:00
|
|
|
# Register OpenFang vendor tools (if enabled)
|
|
|
|
|
if settings.openfang_enabled:
|
|
|
|
|
try:
|
|
|
|
|
from infrastructure.openfang.tools import register_openfang_tools
|
|
|
|
|
|
|
|
|
|
count = register_openfang_tools()
|
|
|
|
|
logger.info("OpenFang: registered %d vendor tools", count)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
logger.warning("OpenFang tool registration failed: %s", exc)
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Initialize Spark Intelligence engine
|
feat: integrate Spark Intelligence into Timmy swarm system
Adds a self-evolving cognitive layer inspired by vibeship-spark-intelligence,
adapted for Timmy's agent architecture. Spark captures swarm events, runs
EIDOS prediction-evaluation loops, consolidates memories, and generates
advisory recommendations — all backed by SQLite consistent with existing
patterns.
New modules:
- spark/memory.py — event capture with importance scoring + memory consolidation
- spark/eidos.py — EIDOS cognitive loop (predict → observe → evaluate → learn)
- spark/advisor.py — ranked advisory generation from accumulated intelligence
- spark/engine.py — top-level API wiring all subsystems together
Dashboard:
- /spark/ui — full Spark Intelligence dashboard (3-column: status/advisories,
predictions/memories, event timeline) with HTMX auto-refresh
- /spark — JSON API for programmatic access
- SPARK link added to navigation header
Integration:
- Coordinator hooks emit Spark events on task post, bid, assign, complete, fail
- EIDOS predictions generated when tasks are posted, evaluated on completion
- Memory consolidation triggers when agents accumulate enough outcomes
- SPARK_ENABLED config toggle (default: true)
Tests: 47 new tests covering all Spark subsystems + dashboard routes.
Full suite: 538 tests passing.
https://claude.ai/code/session_01KJm6jQkNi3aA3yoQJn636c
2026-02-24 15:51:15 +00:00
|
|
|
from spark.engine import spark_engine
|
|
|
|
|
if spark_engine.enabled:
|
|
|
|
|
logger.info("Spark Intelligence active — event capture enabled")
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Start thinking thread if enabled
|
2026-02-27 01:00:11 -05:00
|
|
|
thinking_task = None
|
|
|
|
|
if settings.thinking_enabled and os.environ.get("TIMMY_TEST_MODE") != "1":
|
|
|
|
|
thinking_task = asyncio.create_task(_thinking_loop())
|
|
|
|
|
logger.info(
|
|
|
|
|
"Default thinking thread started (interval: %ds)",
|
|
|
|
|
settings.thinking_interval_seconds,
|
|
|
|
|
)
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Start task processor if not in test mode
|
2026-02-27 01:52:42 -05:00
|
|
|
task_processor_task = None
|
|
|
|
|
if os.environ.get("TIMMY_TEST_MODE") != "1":
|
|
|
|
|
task_processor_task = asyncio.create_task(_task_processor_loop())
|
|
|
|
|
logger.info("Task queue processor started")
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Start chat integrations in background
|
|
|
|
|
chat_task = asyncio.create_task(_start_chat_integrations_background())
|
2026-02-27 01:52:42 -05:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
logger.info("✓ Timmy Time dashboard ready for requests")
|
2026-02-25 01:11:14 +00:00
|
|
|
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
yield
|
2026-02-22 17:16:12 +00:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Cleanup on shutdown
|
|
|
|
|
from integrations.telegram_bot.bot import telegram_bot
|
2026-02-28 15:01:48 -05:00
|
|
|
from integrations.chat_bridge.vendors.discord import discord_bot
|
|
|
|
|
|
2026-02-25 01:11:14 +00:00
|
|
|
await discord_bot.stop()
|
2026-02-22 17:16:12 +00:00
|
|
|
await telegram_bot.stop()
|
2026-02-28 11:07:19 -05:00
|
|
|
|
|
|
|
|
for task in [thinking_task, task_processor_task, briefing_task, persona_task, mcp_task, chat_task]:
|
|
|
|
|
if task:
|
|
|
|
|
task.cancel()
|
|
|
|
|
try:
|
|
|
|
|
await task
|
|
|
|
|
except asyncio.CancelledError:
|
|
|
|
|
pass
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
|
|
|
|
|
|
2026-02-19 19:31:48 +00:00
|
|
|
app = FastAPI(
|
|
|
|
|
title="Timmy Time — Mission Control",
|
|
|
|
|
version="1.0.0",
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
lifespan=lifespan,
|
2026-02-28 11:07:19 -05:00
|
|
|
docs_url="/docs",
|
|
|
|
|
openapi_url="/openapi.json",
|
2026-02-19 19:31:48 +00:00
|
|
|
)
|
2026-02-19 19:05:01 +00:00
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# CORS middleware
|
feat: replace GitHub page with embedded Timmy chat interface
Replaces the marketing landing page with a minimal, full-screen chat
interface that connects to a running Timmy instance. Mobile-first design
with single vertical scroll direction, looping scroll, no zoom, no
buttons — just type and press Enter to talk to Timmy.
- docs/index.html: full rewrite as a clean chat UI with dark terminal
theme, looping infinite scroll, markdown rendering, connection status,
and /connect, /clear, /help slash commands
- src/dashboard/app.py: add CORS middleware so the GitHub Pages site can
reach a local Timmy server cross-origin
- src/config.py: add cors_origins setting (defaults to ["*"])
https://claude.ai/code/session_01AWLxg6KDWsfCATiuvsRMGr
2026-02-27 00:35:33 +00:00
|
|
|
app.add_middleware(
|
|
|
|
|
CORSMiddleware,
|
2026-02-28 11:07:19 -05:00
|
|
|
allow_origins=["*"],
|
feat: replace GitHub page with embedded Timmy chat interface
Replaces the marketing landing page with a minimal, full-screen chat
interface that connects to a running Timmy instance. Mobile-first design
with single vertical scroll direction, looping scroll, no zoom, no
buttons — just type and press Enter to talk to Timmy.
- docs/index.html: full rewrite as a clean chat UI with dark terminal
theme, looping infinite scroll, markdown rendering, connection status,
and /connect, /clear, /help slash commands
- src/dashboard/app.py: add CORS middleware so the GitHub Pages site can
reach a local Timmy server cross-origin
- src/config.py: add cors_origins setting (defaults to ["*"])
https://claude.ai/code/session_01AWLxg6KDWsfCATiuvsRMGr
2026-02-27 00:35:33 +00:00
|
|
|
allow_credentials=True,
|
|
|
|
|
allow_methods=["*"],
|
|
|
|
|
allow_headers=["*"],
|
|
|
|
|
)
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Mount static files
|
|
|
|
|
static_dir = PROJECT_ROOT / "static"
|
|
|
|
|
if static_dir.exists():
|
|
|
|
|
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
|
2026-02-26 23:58:53 -05:00
|
|
|
|
CI/CD Optimization: Guard Rails, Pre-commit Checks, and Test Fixes (#90)
* CI/CD Optimization: Guard Rails, Black Linting, and Pre-commit Hooks
- Fixed all test collection errors (Selenium imports, fixture paths, syntax)
- Implemented pre-commit hooks with Black formatting and isort
- Created comprehensive Makefile with test targets (unit, integration, functional, e2e)
- Added pytest.ini with marker definitions for test categorization
- Established guard rails to prevent future collection errors
- Wrapped optional dependencies (Selenium, MoviePy) in try-except blocks
- Added conftest_markers for automatic test categorization
This ensures a smooth development stream with:
- Fast feedback loops (pre-commit checks before push)
- Consistent code formatting (Black)
- Reliable CI/CD (no collection errors, proper test isolation)
- Clear test organization (unit, integration, functional, E2E)
* Fix CI/CD test failures:
- Export templates from dashboard.app
- Fix model name assertion in test_agent.py
- Fix platform-agnostic path resolution in test_path_resolution.py
- Skip Docker tests in test_docker_deployment.py if docker not available
- Fix test_model_fallback_chain logic in test_ollama_integration.py
* Add preventative pre-commit checks and Docker test skipif decorators:
- Create pre_commit_checks.py script for common CI failures
- Add skipif decorators to Docker tests
- Improve test robustness for CI environments
2026-02-28 11:36:50 -05:00
|
|
|
# Global templates instance
|
|
|
|
|
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
|
|
|
|
|
|
|
|
|
|
|
2026-02-28 11:07:19 -05:00
|
|
|
# Include routers
|
2026-02-19 19:05:01 +00:00
|
|
|
app.include_router(health_router)
|
|
|
|
|
app.include_router(agents_router)
|
feat: Mission Control v2 — swarm, L402, voice, marketplace, React dashboard
Major expansion of the Timmy Time Dashboard:
Backend modules:
- Swarm subsystem: registry, manager, bidder, coordinator, agent_runner, swarm_node, tasks, comms
- L402/Lightning: payment_handler, l402_proxy with HMAC macaroons
- Voice NLU: regex-based intent detection (chat, status, swarm, task, help, voice)
- Notifications: push notifier for swarm events
- Shortcuts: Siri Shortcuts iOS integration endpoints
- WebSocket: live dashboard event manager
- Inter-agent: agent-to-agent messaging layer
Dashboard routes:
- /swarm/* — swarm management and agent registry
- /marketplace — agent catalog with sat pricing
- /voice/* — voice command processing
- /mobile — mobile status endpoint
- /swarm/live — WebSocket live feed
React web dashboard (dashboard-web/):
- Sovereign Terminal design — dark theme with Bitcoin orange accents
- Three-column layout: status sidebar, workspace tabs, context panel
- Chat, Swarm, Tasks, Marketplace tab views
- JetBrains Mono typography, terminal aesthetic
- Framer Motion animations throughout
Tests: 228 passing (expanded from 93)
Includes Kimi's additional templates and QA work.
2026-02-21 12:57:38 -05:00
|
|
|
app.include_router(swarm_router)
|
2026-02-26 21:30:39 +00:00
|
|
|
app.include_router(swarm_internal_router)
|
feat: Mission Control v2 — swarm, L402, voice, marketplace, React dashboard
Major expansion of the Timmy Time Dashboard:
Backend modules:
- Swarm subsystem: registry, manager, bidder, coordinator, agent_runner, swarm_node, tasks, comms
- L402/Lightning: payment_handler, l402_proxy with HMAC macaroons
- Voice NLU: regex-based intent detection (chat, status, swarm, task, help, voice)
- Notifications: push notifier for swarm events
- Shortcuts: Siri Shortcuts iOS integration endpoints
- WebSocket: live dashboard event manager
- Inter-agent: agent-to-agent messaging layer
Dashboard routes:
- /swarm/* — swarm management and agent registry
- /marketplace — agent catalog with sat pricing
- /voice/* — voice command processing
- /mobile — mobile status endpoint
- /swarm/live — WebSocket live feed
React web dashboard (dashboard-web/):
- Sovereign Terminal design — dark theme with Bitcoin orange accents
- Three-column layout: status sidebar, workspace tabs, context panel
- Chat, Swarm, Tasks, Marketplace tab views
- JetBrains Mono typography, terminal aesthetic
- Framer Motion animations throughout
Tests: 228 passing (expanded from 93)
Includes Kimi's additional templates and QA work.
2026-02-21 12:57:38 -05:00
|
|
|
app.include_router(marketplace_router)
|
|
|
|
|
app.include_router(voice_router)
|
|
|
|
|
app.include_router(mobile_router)
|
feat(briefing): morning briefing + approval queue
Implements the Morning Briefing and Approval Queue feature — the first step
from tool to companion. Timmy now shows up before the owner asks.
New modules
-----------
• src/timmy/approvals.py — ApprovalItem dataclass, GOLDEN_TIMMY governance
constant, full SQLite CRUD (create / list / approve / reject / expire).
Items auto-expire after 7 days if not actioned.
• src/timmy/briefing.py — BriefingEngine that queries swarm activity and
chat history, calls Timmy's Agno agent for a prose summary, and caches
the result in SQLite (~/.timmy/briefings.db). get_or_generate() skips
regeneration if a fresh briefing (< 30 min) already exists.
New routes (src/dashboard/routes/briefing.py)
----------------------------------------------
GET /briefing — full briefing page
GET /briefing/approvals — HTMX partial: pending approval cards
POST /briefing/approvals/{id}/approve — approve via HTMX (no page reload)
POST /briefing/approvals/{id}/reject — reject via HTMX (no page reload)
New templates
-------------
• briefing.html — clean, mobile-first prose layout (max 680px)
• partials/approval_cards.html — list of approval cards
• partials/approval_card_single.html — single approval card with
Approve/Reject HTMX buttons
App wiring (src/dashboard/app.py)
----------------------------------
• Added asynccontextmanager lifespan with _briefing_scheduler background task.
Generates a briefing at startup and every 6 hours; skips if fresh.
Push notification hook (src/notifications/push.py)
---------------------------------------------------
• notify_briefing_ready(briefing) — logs + triggers local notifier.
Placeholder for APNs/Pushover wiring later.
Navigation
----------
• Added BRIEFING link to the header nav in base.html.
Tests
-----
• tests/test_approvals.py — 17 tests: GOLDEN_TIMMY, CRUD, expiry, ordering
• tests/test_briefing.py — 22 tests: dataclass, freshness, cache round-trip,
generate/get_or_generate, push notification hook
354 tests, 354 passing.
https://claude.ai/code/session_01D7p5w91KX3grBeioGiiGy8
2026-02-22 14:04:20 +00:00
|
|
|
app.include_router(briefing_router)
|
2026-02-22 17:16:12 +00:00
|
|
|
app.include_router(telegram_router)
|
feat: swarm E2E, MCP tools, timmy-serve L402, tests, notifications
Major Features:
- Auto-spawn persona agents (Echo, Forge, Seer) on app startup
- WebSocket broadcasts for real-time swarm UI updates
- MCP tool integration: web search, file I/O, shell, Python execution
- New /tools dashboard page showing agent capabilities
- Real timmy-serve start with L402 payment gating middleware
- Browser push notifications for briefings and task events
Tests:
- test_docker_agent.py: 9 tests for Docker agent runner
- test_swarm_integration_full.py: 18 E2E lifecycle tests
- Fixed all pytest warnings (436 tests, 0 warnings)
Improvements:
- Fixed coroutine warnings in coordinator broadcasts
- Fixed ResourceWarning for unclosed process pipes
- Added pytest-asyncio config to pyproject.toml
- Test isolation with proper event loop cleanup
2026-02-22 19:01:04 -05:00
|
|
|
app.include_router(tools_router)
|
feat: integrate Spark Intelligence into Timmy swarm system
Adds a self-evolving cognitive layer inspired by vibeship-spark-intelligence,
adapted for Timmy's agent architecture. Spark captures swarm events, runs
EIDOS prediction-evaluation loops, consolidates memories, and generates
advisory recommendations — all backed by SQLite consistent with existing
patterns.
New modules:
- spark/memory.py — event capture with importance scoring + memory consolidation
- spark/eidos.py — EIDOS cognitive loop (predict → observe → evaluate → learn)
- spark/advisor.py — ranked advisory generation from accumulated intelligence
- spark/engine.py — top-level API wiring all subsystems together
Dashboard:
- /spark/ui — full Spark Intelligence dashboard (3-column: status/advisories,
predictions/memories, event timeline) with HTMX auto-refresh
- /spark — JSON API for programmatic access
- SPARK link added to navigation header
Integration:
- Coordinator hooks emit Spark events on task post, bid, assign, complete, fail
- EIDOS predictions generated when tasks are posted, evaluated on completion
- Memory consolidation triggers when agents accumulate enough outcomes
- SPARK_ENABLED config toggle (default: true)
Tests: 47 new tests covering all Spark subsystems + dashboard routes.
Full suite: 538 tests passing.
https://claude.ai/code/session_01KJm6jQkNi3aA3yoQJn636c
2026-02-24 15:51:15 +00:00
|
|
|
app.include_router(spark_router)
|
feat: add full creative studio + DevOps tools (Pixel, Lyra, Reel personas)
Adds 3 new personas (Pixel, Lyra, Reel) and 5 new tool modules:
- Git/DevOps tools (GitPython): clone, status, diff, log, blame, branch,
add, commit, push, pull, stash — wired to Forge and Helm personas
- Image generation (FLUX via diffusers): text-to-image, storyboards,
variations — Pixel persona
- Music generation (ACE-Step 1.5): full songs with vocals+instrumentals,
instrumental tracks, vocal-only tracks — Lyra persona
- Video generation (Wan 2.1 via diffusers): text-to-video, image-to-video
clips — Reel persona
- Creative Director pipeline: multi-step orchestration that chains
storyboard → music → video → assembly into 3+ minute final videos
- Video assembler (MoviePy + FFmpeg): stitch clips, overlay audio,
title cards, subtitles, final export
Also includes:
- Spark Intelligence tool-level + creative pipeline event capture
- Creative Studio dashboard page (/creative/ui) with 4 tabs
- Config settings for all new models and output directories
- pyproject.toml creative optional extra for GPU dependencies
- 107 new tests covering all modules (624 total, all passing)
https://claude.ai/code/session_01KJm6jQkNi3aA3yoQJn636c
2026-02-24 16:31:47 +00:00
|
|
|
app.include_router(creative_router)
|
2026-02-25 01:11:14 +00:00
|
|
|
app.include_router(discord_router)
|
feat: complete Event Log, Ledger, Memory, Cascade Router, Upgrade Queue, Activity Feed
This commit implements six major features:
1. Event Log System (src/swarm/event_log.py)
- SQLite-based audit trail for all swarm events
- Task lifecycle tracking (created, assigned, completed, failed)
- Agent lifecycle tracking (joined, left, status changes)
- Integrated with coordinator for automatic logging
- Dashboard page at /swarm/events
2. Lightning Ledger (src/lightning/ledger.py)
- Transaction tracking for Lightning Network payments
- Balance calculations (incoming, outgoing, net, available)
- Integrated with payment_handler for automatic logging
- Dashboard page at /lightning/ledger
3. Semantic Memory / Vector Store (src/memory/vector_store.py)
- Embedding-based similarity search for Echo agent
- Fallback to keyword matching if sentence-transformers unavailable
- Personal facts storage and retrieval
- Dashboard page at /memory
4. Cascade Router Integration (src/timmy/cascade_adapter.py)
- Automatic LLM failover between providers (Ollama → AirLLM → API)
- Circuit breaker pattern for failing providers
- Metrics tracking per provider (latency, error rates)
- Dashboard status page at /router/status
5. Self-Upgrade Approval Queue (src/upgrades/)
- State machine for self-modifications: proposed → approved/rejected → applied/failed
- Human approval required before applying changes
- Git integration for branch management
- Dashboard queue at /self-modify/queue
6. Real-Time Activity Feed (src/events/broadcaster.py)
- WebSocket-based live activity streaming
- Bridges event_log to dashboard clients
- Activity panel on /swarm/live
Tests:
- 101 unit tests passing
- 4 new E2E test files for Selenium testing
- Run with: SELENIUM_UI=1 pytest tests/functional/ -v --headed
Documentation:
- 6 ADRs (017-022) documenting architecture decisions
- Implementation summary in docs/IMPLEMENTATION_SUMMARY.md
- Architecture diagram in docs/architecture-v2.md
2026-02-26 08:01:01 -05:00
|
|
|
app.include_router(events_router)
|
|
|
|
|
app.include_router(ledger_router)
|
|
|
|
|
app.include_router(memory_router)
|
|
|
|
|
app.include_router(router_status_router)
|
|
|
|
|
app.include_router(upgrades_router)
|
2026-02-26 10:27:08 -05:00
|
|
|
app.include_router(work_orders_router)
|
|
|
|
|
app.include_router(tasks_router)
|
2026-02-26 17:06:00 +00:00
|
|
|
app.include_router(scripture_router)
|
2026-02-28 11:07:19 -05:00
|
|
|
app.include_router(self_coding_router)
|
|
|
|
|
app.include_router(self_modify_router)
|
2026-02-26 12:46:48 -05:00
|
|
|
app.include_router(hands_router)
|
feat: add Grok (xAI) as opt-in premium backend with monetization
- Add GrokBackend class in src/timmy/backends.py with full sync/async
support, health checks, usage stats, and cost estimation in sats
- Add consult_grok tool to Timmy's toolkit for proactive Grok queries
- Extend cascade router with Grok provider type for failover chain
- Add Grok Mode toggle card to Mission Control dashboard (HTMX live)
- Add "Ask Grok" button on chat input for direct Grok queries
- Add /grok/* routes: status, toggle, chat, stats endpoints
- Integrate Lightning invoice generation for Grok usage monetization
- Add GROK_ENABLED, XAI_API_KEY, GROK_DEFAULT_MODEL, GROK_MAX_SATS_PER_QUERY,
GROK_FREE config settings via pydantic-settings
- Update .env.example and docker-compose.yml with Grok env vars
- Add 21 tests covering backend, tools, and route endpoints (all green)
Local-first ethos preserved: Grok is premium augmentation only,
disabled by default, and Lightning-payable when enabled.
https://claude.ai/code/session_01FygwN8wS8J6WGZ8FPb7XGV
2026-02-27 01:12:51 +00:00
|
|
|
app.include_router(grok_router)
|
feat: add custom weights, model registry, per-agent models, and reward scoring
Inspired by OpenClaw-RL's multi-model orchestration, this adds four
features for custom model management:
1. Custom model registry (infrastructure/models/registry.py) — SQLite-backed
registry for GGUF, safetensors, HF checkpoint, and Ollama models with
role-based lookups (general, reward, teacher, judge).
2. Per-agent model assignment — each swarm persona can use a different model
instead of sharing the global default. Resolved via registry assignment >
persona default > global default.
3. Runtime model management API (/api/v1/models) — REST endpoints to register,
list, assign, enable/disable, and remove custom models without restart.
Includes a dashboard page at /models.
4. Reward model scoring (PRM-style) — majority-vote quality evaluation of
agent outputs using a configurable reward model. Scores persist in SQLite
and feed into the swarm learner.
New config settings: custom_weights_dir, reward_model_enabled,
reward_model_name, reward_model_votes.
54 new tests covering registry CRUD, API endpoints, agent assignments,
role lookups, and reward scoring.
https://claude.ai/code/session_01V4iTozMwcE2gjfnCJdCugC
2026-02-27 01:08:03 +00:00
|
|
|
app.include_router(models_router)
|
|
|
|
|
app.include_router(models_api_router)
|
2026-02-26 23:58:53 -05:00
|
|
|
app.include_router(chat_api_router)
|
2026-02-27 01:00:11 -05:00
|
|
|
app.include_router(thinking_router)
|
2026-02-27 19:51:37 -05:00
|
|
|
app.include_router(bugs_router)
|
2026-02-28 11:07:19 -05:00
|
|
|
app.include_router(cascade_router)
|
2026-02-19 19:05:01 +00:00
|
|
|
|
|
|
|
|
|
2026-02-28 12:18:18 -05:00
|
|
|
@app.websocket("/ws")
|
|
|
|
|
async def ws_redirect(websocket: WebSocket):
|
|
|
|
|
"""Catch stale /ws connections and close cleanly.
|
|
|
|
|
|
|
|
|
|
Before PR #82, frontend code connected to /ws which never existed as
|
|
|
|
|
an endpoint. Stale browser tabs retry forever, spamming 403 errors.
|
|
|
|
|
Accept the connection and immediately close with a policy-violation
|
|
|
|
|
code so the client stops retrying.
|
2026-02-28 20:09:03 -05:00
|
|
|
|
|
|
|
|
websockets 16.0 dropped the legacy ``transfer_data_task`` attribute,
|
|
|
|
|
so calling ``websocket.close()`` after accept triggers an
|
|
|
|
|
AttributeError. Use the raw ASGI send instead.
|
2026-02-28 12:18:18 -05:00
|
|
|
"""
|
|
|
|
|
await websocket.accept()
|
2026-02-28 20:09:03 -05:00
|
|
|
try:
|
|
|
|
|
await websocket.close(code=1008, reason="Use /swarm/live instead")
|
|
|
|
|
except AttributeError:
|
|
|
|
|
# websockets >= 16.0 — close via raw ASGI message
|
|
|
|
|
await websocket.send({"type": "websocket.close", "code": 1008})
|
2026-02-28 12:18:18 -05:00
|
|
|
|
|
|
|
|
|
2026-02-19 19:05:01 +00:00
|
|
|
@app.get("/", response_class=HTMLResponse)
|
2026-02-28 11:07:19 -05:00
|
|
|
async def root(request: Request):
|
|
|
|
|
"""Serve the main dashboard page."""
|
|
|
|
|
return templates.TemplateResponse("index.html", {"request": request})
|
CI/CD Optimization: Guard Rails, Pre-commit Checks, and Test Fixes (#90)
* CI/CD Optimization: Guard Rails, Black Linting, and Pre-commit Hooks
- Fixed all test collection errors (Selenium imports, fixture paths, syntax)
- Implemented pre-commit hooks with Black formatting and isort
- Created comprehensive Makefile with test targets (unit, integration, functional, e2e)
- Added pytest.ini with marker definitions for test categorization
- Established guard rails to prevent future collection errors
- Wrapped optional dependencies (Selenium, MoviePy) in try-except blocks
- Added conftest_markers for automatic test categorization
This ensures a smooth development stream with:
- Fast feedback loops (pre-commit checks before push)
- Consistent code formatting (Black)
- Reliable CI/CD (no collection errors, proper test isolation)
- Clear test organization (unit, integration, functional, E2E)
* Fix CI/CD test failures:
- Export templates from dashboard.app
- Fix model name assertion in test_agent.py
- Fix platform-agnostic path resolution in test_path_resolution.py
- Skip Docker tests in test_docker_deployment.py if docker not available
- Fix test_model_fallback_chain logic in test_ollama_integration.py
* Add preventative pre-commit checks and Docker test skipif decorators:
- Create pre_commit_checks.py script for common CI failures
- Add skipif decorators to Docker tests
- Improve test robustness for CI environments
2026-02-28 11:36:50 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/shortcuts/setup")
|
|
|
|
|
async def shortcuts_setup():
|
|
|
|
|
"""Siri Shortcuts setup guide."""
|
|
|
|
|
from integrations.shortcuts.siri import get_setup_guide
|
|
|
|
|
|
|
|
|
|
return get_setup_guide()
|