Main daemon event loop.
(self)
| 448 | self._reload_requested = True |
| 449 | |
| 450 | async def _main_loop(self): |
| 451 | """Main daemon event loop.""" |
| 452 | info("Daemon started") |
| 453 | self.state.set("daemon_started_at", int(time.time())) |
| 454 | self.state.log_action("daemon_started", f"PID {os.getpid()}") |
| 455 | |
| 456 | # Start socket server |
| 457 | server_task = asyncio.create_task(self.server.start()) |
| 458 | |
| 459 | # NOTE: We do NOT start executor.start() as a background task. |
| 460 | # The executor's auto-poll loop and _process_planner_tasks both poll the |
| 461 | # same SQLite task_queue, creating a race where the same task could be |
| 462 | # claimed and executed twice. All task dispatch goes through |
| 463 | # _process_planner_tasks, which uses try_claim_task() for atomic claiming. |
| 464 | |
| 465 | # Pre-load 7B model (llama-server on port 8080) so it's ready for CLI |
| 466 | # Skip when using a remote backend — no local server needed |
| 467 | from utils.config import CODEY_BACKEND as _backend, is_remote_backend as _is_remote |
| 468 | if not _is_remote(): |
| 469 | try: |
| 470 | from core.loader_v2 import get_loader |
| 471 | loader = get_loader() |
| 472 | if loader.ensure_model(): |
| 473 | info("7B model pre-loaded (port 8080)") |
| 474 | else: |
| 475 | warning("7B model pre-load failed — will load on first request") |
| 476 | except Exception as _e: |
| 477 | warning(f"7B model pre-load skipped: {_e}") |
| 478 | else: |
| 479 | info(f"Backend: {_backend} — skipping local 7B and 0.5B server startup") |
| 480 | |
| 481 | # Start dedicated embedding server (nomic-embed on port 8082) |
| 482 | try: |
| 483 | from core.embed_server import start_embed_server |
| 484 | if start_embed_server(): |
| 485 | info("Embed server started (port 8082)") |
| 486 | else: |
| 487 | warning("Embed server unavailable — BM25-only KB search active") |
| 488 | except Exception as _e: |
| 489 | warning(f"Embed server startup skipped: {_e}") |
| 490 | |
| 491 | # Start file watch manager |
| 492 | self.file_watch.start() |
| 493 | |
| 494 | _watchdog_ticks = 0 |
| 495 | try: |
| 496 | while self.running: |
| 497 | # Check for reload request |
| 498 | if self._reload_requested: |
| 499 | info("Processing reload...") |
| 500 | self._reload_requested = False |
| 501 | |
| 502 | # Dispatch next ready task (planner queue + direct commands) |
| 503 | await self._process_planner_tasks() |
| 504 | |
| 505 | # Cleanup completed background tasks periodically |
| 506 | self.background.cleanup_completed(max_age=3600) |
| 507 |
no test coverage detected