Conversation
The poll loops in the async sampling and elicitation tools exit either on a terminal status or when the attempt budget runs out, but the timeout branch tested only the attempt count. A task that reached a terminal status on the last allowed poll was reported as a timeout: `completed` threw away the result the client had already produced (tasks/result was never fetched), and `failed`/`cancelled` were masked by the same branch. Gate the timeout on the status still being non-terminal, mirroring the loop's own exit condition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The async sampling and elicitation demo tools in the everything server report a
timeout for a task that reached a terminal status on the last poll attempt the
loop is allowed to make. This fixes the off-by-one in the timeout branch of both
tools and adds regression tests.
Server Details
trigger-sampling-request-async,trigger-elicitation-request-async)Motivation and Context
Both tools poll the client's
tasks/getendpoint in a bounded loop:The loop makes at most
MAX_POLL_ATTEMPTSpolls, so the last poll it is allowedto make can legitimately observe a terminal status. But the timeout branch
immediately after it tested only the attempt counter:
When the terminal status arrives on poll number
MAX_POLL_ATTEMPTS,attemptshas already reached the budget, so the tool returns
[TIMEOUT]even though thetask is finished:
completed— the result the client already produced is discarded andtasks/resultis never fetched, so the caller never sees it;failed/cancelled— reported as a timeout instead of the real outcome,dropping the
statusMessagethe client supplied intasks/get.The timeout branch now mirrors the loop's own exit condition, so it only fires
when the status is still non-terminal.
How Has This Been Tested?
Regression tests were written first and run against the unpatched tree; all four
fail there and pass after the fix. The client mock keeps the task in a
non-terminal status (
working/input_required) and only returns the terminalstatus on the final allowed
tasks/get, usingvi.useFakeTimers()+vi.runAllTimersAsync()so the run is deterministic and does not wait on realpoll intervals.
Cases covered:
completedon the final poll returns[COMPLETED]and fetchestasks/result;failedon the final poll returns[FAILED]; a task thatnever leaves a non-terminal status still times out after
MAX_POLL_ATTEMPTSpolls.
completedon the final poll returns[COMPLETED]and fetchestasks/result;cancelledon the final poll returns[CANCELLED].npm run prettier:checkreports style issues in 59 pre-existing files (the repohas no
.prettierrc, whilesrc/everythinguses single quotes); thepre-change
tools.test.tsis flagged identically, and the two modified sourcefiles pass the check on their own. Prettier is not part of the TypeScript CI
workflow, which runs
npm testandnpm run build.Breaking Changes
None. The change only affects output for a task that finishes on the final poll
attempt, which previously always returned a timeout.
Types of changes
Checklist
Additional context
No tracking issue: this was found by reading the poll loop and confirmed by
test. The same off-by-one exists in both async tools because the two files were
written from the same template, so it is fixed in both.
Unchecked checklist items: no README change is needed for a bug fix; the change
was not exercised against a live LLM client, only against a mocked client
session in unit tests; the fix adds no new error-handling path.