Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .server-changes/sessions-test-column.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: feature
---

Agent sessions started from the Test playground are now flagged with a real `Session.isTest` boolean instead of a `"playground"` tag, surfaced as a dedicated "Test" column (check icon) in the Sessions table on both the Sessions and Agent pages, plus a matching property on the session detail page. Existing sessions are backfilled and the now-redundant tag is removed.
19 changes: 17 additions & 2 deletions apps/webapp/app/components/sessions/v1/SessionsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ArrowRightIcon } from "@heroicons/react/20/solid";
import { CheckIcon } from "@heroicons/react/24/solid";
import { useLocation, useNavigation } from "@remix-run/react";
import { formatDuration } from "@trigger.dev/core/v3/utils/durations";
import { RunsIconExtraSmall } from "~/assets/icons/RunsIcon";
Expand Down Expand Up @@ -87,6 +88,7 @@ export function SessionsTable({
</TableHeaderCell>
<TableHeaderCell>Type</TableHeaderCell>
<TableHeaderCell>Agent ID</TableHeaderCell>
<TableHeaderCell>Test</TableHeaderCell>
<TableHeaderCell>Tags</TableHeaderCell>
<TableHeaderCell>Created</TableHeaderCell>
<TableHeaderCell>Duration</TableHeaderCell>
Expand All @@ -97,7 +99,7 @@ export function SessionsTable({
</TableHeader>
<TableBody>
{sessions.length === 0 ? (
<TableBlankRow colSpan={8}>
<TableBlankRow colSpan={9}>
<div className="flex items-center justify-center">
<Paragraph className="w-auto">
{hasFilters
Expand Down Expand Up @@ -144,6 +146,19 @@ export function SessionsTable({
<MiddleTruncate text={session.taskIdentifier} className="font-mono text-xs" />
</div>
</TableCell>
<TableCell to={sessionPath}>
<span className="sr-only">{session.isTest ? "Yes" : "No"}</span>
{session.isTest ? (
<CheckIcon
aria-hidden
className="size-4 text-charcoal-400 group-hover/table-row:text-text-bright"
/>
) : (
<span aria-hidden className="text-text-dimmed">
</span>
)}
</TableCell>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<TableCell to={sessionPath}>
{session.tags.length > 0 ? (
<div className="flex flex-wrap gap-1">
Expand All @@ -168,7 +183,7 @@ export function SessionsTable({
)}
{isLoading && (
<TableBlankRow
colSpan={8}
colSpan={9}
className="absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 bg-charcoal-900/90"
>
<Spinner /> <span className="text-text-dimmed">Loading…</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export class SessionListPresenter {
externalId: session.externalId,
type: session.type,
taskIdentifier: session.taskIdentifier,
isTest: session.isTest,
tags: session.tags ? [...session.tags].sort((a, b) => a.localeCompare(b)) : [],
status,
closedAt: session.closedAt ? session.closedAt.toISOString() : undefined,
Expand Down
1 change: 1 addition & 0 deletions apps/webapp/app/presenters/v3/SessionPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export class SessionPresenter {
externalId: session.externalId,
type: session.type,
taskIdentifier: session.taskIdentifier,
isTest: session.isTest,
tags: session.tags ? [...session.tags].sort((a, b) => a.localeCompare(b)) : [],
metadata: session.metadata,
triggerConfig: session.triggerConfig,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BoltIcon, BoltSlashIcon } from "@heroicons/react/20/solid";
import { BookOpenIcon } from "@heroicons/react/24/solid";
import { BookOpenIcon, CheckIcon } from "@heroicons/react/24/solid";
import { type MetaFunction } from "@remix-run/react";
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
import { useVirtualizer } from "@tanstack/react-virtual";
Expand Down Expand Up @@ -818,6 +818,19 @@ function OverviewTab({ session, status }: { session: LoadedSession; status: Sess
<span className="font-mono text-sm">{session.taskIdentifier}</span>
</Property.Value>
</Property.Item>
<Property.Item>
<Property.Label>Test</Property.Label>
<Property.Value>
<span className="sr-only">{session.isTest ? "Yes" : "No"}</span>
{session.isTest ? (
<CheckIcon aria-hidden className="size-4 text-text-dimmed" />
) : (
<span aria-hidden className="text-text-dimmed">
</span>
)}
</Property.Value>
</Property.Item>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{session.currentRun ? (
<Property.Item>
<Property.Label>Current run</Property.Label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
type: "chat.agent",
taskIdentifier: agentSlug,
triggerConfig: triggerConfig as unknown as Prisma.InputJsonValue,
tags: ["playground"],
// Mark as a Test session — surfaced via the Test column in the
// Sessions table. Session tags stay empty; the triggered run still
// carries "playground:true" via triggerConfig.tags.
isTest: true,
projectId: project.id,
runtimeEnvironmentId: environment.id,
environmentType: environment.type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,7 @@ function toSessionInsertArray(
session.expiresAt ? session.expiresAt.getTime() : null,
session.createdAt.getTime(),
session.updatedAt.getTime(),
session.isTest ?? false,
version.toString(),
isDeleted ? 1 : 0,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export class ClickHouseSessionsRepository implements ISessionsRepository {
externalId: true,
type: true,
taskIdentifier: true,
isTest: true,
tags: true,
metadata: true,
closedAt: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export type ListedSession = Prisma.SessionGetPayload<{
externalId: true;
type: true;
taskIdentifier: true;
isTest: true;
tags: true;
metadata: true;
closedAt: true;
Expand Down
2 changes: 2 additions & 0 deletions apps/webapp/test/sessionsReplicationService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ describe("SessionsReplicationService", () => {
},
tags: ["user:42", "plan:pro"],
metadata: { plan: "pro", seats: 3 },
isTest: true,
},
});

Expand Down Expand Up @@ -108,6 +109,7 @@ describe("SessionsReplicationService", () => {
environment_type: "DEVELOPMENT",
task_identifier: "my-agent",
tags: ["user:42", "plan:pro"],
is_test: 1,
_is_deleted: 0,
})
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- +goose Up
-- Existing rows default to 0 and are intentionally NOT backfilled: the Sessions
-- list reads isTest from Postgres (ClickHouse only supplies session IDs), so the
-- UI is correct without it. A backfill is only needed if a ClickHouse-side
-- isTest filter/aggregate over sessions_v1 is added later.
ALTER TABLE trigger_dev.sessions_v1
ADD COLUMN IF NOT EXISTS is_test UInt8 DEFAULT 0;

-- +goose Down
ALTER TABLE trigger_dev.sessions_v1
DROP COLUMN IF EXISTS is_test;
4 changes: 4 additions & 0 deletions internal-packages/clickhouse/src/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const SessionV1 = z.object({
expires_at: z.number().int().nullish(),
created_at: z.number().int(),
updated_at: z.number().int(),
is_test: z.boolean().default(false),
_version: z.string(),
_is_deleted: z.number().int().default(0),
});
Expand All @@ -43,6 +44,7 @@ export const SESSION_COLUMNS = [
"expires_at",
"created_at",
"updated_at",
"is_test",
"_version",
"_is_deleted",
] as const;
Expand Down Expand Up @@ -70,6 +72,7 @@ export type SessionFieldTypes = {
expires_at: number | null;
created_at: number;
updated_at: number;
is_test: boolean;
_version: string;
_is_deleted: number;
};
Expand All @@ -95,6 +98,7 @@ export type SessionInsertArray = [
expires_at: number | null,
created_at: number,
updated_at: number,
is_test: boolean,
_version: string,
_is_deleted: number,
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- AlterTable
ALTER TABLE "Session" ADD COLUMN "isTest" BOOLEAN NOT NULL DEFAULT false;

-- Backfill: legacy Test sessions were marked with a "playground" tag. Flag them
-- as test and strip the now-redundant tag (the Test column replaces it), so the
-- list and detail views render consistently without read-time tag filtering.
-- Bounded one-shot over the playground subset; matches existing in-migration
-- backfill precedent. (Prisma wraps each migration in a single transaction, so
-- batching with intermediate commits isn't possible here.)
UPDATE "Session"
SET "isTest" = true, "tags" = array_remove("tags", 'playground')
WHERE 'playground' = ANY("tags");
4 changes: 4 additions & 0 deletions internal-packages/database/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,10 @@ model Session {
/// (chatId, messages, trigger) are merged at trigger time.
triggerConfig Json

/// Whether this session was created from the Test/playground UI rather
/// than by a real chat.agent() trigger. Mirrors TaskRun.isTest.
isTest Boolean @default(false)

tags String[] @default([])
metadata Json?

Expand Down