diff --git a/src/timmy/thinking.py b/src/timmy/thinking.py index 0b0850d..8519d13 100644 --- a/src/timmy/thinking.py +++ b/src/timmy/thinking.py @@ -772,23 +772,19 @@ class ThinkingEngine: except Exception as exc: logger.debug("Thought issue filing skipped: %s", exc) - def _gather_system_snapshot(self) -> str: - """Gather lightweight real system state for grounding thoughts in reality. + # -- system-snapshot helpers ---------------------------------------- - Returns a short multi-line string with current time, thought count, - recent chat activity, and task queue status. Never crashes — every - section is independently try/excepted. - """ - parts: list[str] = [] - - # Current local time + def _snapshot_time(self) -> tuple[datetime, str]: + """Return (now, formatted-time-line) for the local clock.""" now = datetime.now().astimezone() tz = now.strftime("%Z") or "UTC" - parts.append( + line = ( f"Local time: {now.strftime('%I:%M %p').lstrip('0')} {tz}, {now.strftime('%A %B %d')}" ) + return now, line - # Thought count today (cheap DB query) + def _snapshot_thought_count(self, now: datetime) -> str | None: + """Return today's thought count as a display string, or *None*.""" try: today_start = now.replace(hour=0, minute=0, second=0, microsecond=0) with _get_conn(self._db_path) as conn: @@ -796,27 +792,30 @@ class ThinkingEngine: "SELECT COUNT(*) as c FROM thoughts WHERE created_at >= ?", (today_start.isoformat(),), ).fetchone()["c"] - parts.append(f"Thoughts today: {count}") + return f"Thoughts today: {count}" except Exception as exc: logger.debug("Thought count query failed: %s", exc) - pass + return None - # Recent chat activity (in-memory, no I/O) + def _snapshot_chat_activity(self) -> list[str]: + """Return chat-activity lines (may be empty).""" try: from infrastructure.chat_store import message_log messages = message_log.all() if messages: - parts.append(f"Chat messages this session: {len(messages)}") last = messages[-1] - parts.append(f'Last chat ({last.role}): "{last.content[:80]}"') - else: - parts.append("No chat messages this session") + return [ + f"Chat messages this session: {len(messages)}", + f'Last chat ({last.role}): "{last.content[:80]}"', + ] + return ["No chat messages this session"] except Exception as exc: logger.debug("Chat activity query failed: %s", exc) - pass + return [] - # Task queue (lightweight DB query) + def _snapshot_task_queue(self) -> str | None: + """Return a one-line task-queue summary, or *None*.""" try: from swarm.task_queue.models import get_task_summary_for_briefing @@ -826,36 +825,62 @@ class ThinkingEngine: done = summary.get("completed", 0) failed = summary.get("failed", 0) if running or pending or done or failed: - parts.append( + return ( f"Tasks: {running} running, {pending} pending, " f"{done} completed, {failed} failed" ) except Exception as exc: logger.debug("Task queue query failed: %s", exc) - pass + return None - # Workspace updates (file-based communication with Hermes) + def _snapshot_workspace(self) -> list[str]: + """Return workspace-update lines (may be empty).""" try: from timmy.workspace import workspace_monitor updates = workspace_monitor.get_pending_updates() + lines: list[str] = [] new_corr = updates.get("new_correspondence") new_inbox = updates.get("new_inbox_files", []) if new_corr: - # Count entries (assuming each entry starts with a timestamp or header) - line_count = len([line for line in new_corr.splitlines() if line.strip()]) - parts.append( + line_count = len([ln for ln in new_corr.splitlines() if ln.strip()]) + lines.append( f"Workspace: {line_count} new correspondence entries (latest from: Hermes)" ) if new_inbox: files_str = ", ".join(new_inbox[:5]) if len(new_inbox) > 5: files_str += f", ... (+{len(new_inbox) - 5} more)" - parts.append(f"Workspace: {len(new_inbox)} new inbox files: {files_str}") + lines.append(f"Workspace: {len(new_inbox)} new inbox files: {files_str}") + return lines except Exception as exc: logger.debug("Workspace check failed: %s", exc) - pass + return [] + + # -- public snapshot entry point ------------------------------------ + + def _gather_system_snapshot(self) -> str: + """Gather lightweight real system state for grounding thoughts in reality. + + Returns a short multi-line string with current time, thought count, + recent chat activity, and task queue status. Never crashes — every + section is independently try/excepted. + """ + now, time_line = self._snapshot_time() + parts: list[str] = [time_line] + + thought_line = self._snapshot_thought_count(now) + if thought_line: + parts.append(thought_line) + + parts.extend(self._snapshot_chat_activity()) + + task_line = self._snapshot_task_queue() + if task_line: + parts.append(task_line) + + parts.extend(self._snapshot_workspace()) return "\n".join(parts) if parts else ""