1import type { RelayAgentActivityAggregateState } from "@t3tools/contracts/relay";
2
3import type { AgentActivityProps } from "./AgentActivity";
4
5// The widget only refreshes while the app is open, so after this long it stops
6// claiming an agent is still working. Matches the Live Activity's stale date.
7export const AGENT_ACTIVITY_WIDGET_STALE_AFTER_MS = 10 * 60_000;
8
9export type AgentActivityWidgetSource =
10 | { readonly kind: "signed-out" }
11 | { readonly kind: "unavailable" }
12 | { readonly kind: "loading" }
13 | { readonly kind: "snapshot"; readonly aggregate: RelayAgentActivityAggregateState | null };
14
15export function agentActivityWidgetTimeline(source: AgentActivityWidgetSource, now: number) {
16 const updatedAt = new Date(now).toISOString();
17 if (source.kind !== "snapshot" || !source.aggregate) {
18 const props: AgentActivityProps = {
19 title: "T3 Code",
20 subtitle:
21 source.kind === "signed-out"
22 ? "Sign in to T3 Connect to see agents"
23 : source.kind === "unavailable"
24 ? "Couldn't reach T3 Connect"
25 : source.kind === "loading"
26 ? "Loading agents…"
27 : "No active agents",
28 activeCount: 0,
29 updatedAt,
30 activities: [],
31 };
32 return [{ date: new Date(now), props }];
33 }
34
35 const { aggregate } = source;
36 const props: AgentActivityProps = {
37 title: aggregate.title,
38 subtitle: aggregate.subtitle,
39 activeCount: aggregate.activeCount,
40 updatedAt: aggregate.updatedAt,
41 activities: aggregate.activities,
42 };
43 const hasInFlightRows = props.activities.some(
44 (row) => row.phase !== "completed" && row.phase !== "failed",
45 );
46 if (!hasInFlightRows) {
47 return [{ date: new Date(now), props }];
48 }
49 const staleProps: AgentActivityProps = {
50 ...props,
51 activities: props.activities.map((row) =>
52 row.phase === "completed" || row.phase === "failed"
53 ? row
54 : { ...row, phase: "stale", status: "Out of date" },
55 ),
56 };
57 return [
58 { date: new Date(now), props },
59 { date: new Date(now + AGENT_ACTIVITY_WIDGET_STALE_AFTER_MS), props: staleProps },
60 ];
61}