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.
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
"""SwarmNode — a single agent's view of the swarm.
|
|
|
|
A SwarmNode registers itself in the SQLite registry, listens for tasks
|
|
via the comms layer, and submits bids through the auction system.
|
|
Used by agent_runner.py when a sub-agent process is spawned.
|
|
"""
|
|
|
|
import logging
|
|
import random
|
|
from typing import Optional
|
|
|
|
from swarm import registry
|
|
from swarm.comms import CHANNEL_TASKS, SwarmComms, SwarmMessage
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SwarmNode:
|
|
"""Represents a single agent participating in the swarm."""
|
|
|
|
def __init__(
|
|
self,
|
|
agent_id: str,
|
|
name: str,
|
|
capabilities: str = "",
|
|
comms: Optional[SwarmComms] = None,
|
|
) -> None:
|
|
self.agent_id = agent_id
|
|
self.name = name
|
|
self.capabilities = capabilities
|
|
self._comms = comms or SwarmComms()
|
|
self._joined = False
|
|
|
|
async def join(self) -> None:
|
|
"""Register with the swarm and start listening for tasks."""
|
|
registry.register(
|
|
name=self.name,
|
|
capabilities=self.capabilities,
|
|
agent_id=self.agent_id,
|
|
)
|
|
self._comms.subscribe(CHANNEL_TASKS, self._on_task_posted)
|
|
self._joined = True
|
|
logger.info("SwarmNode %s (%s) joined the swarm", self.name, self.agent_id)
|
|
|
|
async def leave(self) -> None:
|
|
"""Unregister from the swarm."""
|
|
registry.update_status(self.agent_id, "offline")
|
|
self._joined = False
|
|
logger.info("SwarmNode %s (%s) left the swarm", self.name, self.agent_id)
|
|
|
|
def _on_task_posted(self, msg: SwarmMessage) -> None:
|
|
"""Handle an incoming task announcement by submitting a bid."""
|
|
task_id = msg.data.get("task_id")
|
|
if not task_id:
|
|
return
|
|
# Simple bidding strategy: random bid between 10 and 100 sats
|
|
bid_sats = random.randint(10, 100)
|
|
self._comms.submit_bid(
|
|
task_id=task_id,
|
|
agent_id=self.agent_id,
|
|
bid_sats=bid_sats,
|
|
)
|
|
logger.info(
|
|
"SwarmNode %s bid %d sats on task %s",
|
|
self.name, bid_sats, task_id,
|
|
)
|
|
|
|
@property
|
|
def is_joined(self) -> bool:
|
|
return self._joined
|