fix: pause thought counter during idle periods (#319)

Co-authored-by: Kimi Agent <kimi@timmy.local>
Co-committed-by: Kimi Agent <kimi@timmy.local>
This commit is contained in:
2026-03-18 19:12:14 -04:00
committed by hermes
parent 9a21a4b0ff
commit 8ef0ad1778
4 changed files with 37 additions and 0 deletions

View File

@@ -245,6 +245,7 @@ class Settings(BaseSettings):
thinking_distill_every: int = 10 # distill facts from thoughts every Nth thought
thinking_issue_every: int = 20 # file Gitea issues from thoughts every Nth thought
thinking_memory_check_every: int = 50 # check memory status every Nth thought
thinking_idle_timeout_minutes: int = 60 # pause thoughts after N minutes without user input
# ── Gitea Integration ─────────────────────────────────────────────
# Local Gitea instance for issue tracking and self-improvement.

View File

@@ -85,6 +85,14 @@ async def chat_agent(request: Request, message: str = Form(...)):
raise HTTPException(status_code=422, detail="Message too long")
# Record user activity so the thinking engine knows we're not idle
try:
from timmy.thinking import thinking_engine
thinking_engine.record_user_input()
except Exception:
pass
timestamp = datetime.now().strftime("%H:%M:%S")
response_text = None
error_text = None

View File

@@ -79,6 +79,14 @@ async def api_chat(request: Request):
if not last_user_msg:
return JSONResponse(status_code=400, content={"error": "No user message found"})
# Record user activity so the thinking engine knows we're not idle
try:
from timmy.thinking import thinking_engine
thinking_engine.record_user_input()
except Exception:
pass
timestamp = datetime.now().strftime("%H:%M:%S")
try:

View File

@@ -210,6 +210,7 @@ class ThinkingEngine:
def __init__(self, db_path: Path = _DEFAULT_DB) -> None:
self._db_path = db_path
self._last_thought_id: str | None = None
self._last_input_time: datetime = datetime.now(UTC)
# Load the most recent thought for chain continuity
try:
@@ -220,6 +221,17 @@ class ThinkingEngine:
logger.debug("Failed to load recent thought: %s", exc)
pass # Fresh start if DB doesn't exist yet
def record_user_input(self) -> None:
"""Record that a user interaction occurred, resetting the idle timer."""
self._last_input_time = datetime.now(UTC)
def _is_idle(self) -> bool:
"""Return True if no user input has occurred within the idle timeout."""
timeout = settings.thinking_idle_timeout_minutes
if timeout <= 0:
return False # Disabled — never idle
return datetime.now(UTC) - self._last_input_time > timedelta(minutes=timeout)
async def think_once(self, prompt: str | None = None) -> Thought | None:
"""Execute one thinking cycle.
@@ -237,6 +249,14 @@ class ThinkingEngine:
if not settings.thinking_enabled:
return None
# Skip idle periods — don't count internal processing as thoughts
if not prompt and self._is_idle():
logger.debug(
"Thinking paused — no user input for %d minutes",
settings.thinking_idle_timeout_minutes,
)
return None
memory_context = self._load_memory_context()
system_context = self._gather_system_snapshot()
recent_thoughts = self.get_recent_thoughts(limit=5)