Skip to content

fix(agents): count agent typing's half hour from its last activity - #1302

Open
baxen wants to merge 1 commit into
mainfrom
claude00/typing-idle-limit
Open

baxen wants to merge 1 commit into
mainfrom
claude00/typing-idle-limit

Conversation

@baxen

@baxen baxen commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

Problem

Typing for an agent's mention run stopped 30 minutes after the pulse started, even when the agent was still working. On 2026-10-17 mbot (goose) worked without a break from 18:38, but its typing went away around 19:08 and again around 19:40, so it looked like mbot had dropped. The 30-minute cap (LONGEST_MS) came in with #998 and was measured from the first pulse.

Change

The 30 minutes is now an idle limit (IDLE_MS). These reset it:

  • every step the run reports. The runtimes call it on tool calls: goose GooseSession.update, Claude, Codex. runner.ts sends that step to the turn's typing.
  • a new mention that joins an existing shared pulse in the same conversation.

pulseTyping now returns { active, stop }. The last-active time is stored on the shared pulse entry, so activity from any turn in that conversation keeps the pulse alive. Nothing else changes about how pulses are shared or stopped: typing still ends when the last turn settles, when the runner aborts, or after three failed pulses in a row.

Tests

  • typing.test.ts
    • stops after 30 idle minutes (and leaves the pulse map)
    • keeps pulsing past 30 minutes while active() is called, then stops 30 minutes after the last call
    • a joining mention resets the clock
  • service.test.ts: a run that calls delivery.step at minute 20 is still typing at minute 40, and stops 30 minutes after that.
  • I removed each reset in turn (join, active, the runner's step wiring), and the matching test failed each time.
  • Typecheck and biome pass. Full Vitest: the first run had 69 timeouts on a heavily loaded machine (load average about 52), none in the files I changed. Rerunning those 31 files, everything passed (InboxPage needed --testTimeout=30000).

Known gap

A single tool call that runs longer than 30 minutes reports no steps while it runs, so its typing still stops at 30 minutes. That covers mbot's 19:48 Chromium run under timeout 3000. goose also skips a step when it repeats the previous one exactly. Fixing either one means the runtime has to report progress during a tool call, which this PR doesn't do.

🤖 Generated with Claude Code

Typing for a mention run stopped 30 minutes after its first pulse, even
while the agent kept working, so a long goose turn looked like it had
dropped. The half hour is now an idle limit: every step the run reports,
and every mention that joins the shared pulse, starts it again. A run that
goes quiet for half an hour still stops typing; settling and aborting end
it as before.

Co-authored-by: claude00 <fb8b76a01257932b8ca35060862c29bd09b2137638573731c2d5074fc02c5385@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
@baxen
baxen marked this pull request as ready for review October 17, 2026 20:19
@baxen
baxen requested a review from a team as a code owner October 17, 2026 20:19
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T20:22:27.923817Z 4f9adda Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f9addaabc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +87 to +89
active: () => {
if (!stopped && joined) joined.active = Date.now();
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restart typing when activity follows idle expiry

When a tool call lasts longer than IDLE_MS, pulse() stops its interval and removes the shared entry, but this active() callback still updates the now-detached joined object. Consequently, the next reported step cannot restart typing, and the agent remains permanently silent for the rest of the turn even if it continues through many subsequent tools. Rejoin or recreate the conversation pulse when activity arrives after expiry.

Useful? React with 👍 / 👎.

Comment on lines +10 to +12
/** A run that shows no activity for this long stops looking busy, so one that
* never settles does not type forever. */
const IDLE_MS = 30 * 60_000;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the documented typing timeout semantics

This changes the timeout from an unconditional 30-minute cap to 30 minutes since the latest step or joining turn, but docs/agents.md:478-485 still specifies that typing stops “after 30 minutes.” That owning lifecycle documentation now gives runtime maintainers and reviewers the wrong protocol behavior; update it to describe the idle timeout and its reset conditions.

AGENTS.md reference: AGENTS.md:L76-L79

Useful? React with 👍 / 👎.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/user flows) reviews.

No required code changes found; 9/10 for the stated scope. Reviewed head 4f9adda against base 16ca8d3.

The shared activity timestamp and runner step wiring address active turns crossing the old absolute cutoff. I checked all four changed files, the Goose/Claude/Codex step producers, reference counting, stop-before-join, settlement/abort, slow publication and the three-failure cutoff. The existing pulse owner and interval are reused; no new timer is added. The added fake-clock tests cover idle expiry, activity, joining turns and service wiring. No changed focus/interaction controls were found. The public description has no attachments; no disclosure issue found in the reviewed description/diff/commit.

Optional documentation clarification: expand the Known gap to say that after 30 idle minutes, typing stays off for the rest of that turn even if later steps resume. In typing.ts:87–89, activity updates the retired shared entry; it does not recreate the cleared interval. A later mention creates its own pulse. This retains the prior terminal-cutoff behavior and is not a request to expand this fix. docs/agents.md:483–485 also still describes the cutoff as simply “after 30 minutes”; “after 30 minutes without reported activity” would match this change.

Validation limits: source-only; no tests, builds, app launches or live relay/runtime execution performed. A single hosted-check snapshot showed both JavaScript jobs and Vitest flake checks passing, but WebKit shard 1/9 and CI required failed. The failed shard had 89 passes and one failure: channel-archive-delete-pane.spec.mjs:350 expected the Close Channel settings tab button to regain focus. Its relationship to this change is unestablished; this review does not establish green CI or merge readiness. Long-tool/repeated-Goose-step behavior, cross-device display, runtime performance and human acceptance remain unverified. This is a non-blocking COMMENT review, not approval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants