Skip to content

feat(frontend): session and agent surfaces move into the packages - #5869

Draft
ardaerzin wants to merge 6 commits into
pkg/ui-primitivesfrom
pkg/session-surfaces
Draft

feat(frontend): session and agent surfaces move into the packages#5869
ardaerzin wants to merge 6 commits into
pkg/ui-primitivesfrom
pkg/session-surfaces

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

The session and agent surfaces leave the app layer for the packages, so desktop and /m render
the same components instead of two drifting copies.
Not run in a browser — static gates only (pnpm lint-fix 24/24, tsc --noEmit clean
for @agenta/shared, ui, entities, entity-ui, settings-ui, oss, ee, mobile).

Stacked on pkg/ui-primitives; review only this lane's diff.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Error Error Aug 10, 2026 2:58pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: 3eba4e40-37de-4426-8644-d6191fa72b4b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added responsive agent card grids with loading, empty, and create-agent states.
    • Added read-only agent configuration summaries with expandable details and playground editing.
    • Added reusable session filters and session lists with grouping, pagination, pinning, menus, and responsive layouts.
    • Template selection now opens detail and setup flows, with onboarding tracking and copy-to-clipboard feedback.
  • Bug Fixes
    • Category changes preserve expanded rows while resetting pagination and scroll position.
    • Improved keyboard activation for agent and template rows.
    • Corrected pending-session labels and agent avatar fallbacks.

Walkthrough

The PR updates agent onboarding and template selection, adds shared agent and session UI components, and integrates them into OSS pages. It also centralizes session-open state, configuration summaries, list rendering, filtering, pagination, and related package exports.

Changes

Agent onboarding and template flow

Layer / File(s) Summary
Template selection and onboarding flow
web/oss/src/components/pages/agent-home/PlaygroundOnboarding/useAgentOnboarding.ts, web/oss/src/components/pages/agent-home/StripHome.tsx, web/oss/src/components/pages/agent-home/components/TemplatesGallery/index.tsx, web/oss/src/components/pages/agent-home/components/TemplateDetail/index.tsx, web/oss/src/components/pages/agent-home/components/HomeTaskComposer.tsx
Template selection now seeds provenance, records onboarding intent, and routes through template detail and setup surfaces.
Onboarding surface and copy feedback
web/oss/src/components/pages/agent-home/StripHome.tsx, web/oss/src/components/TemplateStrip/index.tsx, web/oss/src/components/pages/agent-home/components/TemplatesSection/index.tsx, web/oss/src/components/pages/agent-home/assets/templates.ts
The onboarding surface adds coding-agent copy feedback, copied confirmation, independent scrolling, and stable template-grid behavior.

Shared agent surfaces

Layer / File(s) Summary
Agent grid and configuration contracts
web/packages/agenta-entity-ui/package.json, web/packages/agenta-entity-ui/src/agent/AgentCardGrid.tsx, web/packages/agenta-entity-ui/src/agent/agentConfigSummary.ts, web/packages/agenta-entity-ui/src/agent/state.ts, web/packages/agenta-entity-ui/src/agent/index.ts, web/packages/agenta-entity-ui/tests/unit/agentConfigSummary.test.ts
The entity UI package adds reusable agent grid APIs, configuration extraction, latest-revision state, exports, and package wiring.
Agent card and configuration components
web/packages/agenta-entity-ui/src/agent/AgentCard.tsx, web/packages/agenta-entity-ui/src/agent/AgentConfigSummaryCard.tsx
Agent cards update avatar and keyboard behavior. The configuration card displays latest revision details with loading and edit states.
Agent page integration
web/oss/src/components/pages/agents/AgentsGrid.tsx, web/oss/src/components/pages/overview/agent/AgentConfigurationCard.tsx, web/oss/src/components/pages/overview/agent/AgentOverview.tsx, web/packages/agenta-entity-ui/src/agent/NextTriggersSection.tsx
OSS pages use shared agent components. Trigger rendering removes local clock and retry state.

Shared session surfaces

Layer / File(s) Summary
Session open state and row contracts
web/packages/agenta-sessions/src/row/*, web/packages/agenta-sessions/src/state/*, web/packages/agenta-sessions/tests/unit/sessionOpenTarget.test.ts
Session rows expose normalized open targets and pending-gate labels. Shared pending-session state and tests are added.
Reusable session filters and lists
web/packages/agenta-sessions-ui/src/SessionCardList.tsx, web/packages/agenta-sessions-ui/src/SessionFiltersPanel.tsx, web/packages/agenta-sessions-ui/src/SessionsListView.tsx, web/packages/agenta-sessions-ui/src/SessionRow.tsx, web/packages/agenta-sessions-ui/src/assets/motion.ts, web/packages/agenta-sessions-ui/src/controls/SessionFilterControls.tsx, web/packages/agenta-sessions-ui/src/index.ts
Shared components now provide filtering, grouping, animation, pagination, status controls, and host-provided actions.
Session page integration
web/oss/src/components/pages/sessions/SessionsPage.tsx, web/oss/src/components/pages/sessions/components/SessionListCard.tsx, web/oss/src/components/pages/agent-home/components/YourAgentsTable/*
OSS session surfaces delegate list rendering and actions to shared components and use the shared session-open helper.

Small maintenance updates

Layer / File(s) Summary
Documentation and rendering cleanup
web/oss/src/components/pages/settings/Triggers/components/GatewaySchedulesSection.tsx
The bound workflow renderer now uses a concise JSX expression without changing output.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TemplateGallery
  participant TemplateDetail
  participant StripHome
  participant StripComposer
  TemplateGallery->>TemplateDetail: Navigate with selected template
  TemplateDetail->>StripHome: Provide template selection
  StripHome->>StripComposer: Seed composer through provenance
Loading
sequenceDiagram
  participant SessionsPage
  participant SessionFiltersPanel
  participant SessionsListView
  participant SessionCardList
  SessionsPage->>SessionFiltersPanel: Provide filters and agent options
  SessionsPage->>SessionsListView: Provide list scope and actions
  SessionsListView->>SessionCardList: Render grouped session rows
  SessionCardList-->>SessionsPage: Invoke row and menu callbacks
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 60.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly summarizes the main change: moving session and agent surfaces into shared packages.
Description check ✅ Passed The description directly explains the package migration and shared desktop/mobile component goal.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pkg/session-surfaces

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/packages/agenta-sessions-ui/src/index.ts (1)

33-40: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Export SessionStatusListControl from the package entry point.

The new reusable control is not available through @agenta/sessions-ui. Export it with the other filter controls so consumers do not import an internal module path.

Proposed fix
 export {
     SessionSearchControl,
     SessionStatusControl,
+    SessionStatusListControl,
     SessionModeControl,
     SessionArchivedControl,
 } from "./controls/SessionFilterControls"

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: 848c02a8-e65f-438f-ad30-e35fcf246392

📥 Commits

Reviewing files that changed from the base of the PR and between aa9863a and 617face.

📒 Files selected for processing (42)
  • web/oss/src/components/TemplateStrip/index.tsx
  • web/oss/src/components/pages/agent-home/PlaygroundOnboarding/useAgentOnboarding.ts
  • web/oss/src/components/pages/agent-home/StripHome.tsx
  • web/oss/src/components/pages/agent-home/assets/templates.ts
  • web/oss/src/components/pages/agent-home/components/HomeTaskComposer.tsx
  • web/oss/src/components/pages/agent-home/components/TemplateDetail/index.tsx
  • web/oss/src/components/pages/agent-home/components/TemplatesGallery/index.tsx
  • web/oss/src/components/pages/agent-home/components/TemplatesSection/index.tsx
  • web/oss/src/components/pages/agent-home/components/YourAgentsTable/AgentRow.tsx
  • web/oss/src/components/pages/agent-home/components/YourAgentsTable/useAgentActivity.ts
  • web/oss/src/components/pages/agents/AgentsGrid.tsx
  • web/oss/src/components/pages/overview/agent/AgentConfigurationCard.tsx
  • web/oss/src/components/pages/overview/agent/AgentOverview.tsx
  • web/oss/src/components/pages/sessions/SessionsPage.tsx
  • web/oss/src/components/pages/sessions/components/SessionListCard.tsx
  • web/oss/src/components/pages/settings/Triggers/components/GatewaySchedulesSection.tsx
  • web/packages/agenta-entity-ui/package.json
  • web/packages/agenta-entity-ui/src/agent/AgentCard.tsx
  • web/packages/agenta-entity-ui/src/agent/AgentCardGrid.tsx
  • web/packages/agenta-entity-ui/src/agent/AgentConfigSummaryCard.tsx
  • web/packages/agenta-entity-ui/src/agent/NextTriggersSection.tsx
  • web/packages/agenta-entity-ui/src/agent/agentConfigSummary.ts
  • web/packages/agenta-entity-ui/src/agent/index.ts
  • web/packages/agenta-entity-ui/src/agent/state.ts
  • web/packages/agenta-entity-ui/tests/unit/agentConfigSummary.test.ts
  • web/packages/agenta-sessions-ui/package.json
  • web/packages/agenta-sessions-ui/src/SessionCardList.tsx
  • web/packages/agenta-sessions-ui/src/SessionFiltersPanel.tsx
  • web/packages/agenta-sessions-ui/src/SessionRow.tsx
  • web/packages/agenta-sessions-ui/src/SessionsListView.tsx
  • web/packages/agenta-sessions-ui/src/assets/motion.ts
  • web/packages/agenta-sessions-ui/src/controls/SessionFilterControls.tsx
  • web/packages/agenta-sessions-ui/src/index.ts
  • web/packages/agenta-sessions/src/row/index.ts
  • web/packages/agenta-sessions/src/row/sessionOpenTarget.ts
  • web/packages/agenta-sessions/src/row/viewModel.ts
  • web/packages/agenta-sessions/src/state/index.ts
  • web/packages/agenta-sessions/src/state/pendingSessionOpen.ts
  • web/packages/agenta-sessions/src/state/useSessionCardList.ts
  • web/packages/agenta-sessions/src/state/useSessionList.ts
  • web/packages/agenta-sessions/test-results/junit.xml
  • web/packages/agenta-sessions/tests/unit/sessionOpenTarget.test.ts

Comment on lines +36 to +37
// Default to the most recently touched agent — the one you're most likely to want next.
const effectiveAgentId = agentId ?? agents[0]?.workflowId ?? null

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate the selected agent against the current roster.

If the selected agent is deleted or becomes inaccessible, effectiveAgentId remains stale. The composer then enables send and passes an invalid appId to startSession.

Proposed fix
-    const effectiveAgentId = agentId ?? agents[0]?.workflowId ?? null
+    const effectiveAgentId =
+        agents.some((agent) => agent.workflowId === agentId)
+            ? agentId
+            : agents[0]?.workflowId ?? null
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Default to the most recently touched agent — the one you're most likely to want next.
const effectiveAgentId = agentId ?? agents[0]?.workflowId ?? null
// Default to the most recently touched agent — the one you're most likely to want next.
const effectiveAgentId =
agents.some((agent) => agent.workflowId === agentId)
? agentId
: agents[0]?.workflowId ?? null

Comment on lines 83 to +86
const handleSelectTemplate = useCallback(
(template: AgentTemplate) => void createFromTemplate(template),
[createFromTemplate],
(template: AgentTemplate) =>
void router.push(`${baseAppURL}/agent-templates/${template.key}`),
[router, baseAppURL],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Define baseAppURL before constructing the template route.

baseAppURL is not declared in this module. TypeScript cannot compile this callback.

Proposed fix
+import useURL from "`@/oss/hooks/useURL`"
+
 const TemplatesGalleryPage = () => {
     const router = useRouter()
+    const {baseAppURL} = useURL()
     const {message} = App.useApp()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleSelectTemplate = useCallback(
(template: AgentTemplate) => void createFromTemplate(template),
[createFromTemplate],
(template: AgentTemplate) =>
void router.push(`${baseAppURL}/agent-templates/${template.key}`),
[router, baseAppURL],
import useURL from "`@/oss/hooks/useURL`"
const TemplatesGalleryPage = () => {
const router = useRouter()
const {baseAppURL} = useURL()
const {message} = App.useApp()
const handleSelectTemplate = useCallback(
(template: AgentTemplate) =>
void router.push(`${baseAppURL}/agent-templates/${template.key}`),
[router, baseAppURL],

event.preventDefault()
actions.onOpenPlayground(record)
}
if (event.key === "Enter" || event.key === " ") actions.onOpenPlayground(record)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep keyboard activation on the row itself.

The onKeyDown handler also receives key events from the nested actions Button. Pressing Enter or Space while that button is focused calls actions.onOpenPlayground(record) before the button can perform its own action. The button's onClick propagation guard does not stop this keydown.

Handle the row shortcut only when event.target === event.currentTarget, then call event.preventDefault() for the row's Space activation.

Proposed fix
         onKeyDown={(event) => {
-            if (event.key === "Enter" || event.key === " ") actions.onOpenPlayground(record)
+            if (event.target !== event.currentTarget) return
+            if (event.key === "Enter" || event.key === " ") {
+                event.preventDefault()
+                actions.onOpenPlayground(record)
+            }
         }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (event.key === "Enter" || event.key === " ") actions.onOpenPlayground(record)
if (event.target !== event.currentTarget) return
if (event.key === "Enter" || event.key === " ") {
event.preventDefault()
actions.onOpenPlayground(record)
}

Comment on lines +123 to +136
const handleCodingAgentCopy = useCallback(async () => {
const text = composerRef.current?.getMarkdown().trim() ?? ""
try {
await navigator.clipboard.writeText(buildCodingAgentClipboard(text))
setToastOpen(true)
} catch {
message.error("Couldn't copy — copy it manually")
return
}
captureFirstAgentIntent(posthog, {
source: "composer",
properties: {action: "coding_agent_copy", message: truncateForCapture(text)},
})
}, [message, posthog])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not send composer text to analytics.

text can contain credentials, customer data, or other sensitive prompt content. truncateForCapture only limits length. It does not sanitize the content. Capture non-sensitive metadata, such as an action name and a length bucket, instead.

Comment on lines +73 to +76
const menuFor = useCallback(
(vm: SessionRowVm) =>
actions.menuItems(actionTargetFor(vm), {onOpen: () => handleOpen(vm)}),
[actions, handleOpen],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Convert Ant Design menu items before passing them to SessionCardList.

actions.menuItems() returns MenuProps["items"]. SessionCardList.menuFor requires SessionMenuEntry[]. These types are not compatible because Ant Design items can be null, groups, submenus, or items without a required string key and label.

Convert the result with toSessionMenuEntries, as web/oss/src/components/pages/sessions/SessionsPage.tsx already does.

Proposed fix
+import {toSessionMenuEntries} from "../assets/menuEntries"
+
 const menuFor = useCallback(
     (vm: SessionRowVm) =>
-        actions.menuItems(actionTargetFor(vm), {onOpen: () => handleOpen(vm)}),
+        toSessionMenuEntries(
+            actions.menuItems(actionTargetFor(vm), {onOpen: () => handleOpen(vm)}),
+        ),
     [actions, handleOpen],
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const menuFor = useCallback(
(vm: SessionRowVm) =>
actions.menuItems(actionTargetFor(vm), {onOpen: () => handleOpen(vm)}),
[actions, handleOpen],
import {toSessionMenuEntries} from "../assets/menuEntries"
const menuFor = useCallback(
(vm: SessionRowVm) =>
toSessionMenuEntries(
actions.menuItems(actionTargetFor(vm), {onOpen: () => handleOpen(vm)}),
),
[actions, handleOpen],
)

Comment on lines +108 to +126
<nav className="flex flex-col gap-0.5">
{STATUSES.map((option) => (
<button
key={option.value}
type="button"
onClick={() => setStatus(option.value)}
className={`box-border flex w-full cursor-pointer items-center gap-2 rounded-lg border-0 px-3 py-2 text-left text-sm transition-colors ${
option.value === status
? "bg-colorFillSecondary text-colorText"
: "bg-transparent text-colorTextSecondary hover:bg-colorFillQuaternary"
}`}
>
<span className="min-w-0 flex-1 truncate">{option.label}</span>
{option.value === "waiting" && waitingCount ? (
<span className="shrink-0 rounded bg-colorWarningBg px-1.5 py-0.5 text-[11px] leading-none text-colorWarningText">
{waitingCount}
</span>
) : null}
</button>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Expose the active status to assistive technology.

The selected status is only visual. Add a labelled control group and expose each button state with aria-pressed.

Proposed fix
-        <nav className="flex flex-col gap-0.5">
+        <div role="group" aria-label="Session status" className="flex flex-col gap-0.5">
             {STATUSES.map((option) => (
                 <button
                     key={option.value}
                     type="button"
+                    aria-pressed={option.value === status}
                     onClick={() => setStatus(option.value)}
@@
-        </nav>
+        </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<nav className="flex flex-col gap-0.5">
{STATUSES.map((option) => (
<button
key={option.value}
type="button"
onClick={() => setStatus(option.value)}
className={`box-border flex w-full cursor-pointer items-center gap-2 rounded-lg border-0 px-3 py-2 text-left text-sm transition-colors ${
option.value === status
? "bg-colorFillSecondary text-colorText"
: "bg-transparent text-colorTextSecondary hover:bg-colorFillQuaternary"
}`}
>
<span className="min-w-0 flex-1 truncate">{option.label}</span>
{option.value === "waiting" && waitingCount ? (
<span className="shrink-0 rounded bg-colorWarningBg px-1.5 py-0.5 text-[11px] leading-none text-colorWarningText">
{waitingCount}
</span>
) : null}
</button>
<div role="group" aria-label="Session status" className="flex flex-col gap-0.5">
{STATUSES.map((option) => (
<button
key={option.value}
type="button"
aria-pressed={option.value === status}
onClick={() => setStatus(option.value)}
className={`box-border flex w-full cursor-pointer items-center gap-2 rounded-lg border-0 px-3 py-2 text-left text-sm transition-colors ${
option.value === status
? "bg-colorFillSecondary text-colorText"
: "bg-transparent text-colorTextSecondary hover:bg-colorFillQuaternary"
}`}
>
<span className="min-w-0 flex-1 truncate">{option.label}</span>
{option.value === "waiting" && waitingCount ? (
<span className="shrink-0 rounded bg-colorWarningBg px-1.5 py-0.5 text-[11px] leading-none text-colorWarningText">
{waitingCount}
</span>
) : null}
</button>
))}
</div>

Comment on lines +68 to +120
<button
type="button"
onClick={() => onOpenRow(vm)}
className="group box-border flex w-full cursor-pointer items-start gap-3 border-0 border-b border-solid border-colorBorderSecondary bg-transparent px-2 py-3 text-left hover:bg-colorFillQuaternary"
>
{/* A glyph for the KIND of row, with the status as a dot on its shoulder — the clock
and the chat bubble separate automation runs from conversations without a heading. */}
<SimpleTooltip title={vm.status.label}>
<span className="relative mt-0.5 flex shrink-0 text-colorTextTertiary">
{origin ? <ClockIcon size={18} /> : <ChatCircleIcon size={18} />}
<span
className={`absolute -right-0.5 -top-0.5 h-2 w-2 rounded-full border border-solid border-colorBgContainer ${vm.status.dotClassName} ${
vm.status.pulse ? "motion-safe:animate-pulse" : ""
}`}
/>
</span>
</SimpleTooltip>
<span className="flex min-w-0 flex-1 flex-col gap-1">
<span className="flex w-full items-center gap-2">
<span className="min-w-0 flex-1 truncate text-sm text-colorText">
{vm.title}
</span>
{/* Quiet chip: the amber urgency lives on the dot; this states WHAT is asked. */}
{vm.status.chipLabel ? (
<span className="shrink-0 rounded bg-colorFillQuaternary px-1.5 py-0.5 text-xs leading-none text-colorTextSecondary">
{pendingGateLabel(vm.pending?.kinds)}
</span>
) : null}
{showAgent ? (
<span className="w-24 shrink-0 truncate text-right">
<SessionAgentName agentId={vm.agentId} />
</span>
) : null}
<span className="w-16 shrink-0 text-right text-xs text-colorTextTertiary">
{vm.activityAt ? timeAgo(Date.parse(vm.activityAt)) : "—"}
</span>
<SimpleTooltip title={vm.isPinned ? "Unpin" : "Pin"}>
<span
role="button"
tabIndex={-1}
aria-label={vm.isPinned ? "Unpin session" : "Pin session"}
onClick={(event) => {
event.stopPropagation()
onTogglePin(vm.id)
}}
className={`shrink-0 text-colorTextTertiary ${
vm.isPinned || alwaysShowPin
? ""
: "opacity-0 group-hover:opacity-100"
}`}
>
<PushPinIcon size={14} weight={vm.isPinned ? "fill" : "regular"} />
</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not nest the pin action inside the row button.

The pin control is inside the row <button>. Nested interactive controls are invalid HTML. The pin control also has tabIndex={-1}, so keyboard users cannot toggle it.

Use a non-interactive row container. Make the title a button and make the pin an independent native button. SessionRow already uses this structure.

Comment on lines +1 to +6
/**
* The session filters — the whole panel, extracted from the desktop rail. The controls bind to
* the shared filter atoms (`useSessionFilters` / the control components), so desktop's 280px
* rail and mobile's stacked sheet render the same filter state. The agent picker runs on the
* kit Select and takes the host's agent list (each app resolves its roster differently).
*/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Reduce the added explanatory comments.

Rewrite these ordinary comments as one short line or remove them. They do not document a bug, race, or ordering constraint.

  • web/packages/agenta-sessions-ui/src/SessionFiltersPanel.tsx#L1-L6: remove or reduce the component overview.
  • web/packages/agenta-sessions-ui/src/SessionFiltersPanel.tsx#L85-L86: reduce the filter-heading explanation to one short line.
  • web/packages/agenta-sessions-ui/src/controls/SessionFilterControls.tsx#L103-L104: reduce the control-description comment to one short line.
  • web/packages/agenta-sessions/tests/unit/sessionOpenTarget.test.ts#L1-L5: remove the redundant test-file overview.

As per coding guidelines, “Keep in-code comments to at most one short line; use longer comments only for genuinely surprising constraints such as bugs, races, or ordering requirements.”

📍 Affects 3 files
  • web/packages/agenta-sessions-ui/src/SessionFiltersPanel.tsx#L1-L6 (this comment)
  • web/packages/agenta-sessions-ui/src/SessionFiltersPanel.tsx#L85-L86
  • web/packages/agenta-sessions-ui/src/controls/SessionFilterControls.tsx#L103-L104
  • web/packages/agenta-sessions/tests/unit/sessionOpenTarget.test.ts#L1-L5

Source: Coding guidelines

Comment on lines +138 to +141
const canShowMore =
!isEmpty &&
(listRows.length > recentRows.length + pinnedRows.length + waitingRows.length ||
Boolean(listQuery.hasNextPage))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Correct canShowMore row accounting.

listRows excludes waiting rows and excludes pinned rows when withPinned is enabled. Lines 140-141 add waitingRows and pinnedRows to the rendered recent-row count. This can hide “Show more” while loaded recent rows are still not rendered.

For example, with a limit of 7 and two waiting rows, recentRows contains five rows from seven listRows. The current comparison evaluates 7 > 5 + 2 as false.

Proposed fix
-        (listRows.length > recentRows.length + pinnedRows.length + waitingRows.length ||
+        (listRows.length > recentRows.length ||
             Boolean(listQuery.hasNextPage))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const canShowMore =
!isEmpty &&
(listRows.length > recentRows.length + pinnedRows.length + waitingRows.length ||
Boolean(listQuery.hasNextPage))
const canShowMore =
!isEmpty &&
(listRows.length > recentRows.length ||
Boolean(listQuery.hasNextPage))

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="21" failures="0" errors="0" time="0.012510875">
<testsuite name="tests/unit/sessionPreview.test.ts" timestamp="2026-08-06T05:27:01.475Z" hostname="Ardas-MacBook-Pro.local" tests="5" failures="0" errors="0" skipped="0" time="0.0045445">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Remove the generated local test report.

Line 3 exposes Ardas-MacBook-Pro.local. The report also omits the new sessionOpenTarget suite. Do not commit local test output. Publish it only as a CI artifact.

- TemplatesGallery read `baseAppURL` without declaring it; take it from `urlAtom`.
- SessionListCard handed antd `MenuProps["items"]` to `menuFor`, which wants
  `SessionMenuEntry[]` — route it through the existing `toSessionMenuEntries`.
- @agenta/sessions-ui exported seven modules this lane never added, and
  SessionsListView imported one of them; bring SessionRowContextMenu over and drop
  the exports whose files land in a later lane.
…roken

- "Show more" compared the recent-only population against a count of all three
  rendered groups, so loaded rows went unrendered with no way to reveal them; each
  population is now measured against its own slice.
- A harness without a model rendered the model row as satisfied; the status follows
  `summary.model`, the composed string stays the summary.
- Failed revision/schedule/subscription requests fell through to the empty state.
  One SectionLoadError with the query's own refetch covers both cards.
- The next-run time never recomputed after the move. nowTickAtom moves out of the
  chat slice into @agenta/shared/state so both surfaces share the one interval.
- AgentCard's initial came from the raw name, so a padded single word blanked it.
- Home's composer kept a deleted agent selected and sent its id; a selection now
  has to still be in the roster.
- The card row's pin was a `role="button" tabIndex={-1}` span nested inside the row
  button — invalid, and unreachable by keyboard. The row takes SessionRow's shape:
  a plain container, a title button, and the shared SessionPinButton as a sibling.
- Enter/Space on the agent row and card fired the container's action even when the
  kebab had focus, and Space scrolled the page.
- The status filter list was styling only; it is now a labelled group whose buttons
  carry aria-pressed.
…g comments

The two committed junit.xml files carry developer hostnames, and the narrow
per-package ignore could not cover them once tracked. One `test-results/` pattern
covers every workspace.
A deliberate behaviour change: `first_agent_intent` no longer carries the raw
"describe your agent" text. `truncateForCapture` only capped length — a composer
message can hold credentials, customer data or a pasted secret, and none of that
belongs in an analytics property.

The module already had the signal it says it exists to capture:
`classifyAgentIntent` buckets the message into support/research/ops/content/
coding/data/other. Two of the three call sites already sent that bucket alongside
the raw text, so dropping the text loses nothing there; the coding-agent-copy path
on StripHome gains the classification it never had. `truncateForCapture` and
`MESSAGE_CAPTURE_LIMIT` are gone with their last reference.
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