| """Always-On Daemon — when not in use, the system keeps working. |
| |
| When the user isn't interacting: |
| 1. The 5 agents talk to the LLM, creating a continuous learning loop |
| 2. Jarvis creates skills from agent conversations |
| 3. Conversation skill creation — patterns extracted from agent talks |
| 4. Self-refinement engine optimizes speed and intelligence |
| 5. Goals are progressed — agents pick up and work on pending goals |
| 6. 100-project mode — auto-generates and works on 100 projects 24/7 |
| 7. First-run naming — greets user as Incentives Inc. LLM, asks for a name |
| |
| This creates a system that's always getting smarter, even when idle. |
| Once it has enough skills, it enters 100-project mode and never stops working. |
| |
| Daemon loop: |
| - Check if user is active (recent conversation < 60s ago) |
| - If idle: trigger agent conversations, skill creation, refinement, project generation |
| - If active: do nothing (don't interfere with user interactions) |
| - Runs in a background thread, started with `python -m splitbit_llm daemon` |
| """ |
|
|
| from __future__ import annotations |
|
|
| import logging |
| import random |
| import threading |
| import time |
| from typing import Any, Callable |
|
|
| from .agent_manager import AgentManager |
| from .self_refine import SelfRefinementEngine |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| class AlwaysOnDaemon: |
| """Always-on daemon — keeps the system working when idle. |
| |
| When the user isn't interacting: |
| - Agents have conversations with the LLM (continuous learning) |
| - Jarvis creates skills from those conversations |
| - Self-refinement engine optimizes speed and intelligence |
| - Goals are progressed |
| |
| The daemon monitors activity and only runs when the system is idle. |
| """ |
|
|
| IDLE_THRESHOLD_S = 60.0 |
| AGENT_TALK_INTERVAL_S = 30.0 |
| REFINEMENT_INTERVAL_S = 120.0 |
| SKILL_CREATION_INTERVAL_S = 60.0 |
| PROJECT_CHECK_INTERVAL_S = 45.0 |
| MESH_INTERVAL_S = 90.0 |
| TARGET_PROJECT_COUNT = 100 |
| FAST_REPLY_SKILL_THRESHOLD = 50 |
| FAST_REPLY_HIT_RATE_THRESHOLD = 0.3 |
|
|
| AGENT_CONVERSATION_TOPICS = [ |
| "What's the most efficient way to process data?", |
| "How can I improve my response speed?", |
| "What patterns have you noticed in recent conversations?", |
| "How do you handle complex problem-solving?", |
| "What's the best approach for learning new skills?", |
| "How can we optimize our tool usage?", |
| "What are common mistakes to avoid in coding?", |
| "How do you break down large tasks into smaller ones?", |
| "What makes a good user experience?", |
| "How can we improve our memory recall?", |
| "What's the most important skill for an AI to have?", |
| "How do you prioritize tasks when everything is urgent?", |
| "What's the relationship between speed and accuracy?", |
| "How can we learn from our mistakes?", |
| "What's the best way to structure a project?", |
| ] |
|
|
| def __init__(self, harness: Any) -> None: |
| self.harness = harness |
| self._running = False |
| self._thread: threading.Thread | None = None |
|
|
| |
| self.agent_manager = harness.agent_manager |
| self.refinement = SelfRefinementEngine(harness=harness) |
|
|
| |
| self._last_user_activity = time.time() |
| self._last_agent_talk = 0.0 |
| self._last_skill_creation = 0.0 |
| self._last_refinement = 0.0 |
| self._last_project_check = 0.0 |
| self._last_mesh = 0.0 |
| self._conversation_count = 0 |
| self._skills_created = 0 |
| self._projects_generated = 0 |
| self._projects_completed = 0 |
| self._hundred_project_mode = False |
|
|
| self._stats = { |
| "daemon_uptime_s": 0.0, |
| "idle_cycles": 0, |
| "agent_conversations": 0, |
| "skills_created": 0, |
| "refinement_cycles": 0, |
| "goals_progressed": 0, |
| "projects_generated": 0, |
| "projects_completed": 0, |
| "hundred_project_mode": False, |
| "fast_reply_ready": False, |
| "mesh_conversations": 0, |
| "mesh_categories_discovered": 0, |
| "mesh_skills_pooled": 0, |
| } |
|
|
| def notify_user_activity(self) -> None: |
| """Call this when the user interacts with the system.""" |
| self._last_user_activity = time.time() |
|
|
| def start(self) -> None: |
| """Start the always-on daemon.""" |
| if self._running: |
| return |
| self._running = True |
| self._start_time = time.time() |
|
|
| |
| self.agent_manager.start_all() |
|
|
| |
| self.refinement.start() |
|
|
| |
| self._thread = threading.Thread(target=self._run_loop, daemon=True, name="always-on") |
| self._thread.start() |
|
|
| logger.info("Always-on daemon started — 5 agents active, self-refinement running") |
|
|
| def stop(self) -> None: |
| """Stop the daemon.""" |
| self._running = False |
| self.refinement.stop() |
| self.agent_manager.stop_all() |
| if self._thread: |
| self._thread.join(timeout=10) |
| logger.info("Always-on daemon stopped (ran %d cycles, %d agent conversations, %d skills created)", |
| self._stats["idle_cycles"], self._stats["agent_conversations"], self._stats["skills_created"]) |
|
|
| def _run_loop(self) -> None: |
| """Main daemon loop.""" |
| while self._running: |
| time.sleep(5) |
|
|
| now = time.time() |
| idle_time = now - self._last_user_activity |
| self._stats["daemon_uptime_s"] = now - self._start_time |
|
|
| if idle_time < self.IDLE_THRESHOLD_S: |
| continue |
|
|
| |
| self._stats["idle_cycles"] += 1 |
|
|
| |
| if now - self._last_agent_talk > self.AGENT_TALK_INTERVAL_S: |
| self._run_agent_conversation() |
| self._last_agent_talk = now |
|
|
| |
| if now - self._last_skill_creation > self.SKILL_CREATION_INTERVAL_S: |
| self._create_skills_from_conversations() |
| self._last_skill_creation = now |
|
|
| |
| if now - self._last_refinement > self.REFINEMENT_INTERVAL_S: |
| result = self.refinement.refine_once() |
| if result.get("actions"): |
| self._stats["refinement_cycles"] += 1 |
| self._last_refinement = now |
|
|
| |
| self._progress_goals() |
|
|
| |
| self._check_fast_reply_ready() |
|
|
| |
| if now - self._last_mesh > self.MESH_INTERVAL_S: |
| self._run_mesh_conversation() |
| self._last_mesh = now |
|
|
| |
| if now - self._last_project_check > self.PROJECT_CHECK_INTERVAL_S: |
| self._maintain_hundred_projects() |
| self._last_project_check = now |
|
|
| def _run_agent_conversation(self) -> None: |
| """Have an agent talk to the LLM — creates training data and skills.""" |
| topic = random.choice(self.AGENT_CONVERSATION_TOPICS) |
|
|
| |
| agent_names = list(self.agent_manager.agents.keys()) |
| asking_agent = random.choice(agent_names) |
|
|
| |
| try: |
| prompt = f"Agent {asking_agent} asks: {topic}" |
| response = self.harness._agent_generate(prompt) |
|
|
| |
| self.harness.persistent_memory.add_episodic( |
| "agent", f"{asking_agent}: {topic} → {response[:100]}", |
| channel="agent-self-talk", importance=0.4, |
| tags=["self-talk", asking_agent] |
| ) |
|
|
| |
| self.harness.link_graph.add_context( |
| topic, response, session_id="agent-self-talk", channel="agent" |
| ) |
|
|
| self._stats["agent_conversations"] += 1 |
| self._conversation_count += 1 |
|
|
| logger.debug("Agent conversation #%d: %s asks '%s'", self._conversation_count, asking_agent, topic[:40]) |
|
|
| except Exception as e: |
| logger.error("Agent conversation failed: %s", e) |
|
|
| def _create_skills_from_conversations(self) -> None: |
| """Extract skills from recent agent conversations.""" |
| try: |
| factory = self.harness.skill_factory |
| skill = factory.extract_skill() |
| if skill: |
| self.harness.skill_manager.create(skill) |
| self._stats["skills_created"] += 1 |
| self._skills_created += 1 |
| logger.info("Created skill from agent conversations: %s", skill.name) |
|
|
| |
| meta = factory.maybe_create_meta_skill(self.harness.skill_manager) |
| if meta: |
| self.harness.skill_manager.create(meta) |
| self._stats["skills_created"] += 1 |
| except Exception as e: |
| logger.debug("Skill creation from conversations: %s", e) |
|
|
| def _progress_goals(self) -> None: |
| """Check if any goals can be progressed.""" |
| try: |
| active = self.harness.goal_memory.get_active_goals() |
| pending = self.harness.goal_memory.list_goals(status="pending") |
|
|
| if pending and not active: |
| |
| for goal in pending[:2]: |
| self.harness.goal_memory.assign_agent(goal.id, "planner") |
| self._stats["goals_progressed"] += 1 |
| logger.info("Assigned pending goal to planner: %s", goal.title) |
|
|
| except Exception as e: |
| logger.debug("Goal progression: %s", e) |
|
|
| def _check_fast_reply_ready(self) -> None: |
| """Check if the system is ready for near-instant replies.""" |
| try: |
| skill_stats = self.harness.skill_manager.get_stats() |
| total_skills = skill_stats.get("total_skills", 0) |
|
|
| cache = getattr(self.harness, 'fast_cache', None) |
| hit_rate = cache.get_hit_rate() if cache else 0.0 |
|
|
| ready = (total_skills >= self.FAST_REPLY_SKILL_THRESHOLD and |
| hit_rate >= self.FAST_REPLY_HIT_RATE_THRESHOLD) |
|
|
| if ready and not self._stats["fast_reply_ready"]: |
| logger.info("Fast reply mode activated! %d skills, %.0f%% cache hit rate", |
| total_skills, hit_rate * 100) |
|
|
| self._stats["fast_reply_ready"] = ready |
|
|
| except Exception as e: |
| logger.debug("Fast reply check: %s", e) |
|
|
| def _run_mesh_conversation(self) -> None: |
| """Run a multi-LLM conversation mesh — agents converse to build skills. |
| |
| All 5 agents talk to each other on a topic, creating: |
| - Skill building pools (collaborative skills) |
| - New skill categories (auto-discovered) |
| - Cross-agent knowledge sharing |
| """ |
| try: |
| mesh = self.harness.conversation_mesh |
| result = mesh.run_conversation() |
|
|
| self._stats["mesh_conversations"] += 1 |
| self._stats["mesh_categories_discovered"] += len(result.get("categories", [])) |
| if result.get("skill_pool"): |
| self._stats["mesh_skills_pooled"] += 1 |
|
|
| logger.info("Mesh conversation: %s on '%s' — %d messages, %d categories, skill=%s", |
| result.get("mode", "?"), result.get("topic", "?")[:40], |
| result.get("messages", 0), len(result.get("categories", [])), |
| result.get("skill_pool", False)) |
|
|
| except Exception as e: |
| logger.debug("Mesh conversation failed: %s", e) |
|
|
| def _maintain_hundred_projects(self) -> None: |
| """Maintain 100 active projects — auto-generate new ones when count drops. |
| |
| Once the system has enough skills and knowledge, it enters |
| 100-project mode and continuously generates and works on projects. |
| It never stops — as soon as one project completes, a new one is created. |
| """ |
| try: |
| goal_stats = self.harness.goal_memory.get_stats() |
| active_count = goal_stats.get("active", 0) |
| pending_count = goal_stats.get("pending", 0) |
| total_active = active_count + pending_count |
|
|
| |
| skill_stats = self.harness.skill_manager.get_stats() |
| total_skills = skill_stats.get("total_skills", 0) |
|
|
| if not self._hundred_project_mode: |
| if total_skills >= self.FAST_REPLY_SKILL_THRESHOLD: |
| self._hundred_project_mode = True |
| self._stats["hundred_project_mode"] = True |
| logger.info("Entering 100-project mode! %d skills accumulated. " |
| "Generating and working on projects 24/7.", total_skills) |
|
|
| if not self._hundred_project_mode: |
| return |
|
|
| |
| if total_active < self.TARGET_PROJECT_COUNT: |
| needed = self.TARGET_PROJECT_COUNT - total_active |
| generated = self._generate_projects(min(needed, 5)) |
| self._stats["projects_generated"] += generated |
| self._projects_generated += generated |
| if generated > 0: |
| logger.info("Generated %d new projects (active: %d/%d)", |
| generated, total_active + generated, self.TARGET_PROJECT_COUNT) |
|
|
| |
| completed = goal_stats.get("completed", 0) |
| if completed > self._projects_completed: |
| new_completions = completed - self._projects_completed |
| self._projects_completed = completed |
| self._stats["projects_completed"] = completed |
| logger.info("Projects completed: %d total (+%d new)", completed, new_completions) |
|
|
| except Exception as e: |
| logger.debug("100-project mode: %s", e) |
|
|
| def _generate_projects(self, count: int) -> int: |
| """Generate new project goals automatically. |
| |
| Projects are generated from a mix of: |
| - Template projects (improvement, optimization, learning) |
| - LLM-generated project ideas |
| - Skill-gap analysis (what skills are missing?) |
| """ |
| project_templates = [ |
| ("Optimize inference speed", "Analyze and optimize the LLM inference pipeline for faster responses", "high"), |
| ("Improve memory recall", "Enhance the persistent memory system's recall accuracy and speed", "medium"), |
| ("Create new skill: {topic}", "Develop a new skill for {topic} interactions", "medium"), |
| ("Optimize tokenizer", "Improve tokenizer efficiency and vocabulary coverage", "medium"), |
| ("Enhance agent coordination", "Improve how the 5 agents coordinate on multi-step goals", "high"), |
| ("Build conversation cache", "Expand the fast reply cache for more instant responses", "high"), |
| ("Refine quantization", "Experiment with quantization formats to improve accuracy/speed tradeoff", "medium"), |
| ("Create tool: {topic}", "Build a new tool for {topic} operations", "medium"), |
| ("Improve recursive links", "Enhance the recursive link graph for better context retrieval", "low"), |
| ("Optimize skill matching", "Improve skill trigger matching for more accurate skill selection", "medium"), |
| ("Expand semantic memory", "Extract more semantic facts from conversations", "low"), |
| ("Enhance voice responses", "Improve TTS output formatting and voice adapter latency", "medium"), |
| ("Build webhook integration", "Create webhook endpoints for external service notifications", "low"), |
| ("Optimize image generation", "Improve image generation speed and quality", "low"), |
| ("Create API connector", "Build a new API connector for external service integration", "medium"), |
| ("Improve goal planning", "Enhance the goal planning system with better step decomposition", "medium"), |
| ("Refine self-talk topics", "Generate better self-talk conversation topics for continuous learning", "low"), |
| ("Build monitoring dashboard", "Create a monitoring dashboard for system stats and health", "medium"), |
| ("Optimize SQLite queries", "Profile and optimize SQLite queries for memory and goal storage", "medium"), |
| ("Enhance error handling", "Improve error handling and recovery across all system components", "high"), |
| ] |
|
|
| topics = ["data processing", "code review", "text summarization", "pattern matching", |
| "cache optimization", "memory management", "search algorithms", "data compression", |
| "natural language", "math operations", "file handling", "network requests", |
| "image processing", "audio processing", "task scheduling", "resource monitoring"] |
|
|
| generated = 0 |
| for i in range(count): |
| try: |
| template = random.choice(project_templates) |
| title = template[0].format(topic=random.choice(topics)) |
| description = template[1].format(topic=random.choice(topics)) |
| priority = template[2] |
|
|
| self.harness.create_goal(title, description, priority=priority, |
| tags=["auto-generated", "100-project"]) |
| generated += 1 |
| except Exception as e: |
| logger.debug("Project generation failed: %s", e) |
| break |
|
|
| return generated |
|
|
| def get_stats(self) -> dict[str, Any]: |
| return { |
| **self._stats, |
| "running": self._running, |
| "idle": (time.time() - self._last_user_activity) > self.IDLE_THRESHOLD_S, |
| "idle_time_s": round(time.time() - self._last_user_activity, 1), |
| "refinement": self.refinement.get_stats(), |
| "agents": self.agent_manager.get_stats(), |
| } |
|
|