Files
curriculum-project-hub/hub/src/org/sessions.ts
T
2026-07-18 14:46:41 +08:00

150 lines
4.1 KiB
TypeScript

/**
* Agent session / run listing for org admin.
*/
import type { PrismaClient } from "@prisma/client";
export async function listProjectSessions(
prisma: PrismaClient,
input: {
readonly organizationId: string;
readonly projectId: string;
readonly limit?: number | undefined;
},
) {
const project = await prisma.project.findFirst({
where: { id: input.projectId, organizationId: input.organizationId },
select: { id: true },
});
if (project === null) {
throw new Error(`project not found: ${input.projectId}`);
}
const limit = Math.min(Math.max(input.limit ?? 50, 1), 200);
const sessions = await prisma.agentSession.findMany({
where: { projectId: project.id, archivedAt: null },
select: {
id: true,
provider: true,
roleId: true,
model: true,
title: true,
createdAt: true,
updatedAt: true,
_count: { select: { runs: true } },
},
orderBy: { updatedAt: "desc" },
take: limit,
});
return sessions.map((s) => ({
id: s.id,
provider: s.provider,
roleId: s.roleId,
model: s.model,
title: s.title,
runCount: s._count.runs,
createdAt: s.createdAt.toISOString(),
updatedAt: s.updatedAt.toISOString(),
}));
}
export async function getSessionDetail(
prisma: PrismaClient,
input: { readonly organizationId: string; readonly sessionId: string },
) {
const session = await prisma.agentSession.findUnique({
where: { id: input.sessionId },
select: {
id: true,
provider: true,
roleId: true,
model: true,
title: true,
createdAt: true,
updatedAt: true,
archivedAt: true,
project: {
select: { id: true, name: true, organizationId: true },
},
runs: {
select: {
id: true,
status: true,
model: true,
provider: true,
inputTokens: true,
outputTokens: true,
costUsd: true,
costSource: true,
startedAt: true,
finishedAt: true,
error: true,
usageFacts: {
select: {
id: true,
occurredAt: true,
kind: true,
provider: true,
model: true,
inputTokens: true,
outputTokens: true,
quantity: true,
unit: true,
costUsd: true,
costSource: true,
capabilityId: true,
correlationId: true,
},
orderBy: { occurredAt: "asc" },
},
},
orderBy: { startedAt: "desc" },
take: 100,
},
},
});
if (session === null || session.project.organizationId !== input.organizationId) {
throw new Error(`session not found: ${input.sessionId}`);
}
return {
id: session.id,
provider: session.provider,
roleId: session.roleId,
model: session.model,
title: session.title,
createdAt: session.createdAt.toISOString(),
updatedAt: session.updatedAt.toISOString(),
archivedAt: session.archivedAt?.toISOString() ?? null,
project: {
id: session.project.id,
name: session.project.name,
},
runs: session.runs.map((r) => ({
id: r.id,
status: r.status,
model: r.model,
provider: r.provider,
inputTokens: r.inputTokens,
outputTokens: r.outputTokens,
costUsd: r.costUsd === null ? null : Number(r.costUsd),
costSource: r.costSource,
startedAt: r.startedAt.toISOString(),
finishedAt: r.finishedAt?.toISOString() ?? null,
error: r.error,
usageFacts: r.usageFacts.map((f) => ({
id: f.id,
occurredAt: f.occurredAt.toISOString(),
kind: f.kind,
provider: f.provider,
model: f.model,
inputTokens: f.inputTokens,
outputTokens: f.outputTokens,
quantity: f.quantity === null ? null : Number(f.quantity),
unit: f.unit,
costUsd: f.costUsd === null ? null : Number(f.costUsd),
costSource: f.costSource,
capabilityId: f.capabilityId,
correlationId: f.correlationId,
})),
})),
};
}