forked from Rockachopa/Timmy-time-dashboard
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
This commit is contained in:
@@ -5,6 +5,8 @@ The actual backend (mock or LND) is selected via LIGHTNING_BACKEND env var.
|
||||
|
||||
For backward compatibility, the PaymentHandler class and payment_handler
|
||||
singleton are preserved, but they delegate to the lightning backend.
|
||||
|
||||
All transactions are logged to the ledger for audit and accounting.
|
||||
"""
|
||||
|
||||
import logging
|
||||
@@ -13,6 +15,12 @@ from typing import Optional
|
||||
# Import from the new lightning module
|
||||
from lightning import get_backend, Invoice
|
||||
from lightning.base import LightningBackend
|
||||
from lightning.ledger import (
|
||||
create_invoice_entry,
|
||||
mark_settled,
|
||||
get_balance,
|
||||
list_transactions,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -42,22 +50,66 @@ class PaymentHandler:
|
||||
self._backend = backend or get_backend()
|
||||
logger.info("PaymentHandler initialized — backend: %s", self._backend.name)
|
||||
|
||||
def create_invoice(self, amount_sats: int, memo: str = "") -> Invoice:
|
||||
"""Create a new Lightning invoice."""
|
||||
def create_invoice(
|
||||
self,
|
||||
amount_sats: int,
|
||||
memo: str = "",
|
||||
source: str = "payment_handler",
|
||||
task_id: Optional[str] = None,
|
||||
agent_id: Optional[str] = None,
|
||||
) -> Invoice:
|
||||
"""Create a new Lightning invoice.
|
||||
|
||||
Args:
|
||||
amount_sats: Invoice amount in satoshis
|
||||
memo: Payment description
|
||||
source: Component creating the invoice
|
||||
task_id: Associated task ID
|
||||
agent_id: Associated agent ID
|
||||
"""
|
||||
invoice = self._backend.create_invoice(amount_sats, memo)
|
||||
logger.info(
|
||||
"Invoice created: %d sats — %s (hash: %s…)",
|
||||
amount_sats, memo, invoice.payment_hash[:12],
|
||||
)
|
||||
|
||||
# Log to ledger
|
||||
create_invoice_entry(
|
||||
payment_hash=invoice.payment_hash,
|
||||
amount_sats=amount_sats,
|
||||
memo=memo,
|
||||
invoice=invoice.bolt11 if hasattr(invoice, 'bolt11') else None,
|
||||
source=source,
|
||||
task_id=task_id,
|
||||
agent_id=agent_id,
|
||||
)
|
||||
|
||||
return invoice
|
||||
|
||||
def check_payment(self, payment_hash: str) -> bool:
|
||||
"""Check whether an invoice has been paid."""
|
||||
return self._backend.check_payment(payment_hash)
|
||||
"""Check whether an invoice has been paid.
|
||||
|
||||
If paid, updates the ledger entry.
|
||||
"""
|
||||
is_paid = self._backend.check_payment(payment_hash)
|
||||
|
||||
if is_paid:
|
||||
# Update ledger entry
|
||||
mark_settled(payment_hash)
|
||||
|
||||
return is_paid
|
||||
|
||||
def settle_invoice(self, payment_hash: str, preimage: str) -> bool:
|
||||
"""Manually settle an invoice with a preimage (for testing)."""
|
||||
return self._backend.settle_invoice(payment_hash, preimage)
|
||||
"""Manually settle an invoice with a preimage (for testing).
|
||||
|
||||
Also updates the ledger entry.
|
||||
"""
|
||||
result = self._backend.settle_invoice(payment_hash, preimage)
|
||||
|
||||
if result:
|
||||
mark_settled(payment_hash, preimage=preimage)
|
||||
|
||||
return result
|
||||
|
||||
def get_invoice(self, payment_hash: str) -> Optional[Invoice]:
|
||||
"""Get invoice details by payment hash."""
|
||||
@@ -75,6 +127,26 @@ class PaymentHandler:
|
||||
def backend_name(self) -> str:
|
||||
"""Get the name of the current backend."""
|
||||
return self._backend.name
|
||||
|
||||
def get_balance(self) -> dict:
|
||||
"""Get current balance summary from ledger.
|
||||
|
||||
Returns:
|
||||
Dict with incoming, outgoing, pending, and available balances
|
||||
"""
|
||||
return get_balance()
|
||||
|
||||
def list_transactions(self, limit: int = 100, **filters) -> list:
|
||||
"""List transactions from ledger.
|
||||
|
||||
Args:
|
||||
limit: Maximum number of transactions
|
||||
**filters: Optional filters (tx_type, status, task_id, agent_id)
|
||||
|
||||
Returns:
|
||||
List of LedgerEntry objects
|
||||
"""
|
||||
return list_transactions(limit=limit, **filters)
|
||||
|
||||
|
||||
# Module-level singleton
|
||||
|
||||
Reference in New Issue
Block a user