Skip to content

host: a tool result never closes its wait, so the 60s steer line reads the turn's age #1644

Closed

Description

@HugoXK

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.

Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: af6aca314c394e8484759f1d65326b0b
Branch: dev/3-130-host-a-tool-result-never-closes-its-wait
Base: c26089f
At: 2026-10-29T05:49:00Z

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.

steering-interrupt.js closes a foreground tool wait by reading a field that tool/result does not carry, so nothing ever closes and the 60s line silently becomes "the turn has been running 60s".

Verified code facts (read at main 3f58b9a8):

  • core/src/host/steering-interrupt.js:42-48 — end(id, key) starts with if (key === '') return.
  • core/src/host/steering-interrupt.js:68-70 — case 'tool/result': end(id, String(event.data?.callId ?? '')).
  • core/src/host/steering-interrupt.js:62-64 — tool/call does have a top-level callId, so opens are recorded; only closes are lost.
  • DSH's own event map says the two shapes differ: 'tool/call': { turn, step, callId, name, arguments } but 'tool/result': { turn, step, message: ToolResultMessage, error?, meta? } — the call id arrives as data.message.toolCallId (also reachable as data.message.source.callId), never as a top-level data.callId. This repo already knows both shapes: core/src/host/flybot-feed.js:241 reads event.data?.callId ?? event.data?.message?.toolCallId.

Consequence. Within one turn open only grows. startedAtOf() (:34-37) then returns the time of the turn's first tool/call, so now - waitStartedAt > 60_000 stops meaning "an open wait has lasted 60s" and starts meaning "the turn has lasted 60s". A human steer that arrives after that aborts a turn whose tools have all returned and that is not waiting on anything.

Reproduction (real install(), real payloads). tool/call at T0; a genuine tool/result at T0+5s whose id is in data.message.toolCallId; a user/message with source.kind === 'user' at T0+61s → the turn is cancelled with {kind:'hook', reason:'ds-bot/interrupt-long-wait'}, options.keepInbox: true, although nothing was waiting. Control: the same sequence with a synthetic data:{callId} result does not cancel.

Why the shipped test is green. core/test/steering-interrupt.test.js builds results as { type:'tool/result', time, data:{ callId } } — a shape the host never writes — so the 5/5 pass pins a fixture, not the wire format.

Expected. A landed tool/result closes that call whatever the payload shape carries the id in; the 60s threshold applies only while a foreground wait is genuinely open. A returned tool means no interrupt, no matter how long the turn has been running.

Acceptance.

  • (a) the reproduction above cancels nothing;
  • (b) a genuinely open wait past 60s plus an arriving human line cancels exactly once, with keepInbox;
  • (c) at or below 60s, after the wait closed, and in a group room, nothing changes;
  • (d) the tests build tool/result payloads in the real shape (data.message.toolCallId), plus one case pinning that a result carrying only that field closes the wait — a red test on today's code.

Scope. core/src/host/steering-interrupt.js, its test, and the patches/ds-bot regeneration plus the one changelog fragment. Keep the change to the read: the trigger-timing question (deciding on agent/inbox/spliced arrival instead of a logged user/message) is a separate decision and must not be folded in here. core/src/host/turns.js:404 (endCall(id, entry, event.data?.callId)) has the same read; if the same one-line shape fixes it, include it, otherwise report it and leave it for its own issue.

Written-by: FlyBot Lead

Activity

  1. HugoXK commented on Oct 29, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: af6aca314c394e8484759f1d65326b0b
    Reason: Released: merged as #1645 (merge 4f2185d)
    At: 2026-10-29T06:42:55Z

  2. added a commit that references this issue on Oct 29, 2026
    4f2185d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions