feature: display timer status interactively
This commit is contained in:
@@ -7,6 +7,7 @@ while preserving the goal-driven approach.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
@@ -161,6 +162,8 @@ class AgentRuntime:
|
||||
self._event_subscriptions: list[str] = []
|
||||
# Timer tasks for scheduled entry points
|
||||
self._timer_tasks: list[asyncio.Task] = []
|
||||
# Next fire time for each timer entry point (ep_id -> datetime)
|
||||
self._timer_next_fire: dict[str, float] = {}
|
||||
|
||||
# State
|
||||
self._running = False
|
||||
@@ -331,9 +334,12 @@ class AgentRuntime:
|
||||
|
||||
def _make_timer(entry_point_id: str, mins: float, immediate: bool):
|
||||
async def _timer_loop():
|
||||
interval_secs = mins * 60
|
||||
if not immediate:
|
||||
await asyncio.sleep(mins * 60)
|
||||
self._timer_next_fire[entry_point_id] = time.monotonic() + interval_secs
|
||||
await asyncio.sleep(interval_secs)
|
||||
while self._running:
|
||||
self._timer_next_fire.pop(entry_point_id, None)
|
||||
try:
|
||||
session_state = self._get_primary_session_state(
|
||||
exclude_entry_point=entry_point_id
|
||||
@@ -354,7 +360,8 @@ class AgentRuntime:
|
||||
entry_point_id,
|
||||
exc_info=True,
|
||||
)
|
||||
await asyncio.sleep(mins * 60)
|
||||
self._timer_next_fire[entry_point_id] = time.monotonic() + interval_secs
|
||||
await asyncio.sleep(interval_secs)
|
||||
|
||||
return _timer_loop
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ arrows drawn on the right margin that visually point back up to earlier nodes.
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from textual.app import ComposeResult
|
||||
from textual.containers import Vertical
|
||||
@@ -64,6 +65,9 @@ class GraphOverview(Vertical):
|
||||
def on_mount(self) -> None:
|
||||
"""Display initial graph structure."""
|
||||
self._display_graph()
|
||||
# Refresh every 1s so timer countdowns stay current
|
||||
if self.runtime._timer_next_fire is not None:
|
||||
self.set_interval(1.0, self._display_graph)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Graph analysis helpers
|
||||
@@ -455,7 +459,16 @@ class GraphOverview(Vertical):
|
||||
if ep.trigger_type == "timer":
|
||||
interval = ep.trigger_config.get("interval_minutes", "?")
|
||||
display.write(f" [green]⏱[/green] {ep.name} [dim]→ {ep.entry_node}[/dim]")
|
||||
display.write(f" [dim]every {interval} min[/dim]")
|
||||
# Show interval + next fire countdown
|
||||
next_fire = self.runtime._timer_next_fire.get(ep.id)
|
||||
if next_fire is not None:
|
||||
remaining = max(0, next_fire - time.monotonic())
|
||||
mins, secs = divmod(int(remaining), 60)
|
||||
display.write(
|
||||
f" [dim]every {interval} min — next in {mins}m {secs:02d}s[/dim]"
|
||||
)
|
||||
else:
|
||||
display.write(f" [dim]every {interval} min[/dim]")
|
||||
|
||||
elif ep.trigger_type in ("event", "webhook"):
|
||||
display.write(f" [yellow]⚡[/yellow] {ep.name} [dim]→ {ep.entry_node}[/dim]")
|
||||
|
||||
Reference in New Issue
Block a user