Skip to content

feat(gui-app): agent mention rows — last-activity time, archived demotion and badge - #1127

Merged
pranshugupta54 merged 3 commits into
mainfrom
feat/agent-mention-row-polish
Aug 12, 2026
Merged

pranshugupta54 merged 3 commits into
mainfrom
feat/agent-mention-row-polish

Conversation

@pranshugupta54

@pranshugupta54 pranshugupta54 commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

Summary

Polish for the @ mention Agent rows (Agents submenu + the same rows in root search):

  • Last-activity time replaces the interface label. The trailing detail showed "Chat" / "Terminal · Claude Code" — the interface label says nothing a user picking between same-named rows can use. The trailing slot now shows the Agent's last-activity time on the sidebar rows' compact ladder (now/10m/4h/1d/1w/short date, formatCompactRelativeTime from lib/relative-time.ts — the exact formatter the sidebar chat rows use). Sampled once when the time leaf mounts (useState initializer): menu rows deliberately do not tick. The leaf is keyed by entry.id, so a ranked reorder while the picker stays open (the menu keys rows by index) remounts and resamples for the Agent that now occupies the row instead of retaining the previous occupant's time. Rows without an activity clock — files, categories, terminals, whose updatedAt is a start time — carry null and render no time. Harness name + the reference-only marker stay in the detail; the preview panel keeps the interface label, where there's room.
  • Timestamp source caveat (updatedAt is a mutation clock). The record's updatedAt approximates activity (it bumps on streaming ticks) but is also bumped by the host's archive write, renames, and other metadata writes. Consequences handled: archived rows show no time at all (the badge alone marks them — otherwise every archived row would read "Archived · now" right after archiving), and the archived-recency ordering within a match band is documented at the comparator as "most recently archived/touched first" (the pre-archive activity time is overwritten and unrecoverable client-side; the sidebar rows read the same clock). Accepted residual on live rows: a rename refreshes the displayed time. A proper fix needs an activity-specific timestamp on the host's projections — out of scope for this repo.
  • Archived Agents rank below live ones at equal match quality. Both chat and terminal-agent records carry archivedAt; archived-ness now slots between match score and recency in rankAgentEntries — it outweighs recency (an archived record more recent than a live one still sorts below it) but never relevance (an archived prefix hit still beats a live substring hit). Composition with feat(gui-app): fuzzy-rank the slash-command menu + step-aware picker height #1045's prefix/substring tiers in root search: the provider's ranked order feeds root search as the candidates' input order, the fuzzy pass tie-breaks equal scores by input index, and the tier resort is stable — so demotion applies within a match tier, never across tiers. Documented in rankAgentEntries' doc comment and pinned by a registry-level test (same-label archived/live tie → live first; archived prefix vs live substring → archived first via tiers).
  • "Archived" badge on archived rows. Carried as a boolean on MentionMenuEntry (per the entry-model note: a flag, not text in detail, so it can never truncate away), rendered semibold + muted to match the sidebar's archived marker. The row is not dimmed (sidebar uses opacity-55): opacity is this menu's disabled-row signal, and archived rows stay selectable.

Not touched, flagged for the record: plain terminal rows' detail is the working directory (not a kind label), so they don't have the "Chat"-style problem; their updatedAt is createdAt, which is why they get no time label.

Validation

  • bunx vitest run src/components/chat/composer src/lib/composer src/hooks/composer — green (new mention-menu-item render suite: time ladder, badge+detail+time, no-clock rows, reorder-resample regression — a different Agent taking the row gets a fresh time; providers ranking suites: archived-below-live at equal quality incl. recency-vs-archived, relevance-over-archived, root-search tier composition, archived rows carry no time; entry-building archivedAt → archived mapping)
  • bun run compile clean, react-doctor (changed files) clean, pre-commit passed at commit, DCO signed, no new deps

…tion and badge

The @ mention Agent rows (Agents submenu and root search) spent their
trailing slot on the interface label ("Chat", "Terminal · ...") - which
says nothing a user picking between same-named rows can use - and
listed archived chats indistinguishably from live ones, at equal rank.

- The trailing slot now shows the Agent's last-activity time on the
  sidebar rows' compact ladder (now/10m/4h/1d/1w/short date), sampled
  once when the row mounts - menu rows do not tick. `updatedAt` is a
  real activity clock for Agents (it bumps on streaming ticks); rows
  without one (files, categories, terminals - whose updatedAt is a
  start time) carry null and render no time. Harness name and the
  reference-only marker stay in the detail; the preview panel keeps
  the interface label, where there is room for it.
- Archived Agents (chat and terminal records both carry archivedAt)
  rank below live ones at EQUAL match quality: archived-ness slots
  between match score and recency in rankAgentEntries, so it outweighs
  recency but never relevance - an archived prefix hit still beats a
  live substring hit. The provider order feeds root search as the
  candidates' input order, where the fuzzy pass tie-breaks by input
  index and the prefix/substring tiers resort stably - so the same
  rule holds there: demotion within a match tier, never across tiers.
- Archived rows carry an "Archived" badge (semibold, muted - the
  sidebar's marker styling) as a flag on MentionMenuEntry rather than
  text in `detail`, so it can never truncate away. The row is not
  dimmed: opacity is this menu's disabled-row signal, and archived
  rows stay selectable.

Signed-off-by: Pranshu Gupta <traycer@MacBook-Pro.local>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 80d9bcb2-005d-437d-9f62-30bae9af0830

📥 Commits

Reviewing files that changed from the base of the PR and between 588e805 and 5056372.

📒 Files selected for processing (5)
  • clients/gui-app/src/components/chat/composer/menu/__tests__/mention-menu-item.test.tsx
  • clients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsx
  • clients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsx
  • clients/gui-app/src/lib/composer/mentions/mention-entry-display.tsx
  • clients/gui-app/src/lib/composer/mentions/providers.tsx

Summary by CodeRabbit

  • New Features
    • Added relative timestamps to Agent mention suggestions.
    • Archived Agents now display an “Archived” label while remaining referenceable.
    • Agent rows show clearer details, including terminal harness and reference-only status.
  • Improvements
    • Refined mention ranking to prioritize match quality, then active status and recency.
    • Archived Agents are ranked below active Agents when relevance is comparable.
    • Improved timestamp handling to keep displayed activity information accurate as suggestions change.

Walkthrough

Agent mention entries now include archive and activity metadata. Providers rank archived Agents below active Agents within equal match tiers and use recency as a tie-breaker. Mention rows display compact activity times and an Archived marker. Tests cover projection, ranking, metadata, and rendering.

Changes

Archived Agent mention flow

Layer / File(s) Summary
Entry metadata and source projection
clients/gui-app/src/lib/composer/types.ts, clients/gui-app/src/lib/composer/mentions/providers.tsx, clients/gui-app/src/components/chat/composer/picker/use-mention-items.ts, clients/gui-app/src/components/chat/composer/picker/__tests__/use-mention-items.test.ts, clients/gui-app/src/components/chat/composer/__tests__/*
Agent mention entries now expose updatedAt and archived. Source archivedAt values populate the archive flag. Test fixtures include the new metadata.
Agent ranking and search ordering
clients/gui-app/src/lib/composer/mentions/providers.tsx, clients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsx, clients/gui-app/src/lib/composer/mentions/__tests__/root-search-ranking.test.ts
Agent results use match quality, archive status, and recency. Archived entries rank below active entries only within equal match tiers.
Mention row display
clients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsx, clients/gui-app/src/lib/composer/mentions/mention-entry-display.tsx, clients/gui-app/src/components/chat/composer/menu/__tests__/mention-menu-item.test.tsx
Agent rows show compact relative activity time, an Archived marker, and detail text without the interface label.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentRecords
  participant useMentionItems
  participant MentionProviders
  participant MentionMenuItem
  AgentRecords->>useMentionItems: Provide archivedAt values
  useMentionItems->>MentionProviders: Build Agent mention entries
  MentionProviders->>MentionProviders: Rank by match, archive status, and recency
  MentionProviders->>MentionMenuItem: Return ranked entries
  MentionMenuItem->>MentionMenuItem: Render activity time and Archived marker
Loading

Possibly related PRs

Suggested reviewers: hdkshingala

Poem

A rabbit sorts the Agents bright,
Live ones hop ahead in flight.
Archived friends remain in sight,
Time labels mark each row just right.
“Mention them all!” the rabbit sings. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main Agent mention row changes: activity time, archived ranking, and the archived badge.
Description check ✅ Passed The description directly explains the Agent mention row behavior, ranking changes, archived badge, implementation details, and validation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-mention-row-polish

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@clients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsx`:
- Around line 15-18: The MentionRowTime label is initialized only on mount and
does not update when timestamp changes. Derive or memoize the label from
props.timestamp so rerenders reflect newer timestamps. In
clients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsx lines
15-18, update MentionRowTime; in
clients/gui-app/src/components/chat/composer/menu/__tests__/mention-menu-item.test.tsx
lines 28-40, rerender the same row with a newer updatedAt and assert the label
changes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1afff80b-e5ad-46d1-ba40-65adc9507511

📥 Commits

Reviewing files that changed from the base of the PR and between f396dd9 and 588e805.

📒 Files selected for processing (12)
  • clients/gui-app/src/components/chat/composer/__tests__/composer-mention-dismissal-flow.test.tsx
  • clients/gui-app/src/components/chat/composer/__tests__/composer-mention-flow.test.tsx
  • clients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.ts
  • clients/gui-app/src/components/chat/composer/menu/__tests__/mention-menu-item.test.tsx
  • clients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsx
  • clients/gui-app/src/components/chat/composer/picker/__tests__/use-mention-items.test.ts
  • clients/gui-app/src/components/chat/composer/picker/use-mention-items.ts
  • clients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsx
  • clients/gui-app/src/lib/composer/mentions/__tests__/root-search-ranking.test.ts
  • clients/gui-app/src/lib/composer/mentions/mention-entry-display.tsx
  • clients/gui-app/src/lib/composer/mentions/providers.tsx
  • clients/gui-app/src/lib/composer/types.ts

Two review findings on the Agent row timestamp:

- The menu keys rows by index, so a ranked reorder while the picker
  stays open reuses a row's component instance for a different Agent;
  the time leaf's once-sampled label kept the previous occupant's
  time. The leaf is now keyed by the entry id, remounting - and
  resampling - when a different Agent takes the row.

- The record's updatedAt is a mutation clock, not a pure activity
  clock: the host's archive write bumps it, as do renames and other
  metadata writes. An archived row would therefore always read
  "Archived · now" after the archive action. Archived rows now carry
  no time label at all - the badge alone marks them - and the
  archived-recency ordering caveat (roughly most-recently-
  archived/touched first; the pre-archive activity time is
  unrecoverable client-side) is documented at the comparator. Live
  rows keep the timestamp; a rename refreshing it is the accepted
  residual until an activity-specific clock exists host-side.

Also a comment-hygiene pass over the branch diff: change-narration
wording rewritten as timeless descriptions.

Signed-off-by: Pranshu Gupta <traycer@MacBook-Pro.local>
@pranshugupta54
pranshugupta54 enabled auto-merge (squash) August 12, 2026 09:26
@pranshugupta54
pranshugupta54 merged commit dd6c6ba into main Aug 12, 2026
20 checks passed
@pranshugupta54
pranshugupta54 deleted the feat/agent-mention-row-polish branch August 12, 2026 09:35
hdkshingala added a commit that referenced this pull request Aug 12, 2026
Merges `main` and answers the Codex/CodeRabbit threads on #1128. The merge
itself broke two files nothing conflicted in: `MentionMenuEntry` grew
`updatedAt`/`archived` on main (#1127) while this branch grew `labelPrefix`.
GitHub rows leave the new time slot null - their age is already composed into
`detail` beside the repository, and filling both renders it twice.

Correctness:

- Sent-message chips render GitHub mentions. Their `path` is a synthetic token
  (`github-pr:org/repo#12`), so the generic chip read a basename off it and
  showed the raw token as the tooltip: `#4917` became `traycer#4917` with a
  file icon the moment the message was posted.
- The live search is gated on `supported`, like the catalog reads already were.
  A host swap could negotiate the method away while the section stayed open.
- The held-row key includes the scope. Holding rows across a host, epic or
  roots change offered selectable mentions the new scope cannot resolve.
- Placeholder catalog responses are reported as the unanswered case rather than
  as rows. Same class as above: `keepPreviousData` hands over the PREVIOUS
  scope's answer, and every row in it is committable.
- A placeholder response no longer arms the automatic stale follow-up, which
  spent a GitHub request deciding for a scope that had not answered yet.
- `sourceStatus` and `notice` are gated on `wanted` like the rows, so a
  `gh-unavailable` banner cannot outlive the search that produced it.
- URL host comparison is case-folded, like owner and repo already were.
- `onStart` judges a new `@` by the root rules. The store can still hold the
  departing session's drilled step there, so `@x, y` could open the menu.
- Persisted filters are coerced to their section on read - identity-preserving
  when there is nothing to coerce, because the selector's result identity is
  what decides whether to re-render.
- The refresh control uses `AgentSpinningDots` rather than a spun icon.

Tests: the vacuous halves are the point - marker assertions that checked for a
marker the fixture never produces, a round-trip that passed if both sides went
empty, absence assertions with no positive control, and store assertions
comparing a local constant to itself. Category lookups go by label, not index.

Not changed, with reasons in the thread replies: the menu's `min(70vh,24rem)`
cap is the repository's viewport-cap idiom, not a fixed bound; the catalog's
Zustand store is deliberate and outlives query `gcTime` by design.

Signed-off-by: Hardik Shingala <hardik@traycer.ai>
hdkshingala added a commit that referenced this pull request Aug 12, 2026
Clears #889's conflict and picks up the Model Providers wire contract
(#1058), the provider CLI version management (#1103) and the agent
mention rows (#1127) that landed while this branch was in review.

Conflicts, all in the notifications family plus the RPC registry:

- protocol/src/host/registry.ts: both sides split a fourth literal out
  of the base definition to stay under TS7056 - ours for the post-v1
  notification minors, main's for `providers.*`. Kept both, so the
  registry now merges five literals. `DuplicateHostRpcMethodNames` needed
  the PROVIDERS x NOTIFICATION pair neither side wrote; without it the
  duplicate-method tripwire silently stops covering one of the ten pairs
  while still compiling.

- stores/notifications/merged-notifications.ts: ours extracted the
  attention sort into `comparePartitionedAttentionOrder` (tier, then
  plane, so a local `createdAt` is never compared against a cloud relay
  one); main added the D7 local-pack-first key. Composed as tier ->
  plane -> pack locality. `compareProviderPackLocalFirst` already carries
  the newest-first then `feedId` tail `compareFeedCandidates` did, so
  nothing below the locality key changed.

- Seven notification suites: kept our `useNotificationHost` mock beside
  main's `importOriginal`-based `use-host-directory-entry` mock.

OSS graph compiles; protocol 147 files / 2310 tests green; the 36
gui-app notification suites green (493 tests).

Signed-off-by: Hardik Shingala <hardik@traycer.ai>
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.

1 participant