Add a sleep tool that really waits, and make wait report the time it took - #223
Closed
handstandsam wants to merge 1 commit into
Closed
Add a sleep tool that really waits, and make wait report the time it took#223handstandsam wants to merge 1 commit into
handstandsam wants to merge 1 commit into
Conversation
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.
Summary
Syncs the latest upstream changes through 2026.08.02.
A
sleeptool that actually waitswaitandwaitForChangeare settles: they return the moment the UI goes quiet, so on astatic screen they come back in milliseconds no matter what duration you asked for. That makes
them the wrong tool when you need time to genuinely pass — e.g. letting a server-side value
propagate before navigating to the screen that reads it.
New
sleeptool blocks for a fixed wall-clock duration and never returns early. It runsin-process for every agent, so the duration is driver-independent. It is hidden from the LLM's
toolbox (
surfaceToLlm = false) — a fixed sleep is right when an author knows about anoff-screen dependency and almost always wrong when picked autonomously — but is callable from
hand-authored trail YAML and scripted tools, and is recorded like any other tool. A duration
outside 100ms–5min is an error rather than a silent clamp, since clamping would return early
while reporting success.
Waits now report the time they actually took
waitused to log"Waited 30 seconds"whether it waited 30 seconds or 150ms, andwaitForChange's unsupported-driver fallback made the same claim. Both now report measuredelapsed time alongside the ceiling that was requested, so a log no longer asserts a wait that
never happened. The tool descriptions say "ceiling, not a duration" too, and point at asserting
on the element you're actually waiting for.
Report timeline: see the tool calls that were folded away
A traceId is allocated per LLM request — one turn's whole tool batch — not per tool call, so a
turn's calls all fold onto one timeline row. The other calls weren't just collapsed, they were
absent from the payload entirely, and nothing in the row hinted they existed. They now appear as
expandable children in dispatch order. Repeated polls keep their
×Ncount instead of expandinginto N rows.
Recording-resolution census fixes
The one-line census printed buckets that overlapped, so summing the numbers a reader saw gave the
wrong total: a matched-but-empty step counted as both
exactandzero-tool no-op. The bucketsnow partition, the trailhead is named separately so step numbers line up with every other
artifact, and
conditionalis parenthesised because it's a property of the matched steps ratherthan a bucket of its own. A self-guarding tool (probes, no-ops when its target is absent) now
counts as conditional alongside the wrapper form, so a device that spells the guard differently
is no longer reported as having lost one.
Implementation detail
SleepTrailblazeTool(HostLocalExecutableTrailblazeTool, soBaseTrailblazeAgent.runTrailblazeToolsruns it before driver-specific dispatch), registered as
CoreTools.SLEEPin thecore_interactiontoolset. Bounds held underDaemonClient.RUN_POLL_TIMEOUT_MS— a host-localsleep emits no progress, so a longer one is indistinguishable from a wedged run.
WaitForIdleSyncTrailblazeTool/WaitForChangeTrailblazeToolmeasure withTimeSource.Monotonicaround the driver call.toolChildreninrun-report-extract.tsmerges executedTrailblazeToolLogs withDelegatingTrailblazeToolLogdeclarations, matching on name and args so a repeatedprimitive with one unlogged dispatch still surfaces.
RecordingResolution/TrailRecordingResolutionbucket partitioning andCONDITIONAL_TOOL_NAMES.testRailUrltrail-metadata read dropped from the runner paths.Test plan
:trailblaze-common:check— newSleepTrailblazeToolTest,WaitForIdleSyncTrailblazeToolTest,WaitForChangeTrailblazeToolTest,ToolSerializationTest:trailblaze-models:check—RecordingResolutionTest,apiCheck:trailblaze-report:check—run-report-core.test.ts