From 6d9fa93d2299aa459419e56482e39a939b7dfcfb Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 12 Jun 2026 21:26:41 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20combine=20usageRecord=20red?= =?UTF-8?q?uce=20calls=20into=20a=20single=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sessions/[sessionId]/route.ts | 31 ++++++++++++------- .../[orgSlug]/dashboard/sessions/route.ts | 17 +++++----- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts index 35486b8..4a5cbe6 100644 --- a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts +++ b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/[sessionId]/route.ts @@ -43,18 +43,25 @@ export async function GET( return forbiddenByRole(access.role, '본인 세션만 열람 가능') } - const totalInput = session.usageRecords.reduce((sum, r) => sum + r.inputTokens, 0) - const totalOutput = session.usageRecords.reduce((sum, r) => sum + r.outputTokens, 0) - const totalCost = session.usageRecords.reduce((sum, r) => sum + (r.estimatedCostUsd ?? 0), 0) - - const usageTimeline: SessionTimelineUsage[] = session.usageRecords.map((r) => ({ - timestamp: r.timestamp.toISOString(), - inputTokens: r.inputTokens, - outputTokens: r.outputTokens, - estimatedCostUsd: r.estimatedCostUsd ?? 0, - model: r.model, - isSubagent: r.isSubagent, - })) + let totalInput = 0 + let totalOutput = 0 + let totalCost = 0 + const usageTimeline: SessionTimelineUsage[] = [] + + for (const r of session.usageRecords) { + totalInput += r.inputTokens + totalOutput += r.outputTokens + totalCost += r.estimatedCostUsd ?? 0 + + usageTimeline.push({ + timestamp: r.timestamp.toISOString(), + inputTokens: r.inputTokens, + outputTokens: r.outputTokens, + estimatedCostUsd: r.estimatedCostUsd ?? 0, + model: r.model, + isSubagent: r.isSubagent, + }) + } // 각 UsageRecord를 "직전 ASSISTANT 턴"에 귀속시켜 메시지별 토큰/비용/모델 집계. // TOOL 메시지는 건너뛰고 가장 가까운 선행 ASSISTANT로 타고 올라감. diff --git a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts index 25fbe70..7d6a4d4 100644 --- a/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts +++ b/packages/web/src/app/api/orgs/[orgSlug]/dashboard/sessions/route.ts @@ -33,14 +33,17 @@ const sessionInclude = { type SessionWithInclude = Prisma.ClaudeSessionGetPayload<{ include: typeof sessionInclude }> function getSessionTotals(session: SessionWithInclude) { - return { - inputTokens: session.usageRecords.reduce((sum, r) => sum + r.inputTokens, 0), - outputTokens: session.usageRecords.reduce((sum, r) => sum + r.outputTokens, 0), - estimatedCostUsd: session.usageRecords.reduce( - (sum, r) => sum + (r.estimatedCostUsd ?? 0), - 0, - ), + let inputTokens = 0 + let outputTokens = 0 + let estimatedCostUsd = 0 + + for (const r of session.usageRecords) { + inputTokens += r.inputTokens + outputTokens += r.outputTokens + estimatedCostUsd += r.estimatedCostUsd ?? 0 } + + return { inputTokens, outputTokens, estimatedCostUsd } } function mapSessionItem(session: SessionWithInclude): SessionItem {