Keep the turn activity tracker steady while subagents run - #157
Merged
Conversation
Two fixes for the inline subagent activity bar in the conversation: Flicker: a running agent's streamed commentary is a timeline entry that renders nothing, but its timestamp moves with every update. It could split and re-merge the turn's work groups as the agent streamed, and the live group never rendered the activity receipt, so the tracker blinked in and out mid-turn. Live commentary entries now stay out of grouping entirely, and a live work group that owns the turn's tracker renders the receipt above its spine so the bar survives group churn. Missing model/effort: the durable roster seeds a record for every agent before lifecycle rows fold in, so the "only inherit for a brand-new record" guard from #155 never fired and a collab spawn that stated no model lost the parent turn's dispatched selection. Native-spawn omission is now a sticky per-record fact instead: native subAgentActivity spawns still never inherit, while collab and Task spawns inherit the turn's model and effort even when the roster seeded their record first.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
badcuban
added a commit
that referenced
this pull request
Aug 15, 2026
…tab (#160) * Keep a subagent's work out of the inline feed and surface the Agents tab A background Claude agent's activity flooded the parent conversation: every per-tool task.progress tick rendered as its own inline row ("Activity - 128 actions" with 110+ leaked entries), while the agent tracker that should summarize the delegation never showed for turnless background stretches. Conversation feed: - deriveWorkLogEntries no longer strips activityKind from emitted entries, which had made the timeline's agent-lifecycle parking (isAgentLifecycleEntry) dead code in production - the exact check #157 shipped. - Background tasks an agent starts inside its own conversation (e.g. its test runs) are now attributed to the spawning agent: the Claude adapter records every tool_use id seen in forwarded subagent messages and stamps task events with ownerAgentToolUseId (new optional field on the task payload contracts), which the web parks out of the feed alongside the agent's own task stream. - Work groups with no turn to key on carry trackerAgentSpawnIds, and selectTurnAgents gained a spawn-call fallback, so a turnless background-agent group at the conversation tail shows the tracker bars and live status line instead of nothing. An all-delegation group's receipt reads "Agent working" / "Agents working" / "Agent activity" instead of claiming zero actions. Agents tab: - A fresh idle-to-running agent transition auto-surfaces the Agents tab: focused when the sidebar is hidden or on the launcher, joined in the background (live node only) when another tab has focus. The edge detector (advanceAgentsAutoOpenEdge) only believes idleness after the thread's detail snapshot has synced - the chat column now publishes a hydrated flag with its agent state - so loading or reloading a thread whose agent is already running never yanks the panel open. Once per batch, never on sheet layouts, and closing the tab mid-batch is respected. Durable roster: - projection_thread_subagents was empty for every thread: the projection only recognized Codex-shaped collab items (data.item). The Claude item shaping moved from web session-logic into @threadlines/shared/claudeSubagentActivity and the server projection now uses it too, links Claude transcript task ids, settles agents from task.completed (including restart-synthesized completions that carry only a taskId), and maps the shaper's "errored" state to failed. - Migration 048 backfills the roster by replaying each thread's roster-moving activities through the same fold, in rowid (append) order so same-timestamp lifecycle rows cannot resurrect a settled agent, one thread at a time. Verified end to end against a snapshot of real data: migration backfilled 27 agents in ~6s, the flood thread renders clean with the tracker live at the tail, and load/reload of a running-agent thread no longer auto-opens the panel. * Sanitize subagent result text without polynomial backtracking CodeQL flagged the moved sanitizer's regexes (js/polynomial-redos): the trailing <usage> stripper and the SendMessage continuation-footer stripper both backtracked polynomially, and agent output is provider-influenced input. The usage stripper is now index arithmetic, and the footer pattern only ever runs anchored against a bounded slice from the last "agentId:". Covered by direct tests for the shared module, including an adversarial repetition case that would time out on the quadratic implementation.
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.
Fixes two long-standing issues with the inline subagent activity bar in the main chat.
Flickering activity bar
A running agent's streamed commentary becomes a
subagent-livetimeline entry. It renders nothing, but itscreatedAtmoves forward on every stream update, and it still broke work-group contiguity inderiveMessagesTimelineRows. The result: as the agent streamed, the entry hopped between the middle and the tail of the turn's work entries, splitting and re-merging the activity groups. Whenever the groups merged into one live group, the receipt (the "Activity · N actions · 2 subagents" row with the tracker) vanished, because the live group only rendered the step spine. That is the flicker.Two changes:
subagent-liveentries are now filtered out before grouping (alongside subagent-attributed work entries), so group boundaries no longer depend on a moving timestamp.Model and reasoning effort intermittently missing
#155 restricted parent-turn model/effort inheritance to records seen for the first time (
previous === undefined). But since the durable subagent roster started seeding a record for every agent before activity rows are folded in (f658a57),previousis always defined, so the inheritance floor was dead. Any collab spawn that did not state an explicit model (Codexspawn_agentwithoutmodelargs, ClaudeTaskwithout an override) showed a blank model, and whether the bar showed model/effort depended on whether the orchestrator happened to pass explicit args.The fix makes "native spawn omission is deliberate" a sticky per-record fact (
nativeSpawnon the internal record) instead of inferring it from record freshness:subAgentActivityspawns still never inherit, including through laterwait/sendInput/closeAgentitems (preserves Preserve native subagent model omissions #155).Tests
vp fmt,vp lint,vp run typecheckgreen. Full web unit suite: 2194 passed. Full browser suite: 465/466, with the one failure an unrelatedFileViewerPierreflake that passes in isolation.