forked from EduCraft/curriculum-project-hub
aaa098bb8b
Co-authored-by: Hong Jiarong <me@jrhim.com> Co-committed-by: Hong Jiarong <me@jrhim.com>
150 lines
4.1 KiB
TypeScript
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,
|
|
})),
|
|
})),
|
|
};
|
|
}
|