Skip to content

Commit 87863ef

Browse files
committed
feat(agents): show last used timestamp on agent card and settings
1 parent 9bd12b9 commit 87863ef

4 files changed

Lines changed: 65 additions & 6 deletions

File tree

apps/mesh/src/storage/virtual.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,12 @@ export class VirtualMCPStorage implements VirtualMCPStoragePort {
183183
.where("dependency_mode", "=", "direct")
184184
.execute();
185185

186+
const lastUsedMap = await this.fetchLastUsed([id]);
187+
186188
return this.deserializeVirtualMCPEntity(
187189
row as unknown as RawConnectionRow,
188190
aggregationRows as RawAggregationRow[],
191+
lastUsedMap.get(id),
189192
);
190193
}
191194

@@ -227,10 +230,13 @@ export class VirtualMCPStorage implements VirtualMCPStoragePort {
227230
aggregationsByParent.set(agg.parent_connection_id, existing);
228231
}
229232

233+
const lastUsedMap = await this.fetchLastUsed(virtualMcpIds);
234+
230235
return rows.map((row) =>
231236
this.deserializeVirtualMCPEntity(
232237
row as unknown as RawConnectionRow,
233238
aggregationsByParent.get(row.id) ?? [],
239+
lastUsedMap.get(row.id),
234240
),
235241
);
236242
}
@@ -483,12 +489,47 @@ export class VirtualMCPStorage implements VirtualMCPStoragePort {
483489
}
484490
}
485491

492+
/**
493+
* Returns the most recent thread per agent (by created_at) with the user who started it.
494+
*/
495+
private async fetchLastUsed(
496+
ids: string[],
497+
): Promise<Map<string, { last_used_at: string; last_used_by: string }>> {
498+
if (ids.length === 0) return new Map();
499+
500+
const rows = await this.db
501+
.selectFrom("threads")
502+
.distinctOn("virtual_mcp_id")
503+
.select(["virtual_mcp_id", "created_by", "created_at"])
504+
.where("virtual_mcp_id", "in", ids)
505+
.orderBy("virtual_mcp_id")
506+
.orderBy("created_at", "desc")
507+
.execute();
508+
509+
const result = new Map<
510+
string,
511+
{ last_used_at: string; last_used_by: string }
512+
>();
513+
for (const row of rows) {
514+
const at =
515+
row.created_at instanceof Date
516+
? row.created_at.toISOString()
517+
: String(row.created_at);
518+
result.set(row.virtual_mcp_id, {
519+
last_used_at: at,
520+
last_used_by: row.created_by,
521+
});
522+
}
523+
return result;
524+
}
525+
486526
/**
487527
* Deserialize connection row with aggregations to VirtualMCPEntity
488528
*/
489529
private deserializeVirtualMCPEntity(
490530
row: RawConnectionRow,
491531
aggregationRows: RawAggregationRow[],
532+
lastUsed?: { last_used_at: string; last_used_by: string },
492533
): VirtualMCPEntity {
493534
// Convert Date to ISO string if needed
494535
const createdAt =
@@ -518,6 +559,8 @@ export class VirtualMCPStorage implements VirtualMCPStoragePort {
518559
updated_at: updatedAt,
519560
created_by: row.created_by,
520561
updated_by: row.updated_by ?? undefined,
562+
last_used_at: lastUsed?.last_used_at,
563+
last_used_by: lastUsed?.last_used_by,
521564
metadata: {
522565
...metadata,
523566
instructions: metadata?.instructions ?? null,

apps/mesh/src/web/components/project-card.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ export function ProjectCard({ project, onDeleteClick }: ProjectCardProps) {
9191
<div className="border-t border-border mt-auto">
9292
<div className="h-10 flex items-center px-4.5">
9393
<p className="text-xs text-muted-foreground">
94-
{formatDistanceToNow(new Date(project.updated_at), {
95-
addSuffix: true,
96-
})}
94+
{project.last_used_at
95+
? `Last used ${formatDistanceToNow(new Date(project.last_used_at), { addSuffix: true })}`
96+
: `Updated ${formatDistanceToNow(new Date(project.updated_at), { addSuffix: true })}`}
9797
</p>
9898
</div>
9999
</div>

apps/mesh/src/web/views/virtual-mcp/index.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { formatDistanceToNow } from "date-fns";
12
import { generatePrefixedId } from "@/shared/utils/generate-id";
23
import type { VirtualMCPEntity } from "@/tools/virtual/schema";
34
import { getUIResourceUri } from "@/mcp-apps/types.ts";
@@ -1548,20 +1549,27 @@ Define step-by-step how the agent should handle requests.
15481549
</div>
15491550

15501551
{/* Creator metadata */}
1551-
<div className="flex items-center gap-2 -mt-6 text-muted-foreground">
1552+
<div className="flex items-center gap-2 -mt-6 text-sm text-muted-foreground">
15521553
<User
15531554
id={virtualMcp.created_by}
15541555
size="2xs"
15551556
className="text-sm text-muted-foreground"
15561557
/>
1557-
<span className="text-muted-foreground/50 text-sm">·</span>
1558-
<span className="text-sm">
1558+
<span className="text-muted-foreground/50">·</span>
1559+
<span>
1560+
Created{" "}
15591561
{new Date(virtualMcp.created_at).toLocaleDateString("en-US", {
15601562
month: "short",
15611563
day: "numeric",
15621564
year: "numeric",
15631565
})}
15641566
</span>
1567+
<span className="text-muted-foreground/50">·</span>
1568+
<span>
1569+
{virtualMcp.last_used_at
1570+
? `Last used ${formatDistanceToNow(new Date(virtualMcp.last_used_at), { addSuffix: true })}`
1571+
: "Never used"}
1572+
</span>
15651573
</div>
15661574

15671575
{/* Connections section */}

packages/mesh-sdk/src/types/virtual-mcp.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,14 @@ export const VirtualMCPEntitySchema = z.object({
196196
.string()
197197
.optional()
198198
.describe("User ID who last updated this item"),
199+
last_used_at: z
200+
.string()
201+
.optional()
202+
.describe("Timestamp of most recent thread creation for this agent"),
203+
last_used_by: z
204+
.string()
205+
.optional()
206+
.describe("User ID who most recently used this agent"),
199207

200208
// Entity-specific fields
201209
organization_id: z.string().describe("Organization ID this item belongs to"),

0 commit comments

Comments
 (0)