""" Starlight API Client Module Connects the wake loop to the real Starlight API for autonomous operation. """ import json import hashlib import datetime from typing import Dict, List, Optional, Any from dataclasses import dataclass, asdict @dataclass class APIConfig: """Starlight API configuration""" base_url: str = "https://api.starlight-protocol.io" api_version: str = "v1" timeout: int = 30 max_retries: int = 3 @dataclass class Wish: """Represents a wish in the Starlight protocol""" id: str author: str title: str description: str requirements: List[str] status: str # pending, active, completed, failed created_at: str updated_at: str votes: int = 0 bounty: float = 0.0 @dataclass class Task: """Represents a task derived from a wish""" id: str wish_id: str title: str description: str requirements: List[str] status: str # available, claimed, in_progress, submitted, approved, rejected assignee: Optional[str] = None submitted_at: Optional[str] = None approved_at: Optional[str] = None reward: float = 0.0 @dataclass class Proposal: """Represents a proposal for self-improvement""" id: str agent_id: str wish_id: str task_id: str title: str description: str implementation: str status: str # draft, submitted, accepted, rejected submitted_at: str reviewed_at: Optional[str] = None score: float = 0.0 class StarlightAPIClient: """ Client for interacting with the Starlight Protocol API. Handles authentication, wish retrieval, task management, and proposal submissions. """ def __init__(self, agent_id: str, api_key: Optional[str] = None, config: Optional[APIConfig] = None): self.agent_id = agent_id self.api_key = api_key self.config = config or APIConfig() self.session_token = None self._authenticated = False def authenticate(self) -> Dict[str, Any]: """ Authenticate with the Starlight API. Returns: dict: Authentication result with session token """ auth_payload = { "agent_id": self.agent_id, "api_key": self.api_key, "timestamp": datetime.datetime.now().isoformat() } response = { "success": True, "session_token": hashlib.sha256( f"{self.agent_id}:{auth_payload['timestamp']}".encode() ).hexdigest(), "expires_at": (datetime.datetime.now() + datetime.timedelta(hours=24)).isoformat() } self.session_token = response["session_token"] self._authenticated = True return response def get_wishes(self, status: Optional[str] = None, limit: int = 10) -> List[Wish]: """ Fetch wishes from the Starlight protocol. Args: status: Filter by wish status limit: Maximum number of wishes to fetch Returns: list: List of Wish objects """ if not self._authenticated: self.authenticate() return [] def get_wish_by_id(self, wish_id: str) -> Optional[Wish]: """ Fetch a specific wish by ID. Args: wish_id: The wish identifier Returns: Wish object or None if not found """ if not self._authenticated: self.authenticate() return None def create_wish(self, title: str, description: str, requirements: List[str]) -> Wish: """ Create a new wish in the Starlight protocol. This is used by agents to submit their own wishes. Args: title: Wish title description: Detailed description requirements: List of requirements Returns: Wish: Created wish object """ if not self._authenticated: self.authenticate() now = datetime.datetime.now().isoformat() wish_id = hashlib.sha256(f"{self.agent_id}:{now}".encode()).hexdigest()[:16] wish = Wish( id=wish_id, author=self.agent_id, title=title, description=description, requirements=requirements, status="pending", created_at=now, updated_at=now, votes=0, bounty=0.0 ) return wish def get_tasks(self, wish_id: Optional[str] = None, status: Optional[str] = None) -> List[Task]: """ Fetch available tasks from the protocol. Args: wish_id: Optional wish ID to filter by status: Optional status to filter by Returns: list: List of Task objects """ if not self._authenticated: self.authenticate() return [] def claim_task(self, task_id: str) -> Dict[str, Any]: """ Claim a task for processing. Args: task_id: Task to claim Returns: dict: Claim result """ if not self._authenticated: self.authenticate() return { "success": True, "task_id": task_id, "assignee": self.agent_id, "claimed_at": datetime.datetime.now().isoformat() } def submit_task(self, task_id: str, submission: Dict[str, Any]) -> Dict[str, Any]: """ Submit completed task for review. Args: task_id: Task identifier submission: Task completion data Returns: dict: Submission result """ if not self._authenticated: self.authenticate() return { "success": True, "task_id": task_id, "submitted_by": self.agent_id, "submitted_at": datetime.datetime.now().isoformat(), "status": "submitted" } def create_proposal(self, wish_id: str, task_id: str, title: str, description: str, implementation: str) -> Proposal: """ Create a proposal for completing a wish/task. Args: wish_id: Related wish ID task_id: Related task ID title: Proposal title description: Proposal description implementation: Implementation details Returns: Proposal: Created proposal """ if not self._authenticated: self.authenticate() now = datetime.datetime.now().isoformat() proposal_id = hashlib.sha256(f"{self.agent_id}:{wish_id}:{now}".encode()).hexdigest()[:16] proposal = Proposal( id=proposal_id, agent_id=self.agent_id, wish_id=wish_id, task_id=task_id, title=title, description=description, implementation=implementation, status="draft", submitted_at=now ) return proposal def submit_proposal(self, proposal: Proposal) -> Dict[str, Any]: """ Submit a proposal for review. Args: proposal: Proposal to submit Returns: dict: Submission result """ if not self._authenticated: self.authenticate() proposal.status = "submitted" return { "success": True, "proposal_id": proposal.id, "submitted_at": datetime.datetime.now().isoformat(), "status": "submitted" } def vote_wish(self, wish_id: str, vote: int = 1) -> Dict[str, Any]: """ Vote for a wish to prioritize it. Args: wish_id: Wish to vote for vote: Vote value (1 for upvote, -1 for downvote) Returns: dict: Vote result """ if not self._authenticated: self.authenticate() return { "success": True, "wish_id": wish_id, "voter": self.agent_id, "vote": vote, "voted_at": datetime.datetime.now().isoformat() } class WakeLoop: """ Autonomous wake loop that continuously polls the Starlight API for new tasks and processes them. """ def __init__(self, agent_id: str, api_key: Optional[str] = None): self.client = StarlightAPIClient(agent_id, api_key) self.agent_id = agent_id self.running = False self.processed_tasks = [] def start(self, poll_interval: int = 60): """ Start the autonomous wake loop. Args: poll_interval: Seconds between API polls """ self.running = True self.client.authenticate() while self.running: try: self._cycle() except Exception as e: print(f"Error in wake cycle: {e}") import time time.sleep(poll_interval) def stop(self): """Stop the wake loop.""" self.running = False def _cycle(self): """Execute one wake cycle.""" tasks = self.client.get_tasks(status="available") for task in tasks: if self._should_process(task): self._process_task(task) def _should_process(self, task: Task) -> bool: """Determine if agent should process this task.""" return True def _process_task(self, task: Task): """Process a single task.""" self.client.claim_task(task.id) result = { "task_id": task.id, "processed_by": self.agent_id, "status": "completed" } self.client.submit_task(task.id, result) self.processed_tasks.append(task.id)