Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/prime_agent_client/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,16 @@ async def prompt_stream(
) -> AsyncIterator[PrimeEvent]:
stream = self.events()
timeout_seconds = self.prompt_timeout if timeout is None else float(timeout)
deadline = asyncio.get_running_loop().time() + timeout_seconds
try:
await self.prompt(message, images=images)
while True:
try:
remaining = deadline - asyncio.get_running_loop().time()
if remaining <= 0:
raise asyncio.TimeoutError
event = await asyncio.wait_for(stream.__anext__(), timeout=remaining)
# Agent turns can legitimately run for hours. Treat the prompt
# timeout as an inactivity limit, not a wall-clock deadline, so
# a live event stream is never aborted merely for being long.
event = await asyncio.wait_for(
stream.__anext__(), timeout=timeout_seconds
)
except asyncio.TimeoutError as exc:
with contextlib.suppress(Exception):
await self.abort()
Expand Down
8 changes: 8 additions & 0 deletions tests/fixtures/fake_prime_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import json
import os
import sys
import time
from typing import Any


Expand Down Expand Up @@ -87,6 +88,13 @@ def emit(payload: dict[str, Any]) -> None:
if command == "prompt":
if request.get("message") == "stall":
continue
if request.get("message") == "active-beyond-timeout":
emit({"type": "agent_start"})
for index in range(3):
time.sleep(0.03)
emit({"type": "progress", "index": index})
emit({"type": "agent_end"})
continue
if request.get("message") == "ui":
waiting_for_ui = True
emit({"type": "extension_ui_request", "id": "ui-1", "method": "confirm"})
Expand Down
13 changes: 13 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,16 @@ async def test_prompt_stream_timeout_aborts_the_active_run() -> None:
await session.prompt_and_wait("stall")

assert raised.value.command == "prompt_events"


async def test_prompt_stream_timeout_measures_inactivity_not_total_runtime() -> None:
async with PrimeSession(command=FAKE_COMMAND, prompt_timeout=0.05) as session:
events = await session.prompt_and_wait("active-beyond-timeout")

assert [event.type for event in events] == [
"agent_start",
"progress",
"progress",
"progress",
"agent_end",
]