Repository navigation
Conversation
The Gateway emits no events between tool.start and tool.complete, so the 180s idle watchdog treated any single tool call that ran longer than that as a dead turn and sent session.interrupt, killing a healthy tool (exit 130). Track open tool calls in GatewayEventMapper (id -> name, matched the same way as tool.complete handling) and, while any is open, arm TOOL_IN_FLIGHT_TIMEOUT_MS (1800s, matching the prompt.submit ceiling and the backend gateway timeout) instead of the idle window. Ask and compaction leases keep precedence. Open-tool state is dropped on a mid-turn rejoin since a missed tool.complete cannot be replayed. The ordinary idle timeout applies again once no tool is open. Adds a toolInFlightTimeoutMs constructor seam and tests for: silent in-flight tool, normal timeout after tool.complete, parallel tools, and a dead turn with no tool in flight.
12 tasks done
Owner
sacgsxr
pushed a commit
to sacgsxr/hermes-relay
that referenced
this pull request
Oct 16, 2026
Extend the preserved PR Codename-11#675 commits with read-only quiet probes, exact unsolicited settlement, passive reconnect and shutdown, native ask replay, and missing-final history reconciliation. Cover owner and observer paths through real Gateway transport and rendered fixture tests. Update current-upstream conformance for extracted helpers and additive requests. Adapt cancellation-only diagnostics from PR Codename-11#668. Supersede PR Codename-11#662's eventual interrupt lease; quiet tools use server-owned liveness instead. Co-authored-by: ophirhan <ophirhan@users.noreply.github.com>
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
The Gateway emits no events between
tool.startandtool.complete.GatewayChatClient's idle watchdog (TURN_TIMEOUT_MS, 180s) is re-armed only on events, so any single tool call that runs silently for longer than 180s (for example a long terminal command) is treated as a dead turn: the client sendssession.interrupt, the server logsInterrupt requested (hard): explicit stop requested, and the healthy tool is killed (exit 130). The user sees "Gateway turn timed out" / "Operation interrupted" mid-task without having pressed stop.Asks and compaction already get longer leases for exactly this reason (see the compacting lease); tool execution had no equivalent. This PR holds a longer lease while any tool call is in flight.
Changes
GatewayEventMappertracks open tool calls (id → name):tool.startadds,tool.completeremoves (same id/name matching as the existing complete handling; an id-less complete retires the oldest open call of that name). ExposeshasOpenTools/clearOpenTools().GatewayChatClientaddsTOOL_IN_FLIGHT_TIMEOUT_MS(1800s, matchingPROMPT_SUBMIT_REQUEST_TIMEOUT_MSand the backend's agent turn ceiling) with atoolInFlightTimeoutMstest seam.watchdogTimeoutFor/ defaultarmWatchdog()use it while any tool is open; ask and compaction leases keep priority.tool.completemissed during the gap cannot be replayed), so the normal idle timeout applies after a rejoin.Verification
./gradlew :app:testSideloadDebugUnitTest --tests "com.hermesandroid.relay.network.upstream.GatewayChatClientTest" --tests "com.hermesandroid.relay.network.upstream.GatewayEventMapperTest"on the PR head (rebased on currentdev): BUILD SUCCESSFUL — GatewayChatClientTest 199 tests, GatewayEventMapperTest 77 tests, 0 failures, 0 errors.tool.complete; with parallel tools the lease holds until every call completes; a dead turn with no tool in flight still times out and interrupts even with a long tool lease configured.Screenshots
No visual change.
Compatibility / risk
tool.start/tool.completeevents). No relay-plugin or fork-only behavior.tool.completeis now cut off client-side after 1800s instead of 180s; server-side tool timeouts still apply first.tool.completeis lost without a socket rejoin, the long lease persists until the next event or turn end.Lineage / contributor credit
Checklist
devCHANGELOG.mdis updated