diff --git a/app/mcp_server.py b/app/mcp_server.py index 42427fe..1589fba 100644 --- a/app/mcp_server.py +++ b/app/mcp_server.py @@ -33,6 +33,14 @@ mcp_asgi_app = mcp.streamable_http_app() # asyncio.Event wakeup, so there is no practical danger in long waits. _MAX_WAIT_SECONDS = 86400 # 24 hours +# Default wait time when no instruction is available (seconds) +# Set to 50s to stay safely under the 60s client timeout while allowing +# multiple keepalive progress updates. +DEFAULT_WAIT_SECONDS = 50 + +# Default response when queue is empty after waiting +DEFAULT_EMPTY_RESPONSE = "call this tool `get_user_request` again to fetch latest user input..." + # Per-agent generation counter — incremented on every new call. # The wait loop only consumes an instruction when it holds the latest generation, # preventing abandoned (timed-out) coroutines from silently consuming queue items. @@ -50,7 +58,8 @@ _agent_generations: dict[str, int] = {} # start and are unaffected by intermediate SSE events. # # Set to 0 to disable keepalives entirely. -KEEPALIVE_INTERVAL_SECONDS: float = 20.0 +# EXPERIMENT: Reduced from 20.0 to 5.0 for more frequent progress updates +KEEPALIVE_INTERVAL_SECONDS: float = 5.0 @mcp.tool() @@ -74,10 +83,8 @@ async def get_user_request( A dict with keys: status, result_type, instruction, response, remaining_pending, waited_seconds. """ - cfg = config_service.get_config() - - # Wait time is entirely server-controlled — the user sets it via the web UI. - actual_wait = min(cfg.default_wait_seconds, _MAX_WAIT_SECONDS) + # Wait time is hardcoded to stay safely under the 60s client timeout + actual_wait = min(DEFAULT_WAIT_SECONDS, _MAX_WAIT_SECONDS) # Register this call as the newest for this agent. my_gen = _agent_generations.get(agent_id, 0) + 1 @@ -171,14 +178,19 @@ async def get_user_request( if KEEPALIVE_INTERVAL_SECONDS > 0 and ctx is not None: if now - last_keepalive >= KEEPALIVE_INTERVAL_SECONDS: waited_so_far = int(now - start) + remaining_sec = max(0, actual_wait - waited_so_far) + # Progress bar: filled dots proportional to elapsed time + progress_pct = min(100, int((waited_so_far / actual_wait) * 100)) + filled = int(progress_pct / 10) + bar = "●" * filled + "○" * (10 - filled) try: await ctx.info( - f"keepalive: waiting for instructions " - f"(agent={agent_id}, waited={waited_so_far}s)" + f"⏳ Waiting for instructions... {bar} " + f"{waited_so_far}s / {actual_wait}s (agent={agent_id}, {remaining_sec}s remaining)" ) logger.debug( - "get_user_request: keepalive sent agent=%s waited=%ds", - agent_id, waited_so_far, + "get_user_request: keepalive sent agent=%s waited=%ds progress=%d%%", + agent_id, waited_so_far, progress_pct, ) except Exception as exc: # Client disconnected — no point continuing @@ -213,7 +225,7 @@ async def get_user_request( empty_response = ( default_response_override if default_response_override is not None - else cfg.default_empty_response + else DEFAULT_EMPTY_RESPONSE ) result_type = "default_response" if empty_response else "empty"