[feat] Add automation history to session rows - #5927
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR adds typed paginated session queries, centralized session-list policies, automation metadata in session rows, automation menus, and owner-history or exact-delivery drawer flows. Deleted schedules and subscriptions now render as read-only. ChangesSession querying and automation delivery
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant SessionListConsumer
participant sessionListQueryOptions
participant querySessionsPage
participant SessionsClient
SessionListConsumer->>sessionListQueryOptions: build policy and cursor options
sessionListQueryOptions->>querySessionsPage: request structured session page
querySessionsPage->>SessionsClient: send serialized query
SessionsClient-->>querySessionsPage: return session page envelope
querySessionsPage-->>SessionListConsumer: return sessions and pagination metadata
sequenceDiagram
participant SessionRow
participant SessionAutomationActions
participant TriggerDeliveriesDrawer
participant useTriggerDelivery
participant TriggersClient
SessionRow->>SessionAutomationActions: select automation or delivery action
SessionAutomationActions->>TriggerDeliveriesDrawer: open schedule, subscription, or exact delivery
TriggerDeliveriesDrawer->>useTriggerDelivery: request project-scoped delivery
useTriggerDelivery->>TriggersClient: fetch delivery
TriggersClient-->>TriggerDeliveriesDrawer: return delivery or error
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
| const openSchedule = useSetAtom(triggerScheduleDrawerAtom) | ||
| const openSubscription = useSetAtom(triggerSubscriptionDrawerAtom) | ||
| const openDelivery = useSetAtom(triggerDeliveriesDrawerAtom) | ||
| const canViewTriggers = hasPermission("view_triggers") |
There was a problem hiding this comment.
Review focus: view_triggers gates only the two automation-specific secondary actions. The session row click is wired separately and must remain available to users without trigger permission; the action and row tests cover that regression.
Signed: OpenCode
| ownerHistory: ReactNode | ||
| exactDelivery: ReactNode | ||
| }) { | ||
| return state.mode === "exact-delivery" ? exactDelivery : ownerHistory |
There was a problem hiding this comment.
Review focus: this branch keeps exact-delivery mode from mounting the owner-history subtree, so opening one delivery cannot trigger the paginated owner list request. The drawer-mode unit test pins this request boundary.
Signed: OpenCode
ed2008b to
c8bb08d
Compare
0365e19 to
f6f80e3
Compare
c8bb08d to
52777a1
Compare
f6f80e3 to
5b24a57
Compare
52777a1 to
5d4cc86
Compare
5b24a57 to
def1cc7
Compare
Railway Preview Environment
Updated at 2026-08-11T11:50:38.725Z |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (7)
web/packages/agenta-entities/src/gatewayTrigger/state/atoms.ts (1)
85-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShorten or remove this comment.
This comment describes normal feature behavior. It does not document a bug, race, or ordering constraint. Keep one short line if this context is required.
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.”
Source: Coding guidelines
web/packages/agenta-entities/src/session/api/api.ts (1)
262-265: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a dedicated request type for windowing.
SessionWindowingis inferred from the response schema, where each field is.nullish().Picktherefore admitsnullforlimit,next,newest,oldest, andorderin request parameters. Callers can passnullwhere the API expects an absent value. Define a request-side windowing type, or applyNonNullableper field.♻️ Proposed refactor
-type SessionWindowingParams = Pick< - SessionWindowing, - "limit" | "next" | "newest" | "oldest" | "order" -> +type SessionWindowingParams = { + [K in "limit" | "next" | "newest" | "oldest" | "order"]?: NonNullable<SessionWindowing[K]> +}web/packages/agenta-entities/src/session/state/listOptions.ts (1)
44-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
stableIdsduplicatesstableValues.Both functions have the same body.
stableIdsisstableValues<string>.♻️ Proposed refactor
const stableValues = <T extends string>(values: T[] | undefined): T[] | undefined => values ? [...new Set(values)].sort() : undefined - -const stableIds = (values: string[] | undefined): string[] | undefined => - values ? [...new Set(values)].sort() : undefinedThen call
stableValues(sessionIds)andstableValues(excludeSessionIds).web/packages/agenta-entities/tests/unit/session-list-options.test.ts (1)
145-153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a case for
windowing: null.
nextSessionCursortreatswindowing: nulldifferently from an absentwindowing:nullstops pagination, whileundefinedfalls back to row reconstruction. That branch decides whether a full page can be paged past. No test pins it.💚 Proposed test
+ it("stops when the response sets windowing to null", () => { + expect(nextSessionCursor({count: 1, sessions: [row], windowing: null}, 1)).toBeUndefined() + })web/mobile/src/features/sessions/useSessionsInfinite.ts (2)
10-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse the shared
SESSIONS_PAGE_SIZE.
@agenta/entities/sessionalready exportsSESSIONS_PAGE_SIZEwith the value 30, anduseSessionListHead.tsimports it from there. This file declares a second constant with the same name and value. The two can drift.♻️ Proposed refactor
import { nextSessionCursor, sessionListQueryOptions, + SESSIONS_PAGE_SIZE, type SessionListCursor, } from "`@agenta/entities/session`" import {useInfiniteQuery} from "`@tanstack/react-query`" import {mobileSessionListPolicy} from "./sessionListPolicy" -export const SESSIONS_PAGE_SIZE = 30 -const PAGE_SIZE = SESSIONS_PAGE_SIZE +export {SESSIONS_PAGE_SIZE} +const PAGE_SIZE = SESSIONS_PAGE_SIZEVerify that no mobile consumer depends on this module owning the constant.
38-38: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winStabilize the
selecttransform.
selectis an inline arrow that TanStack re-runs whenever its identity changes. It allocates a new result object and a newpagesarray on each render, which propagates rerenders to list consumers. Hoist it to a module-level function, because it captures nothing from the render scope.♻️ Proposed refactor
+const selectSessionPages = (data: {pages: {sessions: SessionStream[]}[]}) => ({ + ...data, + pages: data.pages.map((page) => page.sessions), +})Then reference it:
- select: (data) => ({...data, pages: data.pages.map((page) => page.sessions)}), + select: selectSessionPages,As per coding guidelines: "Minimize React re-renders with
useMemo,useCallback, andReact.memowhere appropriate; avoid unstable inline functions and objects, especially in lists."Source: Coding guidelines
web/oss/src/components/AgentChatSlice/state/projectSessionsQuery.ts (1)
47-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
activityduplicates the helper inprojectSessions.ts.
projectSessions.tsdefines the same function at lines 69-73 with identical logic. Export the helper from this module and import it there.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: d1a8f18e-48c9-4f17-8a0f-74774fd60638
⛔ Files ignored due to path filters (1)
web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (72)
web/mobile/src/features/sessions/sessionListPolicy.tsweb/mobile/src/features/sessions/useSessionListHead.tsweb/mobile/src/features/sessions/useSessionsInfinite.tsweb/mobile/tests/unit/sessionListPolicy.test.tsweb/oss/src/components/AgentChatSlice/state/projectSessions.tsweb/oss/src/components/AgentChatSlice/state/projectSessionsQuery.test.tsweb/oss/src/components/AgentChatSlice/state/projectSessionsQuery.tsweb/oss/src/components/Sidebar/dynamic/sessionOptions.test.tsweb/oss/src/components/Sidebar/dynamic/sessionOptions.tsweb/oss/src/components/Sidebar/dynamic/sessionsSource.tsweb/oss/src/components/pages/agent-home/StripHome.tsxweb/oss/src/components/pages/agent-home/components/HomeAutomationsSection.tsxweb/oss/src/components/pages/agent-home/components/HomeSessionsSection.tsxweb/oss/src/components/pages/agent-home/components/YourAgentsTable/useAgentActivity.tsweb/oss/src/components/pages/overview/agent/AgentOverview.tsxweb/oss/src/components/pages/sessions/SessionsPage.tsxweb/oss/src/components/pages/sessions/assets/menuEntries.tsweb/oss/src/components/pages/sessions/assets/sessionAutomationActions.test.tsweb/oss/src/components/pages/sessions/assets/sessionAutomationActions.tsweb/oss/src/components/pages/sessions/components/SessionAutomationDrawers.tsxweb/oss/src/components/pages/sessions/components/SessionListCard.tsxweb/oss/src/components/pages/sessions/hooks/useSessionAutomationActions.tsweb/oss/src/components/pages/settings/Triggers/components/GatewaySchedulesSection.tsxweb/oss/src/components/pages/settings/Triggers/components/GatewaySubscriptionsSection.tsxweb/oss/src/lib/sessionListPolicies.test.tsweb/oss/src/lib/sessionListPolicies.tsweb/packages/agenta-entities/src/gatewayTrigger/api/api.tsweb/packages/agenta-entities/src/gatewayTrigger/core/types.tsweb/packages/agenta-entities/src/gatewayTrigger/hooks/index.tsweb/packages/agenta-entities/src/gatewayTrigger/hooks/useTriggerDeliveries.tsweb/packages/agenta-entities/src/gatewayTrigger/index.tsweb/packages/agenta-entities/src/gatewayTrigger/state/atoms.tsweb/packages/agenta-entities/src/gatewayTrigger/state/index.tsweb/packages/agenta-entities/src/session/api/api.tsweb/packages/agenta-entities/src/session/core/schema.tsweb/packages/agenta-entities/src/session/index.tsweb/packages/agenta-entities/src/session/state/listOptions.tsweb/packages/agenta-entities/tests/unit/fetchTriggerDelivery.test.tsweb/packages/agenta-entities/tests/unit/session-list-options.test.tsweb/packages/agenta-entities/tests/unit/session-query-api.test.tsweb/packages/agenta-entities/tests/unit/session-query-schema.test.tsweb/packages/agenta-entities/tests/unit/triggerApplicationArtifactId.test.tsweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/TriggerManagementSection.tsxweb/packages/agenta-entity-ui/src/gatewayTrigger/drawers/DeliveryDetails.tsxweb/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerDeliveriesDrawer.tsxweb/packages/agenta-entity-ui/src/gatewayTrigger/drawers/TriggerDeliveriesDrawerContent.tsxweb/packages/agenta-entity-ui/src/gatewayTrigger/drawers/linkedSessionAction.tsweb/packages/agenta-entity-ui/src/gatewayTrigger/drawers/schedule/ScheduleForm.tsxweb/packages/agenta-entity-ui/src/gatewayTrigger/drawers/subscription/SubscriptionForm.tsxweb/packages/agenta-entity-ui/tests/unit/deliveryDetails.test.tsweb/packages/agenta-entity-ui/tests/unit/linkedSessionAction.test.tsweb/packages/agenta-entity-ui/tests/unit/triggerDeliveriesDrawerMode.test.tsweb/packages/agenta-sdk/src/resources.tsweb/packages/agenta-sessions-ui/package.jsonweb/packages/agenta-sessions-ui/src/SessionAutomationKind.tsxweb/packages/agenta-sessions-ui/src/SessionRow.tsxweb/packages/agenta-sessions-ui/src/automationMenu.tsweb/packages/agenta-sessions-ui/src/index.tsweb/packages/agenta-sessions-ui/tests/unit/SessionRow.test.tsweb/packages/agenta-sessions-ui/vitest.config.tsweb/packages/agenta-sessions/src/row/index.tsweb/packages/agenta-sessions/src/row/sessionRowTitle.tsweb/packages/agenta-sessions/src/row/sessionTrigger.tsweb/packages/agenta-sessions/src/row/viewModel.tsweb/packages/agenta-sessions/src/state/index.tsweb/packages/agenta-sessions/src/state/sessionListPolicy.tsweb/packages/agenta-sessions/src/state/useSessionCardList.tsweb/packages/agenta-sessions/src/state/useSessionList.tsweb/packages/agenta-sessions/src/state/useSessionsList.tsweb/packages/agenta-sessions/tests/unit/sessionListIdWindow.test.tsweb/packages/agenta-sessions/tests/unit/sessionListPolicy.test.tsweb/packages/agenta-sessions/tests/unit/sessionRowVm.test.ts
5d4cc86 to
8fc2123
Compare
def1cc7 to
62571c8
Compare
…es, and session-list rename/delete refresh The schedule/subscription edit drawer showed an empty revision picker even when a variant-level (unversioned) bind existed: the label selectors expect a revision id, but the default bind stores a variant id, so resolution silently returned null. Add a fallback that resolves the label via the bound workflow id instead, with a shared composeRevisionLabel() helper and tests. The Agent Overview "Automation runs" section requested no expansions, so trigger names never resolved and every row read "Missing schedule". Request the trigger expansion for that surface only (still no last_message, matching the surface's existing policy). Renaming or deleting a schedule/subscription never invalidated the session-list queries (desktop, sidebar, mobile), so an automation session's row kept showing the old name until an unrelated refetch happened to fire. invalidateTriggerSchedules/Subscriptions now also invalidates every session-list query via a shared query-key token, without enumerating each surface's nesting.
Trims session.name before using it as a chat-sidebar title (the guard checked trim(), the assignment didn't). Degrades an unrecognized origin/trigger.kind wire value to undefined instead of failing the whole /sessions/query page: sessionStreamSchema validates the entire `sessions` array in one parse, so one row with a future/unknown enum value previously nulled out every row on the page. Fixes the delivery status badge falling back to the default (grey) color when only status.code is set: the badge text already fell back to code, but the color lookup only ever received status.type. Disables the subscription mapping editor (raw-JSON Editor and the composer's contenteditable PillEditor) for a deleted subscription. The surrounding <fieldset disabled> already covers native controls; these two aren't native form elements, so they stayed interactive despite Save being blocked.
…e parsing, stuck-delivery badge
8fc2123 to
ebb085f
Compare
62571c8 to
c80530c
Compare
|
QA walkthrough of the session UX feature (before and after fixes): session-ux-qa.mp4 (Direct comment attachment isn't available through |
Context
Sessions started by schedules and subscriptions need to stay out of human-work lists by default, while automation mode must show which automation ran and let users inspect the exact delivery. The UI previously depended on reserved tags and had no exact-delivery row action.
Changes
Each session-list caller now declares its origin and expansion policy. Row models consume typed automation data, show schedule or subscription kind, and preserve the session as the primary click target. Secondary actions open the automation configuration or one exact delivery. Deleted configurations remain available in read-only historical drawers while normal lists and mutations stay live-only.
Exact delivery mode calls
GET /triggers/deliveries/{delivery_id}once and does not mount the owner-wide delivery-list query.Tests / notes
pnpm lint-fixpassed.http://144.76.237.122:8280.What to QA
Open automation. The matching configuration drawer opens.View delivery. Only the linked delivery loads and shows the linked session.Stack: 3 of 4. Base:
clients/session-ux-contract.