























@@ -13,13 +13,14 @@ import type {
1313SessionModelUsage,
1414} from "../../infra/session-cost-usage.js";
1515import {
16-loadCostUsageSummary,
16+loadCostUsageSummaryFromCache,
1717loadSessionLogs,
18-loadSessionCostSummary,
18+loadSessionCostSummaryFromCache,
1919loadSessionUsageTimeSeries,
2020discoverAllSessions,
2121resolveExistingUsageSessionFile,
2222type DiscoveredSession,
23+type UsageCacheStatus,
2324} from "../../infra/session-cost-usage.js";
2425import { parseAgentSessionKey } from "../../routing/session-key.js";
2526import { resolvePreferredSessionKeyForSessionIdMatches } from "../../sessions/session-id-resolution.js";
@@ -313,6 +314,7 @@ async function discoverAllSessionsForUsage(params: {
313314agentId: agent.id,
314315startMs: params.startMs,
315316endMs: params.endMs,
317+includeFirstUserMessage: false,
316318});
317319return sessions.map((session) => Object.assign({}, session, { agentId: agent.id }));
318320}),
@@ -328,7 +330,12 @@ async function loadCostUsageSummaryCached(params: {
328330const cacheKey = `${params.startMs}-${params.endMs}`;
329331const now = Date.now();
330332const cached = costUsageCache.get(cacheKey);
331-if (cached?.summary && cached.updatedAt && now - cached.updatedAt < COST_USAGE_CACHE_TTL_MS) {
333+if (
334+cached?.summary &&
335+cached.updatedAt &&
336+now - cached.updatedAt < COST_USAGE_CACHE_TTL_MS &&
337+cached.summary.cacheStatus?.status !== "refreshing"
338+) {
332339return cached.summary;
333340}
334341@@ -340,13 +347,18 @@ async function loadCostUsageSummaryCached(params: {
340347}
341348342349const entry: CostUsageCacheEntry = cached ?? {};
343-const inFlight = loadCostUsageSummary({
350+const inFlight = loadCostUsageSummaryFromCache({
344351startMs: params.startMs,
345352endMs: params.endMs,
346353config: params.config,
354+requestRefresh: true,
355+refreshMode: "sync-when-empty",
347356})
348357.then((summary) => {
349-setCostUsageCache(cacheKey, { summary, updatedAt: Date.now() });
358+setCostUsageCache(cacheKey, {
359+ summary,
360+updatedAt: summary.cacheStatus?.status === "refreshing" ? undefined : Date.now(),
361+});
350362return summary;
351363})
352364.catch((err) => {
@@ -372,6 +384,28 @@ async function loadCostUsageSummaryCached(params: {
372384return await inFlight;
373385}
374386387+function mergeUsageCacheStatus(
388+target: UsageCacheStatus | undefined,
389+source: UsageCacheStatus,
390+): UsageCacheStatus {
391+if (!target) {
392+return { ...source };
393+}
394+const statusRank = { fresh: 0, partial: 1, stale: 2, refreshing: 3 } as const;
395+return {
396+status: statusRank[source.status] > statusRank[target.status] ? source.status : target.status,
397+cachedFiles: target.cachedFiles + source.cachedFiles,
398+pendingFiles: target.pendingFiles + source.pendingFiles,
399+staleFiles: target.staleFiles + source.staleFiles,
400+refreshedAt:
401+target.refreshedAt === undefined
402+ ? source.refreshedAt
403+ : source.refreshedAt === undefined
404+ ? target.refreshedAt
405+ : Math.max(target.refreshedAt, source.refreshedAt),
406+};
407+}
408+375409// Exposed for unit tests (kept as a single export to avoid widening the public API surface).
376410export const __test = {
377411 parseDateParts,
@@ -598,6 +632,7 @@ export const usageHandlers: GatewayRequestHandlers = {
598632{ date: string; count: number; sum: number; min: number; max: number; p95Max: number }
599633>();
600634const modelDailyMap = new Map<string, SessionDailyModelUsage>();
635+let cacheStatus: UsageCacheStatus | undefined;
601636602637const emptyTotals = (): CostUsageSummary["totals"] => ({
603638input: 0,
@@ -631,15 +666,18 @@ export const usageHandlers: GatewayRequestHandlers = {
631666632667for (const merged of limitedEntries) {
633668const agentId = parseAgentSessionKey(merged.key)?.agentId;
634-const usage = await loadSessionCostSummary({
669+const cachedUsage = await loadSessionCostSummaryFromCache({
635670sessionId: merged.sessionId,
636671sessionEntry: merged.storeEntry,
637672sessionFile: merged.sessionFile,
638673 config,
639674 agentId,
640675 startMs,
641676 endMs,
677+refreshMode: "sync-when-empty",
642678});
679+cacheStatus = mergeUsageCacheStatus(cacheStatus, cachedUsage.cacheStatus);
680+const usage = cachedUsage.summary;
643681644682if (usage) {
645683aggregateTotals.input += usage.input;
@@ -843,6 +881,7 @@ export const usageHandlers: GatewayRequestHandlers = {
843881 sessions,
844882totals: aggregateTotals,
845883 aggregates,
884+ cacheStatus,
846885};
847886848887respond(true, result, undefined);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。