improvement(chat): restore stable inline tool activity headers and action summaries - #8225
waleedlatif1 wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
There was a problem hiding this comment.
All reported issues were addressed across 20 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
…tion summaries
Mothership v1.0.0 reintroduced the "Searching -> Searched -> Searching"
flicker that staging had fixed: between two calls of an open main-agent
activity, the header dropped to the past tense, lost its shimmer, and the
turn-level Thinking row appeared until the next call started. It also removed
the header icon and summarized headers as "<latest title> + N".
Stable in-progress header
- An open main-agent activity group (the streaming turn's tail, with nothing
after its last call) stays in the present tense through the gaps between
its calls, so the header no longer flips tense. Succeeded calls arrive
with past-tense titles, so the open header maps them back through the exact
inverse of the completed-verb rewrite; one helper (getToolInProgressTitle)
serves main lanes, subagent lanes, and the landing hero.
One live indicator per lane
- A new pure module (lane-activity) owns the rule and states it in TSDoc.
Each active lane has one live call: the newest running call anywhere in
the lane (across all its runs, including runs split by a search or an
interaction card, and its nested lanes). With none running and the lane
open, the latest call of its trailing run owns the gap, and only if it
succeeded. A finished search shows static results, so the gap after it
belongs to Thinking.
- Only the run holding that call shimmers: its group header, or its one
search row. Tool rows never shimmer by themselves. A parent lane defers
to a visible nested lane holding the live call only while that lane is
still working; an ended nested lane hands its last call back to the
parent's header.
- Tense follows liveness: a header reads in progress only while it is live
or its call still runs, so a group whose latest call failed or stopped
reads as finished instead of keeping a stale present tense.
- The turn computes this once; every lane view receives its share, and the
Thinking row reads the same result. The main lane spans all main-agent
segments. Thinking shows only when no lane is live and no lane waits on
the user. A lane waiting on an approval, terminal handoff, or browser
takeover shows no indicator, while other lanes doing real work keep theirs.
When the stream finishes, nothing shimmers.
- Rendering and liveness share one run split, and failed subagent lanes no
longer count as working. Only the tail group is open, so a later pending
interaction no longer re-opens earlier finished groups.
Header icons
- Group headers and single inline rows render the icon of the call they
describe again, including integration brand icons, and keep it through
completion. Main and subagent headers share one title rule: "Working…"
while a sim_cli or run_code call generates its arguments, a live wait
countdown, and streaming file-edit titles.
Summaries without "+N"
- Running headers show only the active call. Main and subagent lanes share
one completed-label rule: the model's completedTitle only when every call
succeeded, and otherwise a fallback naming up to three distinct successful
actions ("Navigated, read pages, clicked elements"), picked by first
occurrence in transcript order. Failed calls are
left out, and the " · N stopped/skipped" outcome suffix stays.
- A rebuilt action catalog covers the current tool surface: every visible
catalog tool and operation, plus sim_cli commands. Each command's verb comes
from its own display title, and the object comes from its resource path, so
commands on one resource share a word ("Listed, read tables"). `mkdir`
commands read as creating folders and `tables upsert` as writing table rows.
Tools outside the catalog use their own completed title.
Separate finished activity groups
- groupByActivity still splits main-agent calls by activity id, but no longer
merges finished groups into one header, so the completedGroupCount plumbing
is removed, along with the unused getAgentIcon fallback parameter.
Flat expanded layout
- Indentation now only marks nested work. Expanded tool rows in main and
subagent groups line up with their header: the icon in the shared 14px
icon column, the text one gap-2 to its right. Nested subagent lanes,
narration, lane errors, and the permission card's rows sit on that same
text column through one shared primitive instead of pl-6 or pl-[22px].
- One spacing scale: gap-1.5 between rows inside a group (tool rows, search
queries), gap-3 between blocks in the main lane (tool groups, search runs,
lanes, interaction cards, prose).
Inline links in answers
- A link's favicon is centered on the text's own middle with align-middle,
like inline citation chips, instead of a baseline pixel nudge.
- The link tooltip names the page instead of showing its URL. It uses the
turn's retrieved source for that exact URL, then the link preview's title,
then the site name, with the site name muted beneath. One helper dedupes a
turn's sources by URL everywhere they are listed or looked up.
- Prose links show a thin muted underline on hover instead of a filled
background, and keep the keyboard focus outline.
Verb rewrites
- The past-tense and present-tense verb tables are Maps, because titles
include model-written text, and a description starting with "constructor"
must never resolve to an inherited object property.
c6eb7e8 to
a6114e8
Compare
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
2 issues found across 36 files
Confidence score: 3/5
lane-activity.tscan suppress the turn wait when a browser takeover is executing but the browser agent is unavailable, leaving no takeover card and potentially leaving the user without visible progress; pass browser-agent availability into the lane decision.tool-call-title.tstruncates streamedprepare_file_editlabels when title values contain escaped quotes, reducing live status clarity; parse escaped JSON characters while extracting the title.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts">
<violation number="1" location="apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts:100">
P2: This unconditionally suppresses the turn wait for an executing browser takeover, even when the browser agent is unavailable and no takeover card can render. Pass the browser-agent availability into the lane decision and only treat the takeover as a user wait when the corresponding card will be shown.</violation>
</file>
<file name="apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-title.ts">
<violation number="1" location="apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-title.ts:60">
P2: Escaped quotes in a streamed `prepare_file_edit` title are parsed as the end of the value, truncating the live label. Match escaped JSON characters while extracting the title so labels remain correct during streaming.</violation>
</file>
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Fix all with cubic | Re-trigger cubic
| includeBrowserTakeover = false | ||
| ): boolean { | ||
| return ( | ||
| (includeBrowserTakeover && getActiveBrowserTakeover(items) !== null) || |
There was a problem hiding this comment.
P2: This unconditionally suppresses the turn wait for an executing browser takeover, even when the browser agent is unavailable and no takeover card can render. Pass the browser-agent availability into the lane decision and only treat the takeover as a user wait when the corresponding card will be shown.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/lane-activity.ts, line 100:
<comment>This unconditionally suppresses the turn wait for an executing browser takeover, even when the browser agent is unavailable and no takeover card can render. Pass the browser-agent availability into the lane decision and only treat the takeover as a user wait when the corresponding card will be shown.</comment>
<file context>
@@ -0,0 +1,252 @@
+ includeBrowserTakeover = false
+): boolean {
+ return (
+ (includeBrowserTakeover && getActiveBrowserTakeover(items) !== null) ||
+ items.some((item) =>
+ item.type === 'tool'
</file context>
| */ | ||
| function getLiveFileEditTitle(toolName?: string, streamingArgs?: string): string | null { | ||
| if (toolName !== PrepareFileEdit.id || !streamingArgs) return null | ||
| const titleMatch = streamingArgs.match(/"title"\s*:\s*"([^"]+)"/) |
There was a problem hiding this comment.
P2: Escaped quotes in a streamed prepare_file_edit title are parsed as the end of the value, truncating the live label. Match escaped JSON characters while extracting the title so labels remain correct during streaming.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-title.ts, line 60:
<comment>Escaped quotes in a streamed `prepare_file_edit` title are parsed as the end of the value, truncating the live label. Match escaped JSON characters while extracting the title so labels remain correct during streaming.</comment>
<file context>
@@ -0,0 +1,111 @@
+ */
+function getLiveFileEditTitle(toolName?: string, streamingArgs?: string): string | null {
+ if (toolName !== PrepareFileEdit.id || !streamingArgs) return null
+ const titleMatch = streamingArgs.match(/"title"\s*:\s*"([^"]+)"/)
+ if (!titleMatch?.[1]) return null
+ const operation = streamingArgs.match(/"operation"\s*:\s*"(\w+)"/)?.[1] ?? ''
</file context>
| const titleMatch = streamingArgs.match(/"title"\s*:\s*"([^"]+)"/) | |
| const titleMatch = streamingArgs.match(/"title"\s*:\s*"((?:\\.|[^"\\])*)"/) |
Summary
Restores the inline tool activity feel from before v1.0.0 on top of the new activity grouping, built on one rule: one live indicator per active lane, and the Thinking row only when nothing is live and nothing waits on the user.
lane-activity) decides each lane's single live call (newest running call across the lane's tool groups, search runs, and nested lanes); only that run shimmers, so parallel calls, interleaved searches, and approval cards never show two indicatorsactivityDescription) from the worker; Sim already renders themType of Change
Testing
MessageContent, collapsed and expanded: streaming/reload × position × tool group/search/subagent/nested × every call status × parallel/sequential × model title/description) shows exactly the expected live indicator, tense, header text, and icon in every statecheck:audits(49), block registry, and docs manifest pass; 3,264 tests across home, mothership tools, and the landing hero passChecklist