import type { OrchestrationV2ProviderTurnTokenUsage, OrchestrationV2TurnItem, ThreadTokenUsageSnapshot,} from "@t3tools/contracts";import * as DateTime from "effect/DateTime"; function asFiniteNumber(value: unknown): number | null { return typeof value === "number" && Number.isFinite(value) ? value : null;} type NullableContextWindowUsage = { readonly [Key in keyof ThreadTokenUsageSnapshot]: undefined extends ThreadTokenUsageSnapshot[Key] ? Exclude<ThreadTokenUsageSnapshot[Key], undefined> | null : ThreadTokenUsageSnapshot[Key];}; export type ContextWindowSnapshot = NullableContextWindowUsage & { readonly remainingTokens: number | null; readonly usedPercentage: number | null; readonly remainingPercentage: number | null; readonly updatedAt: string;}; /** Prefers the provider's live usage report (#8144); falls back to the last compaction item. */export function deriveLatestContextWindowSnapshot( entries: ReadonlyArray<{ readonly item: OrchestrationV2TurnItem; }>, liveUsage?: OrchestrationV2ProviderTurnTokenUsage | null,): ContextWindowSnapshot | null { if (liveUsage != null) { const usedTokens = Math.max(0, liveUsage.usedTokens); const maxTokens = liveUsage.maxTokens ?? null; const usedPercentage = maxTokens !== null && maxTokens > 0 ? Math.min(100, (usedTokens / maxTokens) * 100) : null; const remainingTokens = maxTokens !== null ? Math.max(0, Math.round(maxTokens - usedTokens)) : null; const remainingPercentage = usedPercentage !== null ? Math.max(0, 100 - usedPercentage) : null; return { usedTokens, totalProcessedTokens: null, maxTokens, remainingTokens, usedPercentage, remainingPercentage, inputTokens: liveUsage.inputTokens ?? null, cachedInputTokens: liveUsage.cachedInputTokens ?? null, outputTokens: liveUsage.outputTokens ?? null, reasoningOutputTokens: liveUsage.reasoningOutputTokens ?? null, lastUsedTokens: null, lastInputTokens: null, lastCachedInputTokens: null, lastOutputTokens: null, lastReasoningOutputTokens: null, toolUses: null, durationMs: null, compactsAutomatically: true, autoCompactThreshold: null, updatedAt: liveUsage.updatedAt, }; } for (let index = entries.length - 1; index >= 0; index -= 1) { const entry = entries[index]; if (!entry || entry.item.type !== "compaction") { continue; } const payload = entry.item; const usedTokens = asFiniteNumber(payload.afterTokenCount); if (usedTokens === null || usedTokens < 0) { continue; } const maxTokens = null; const usedPercentage = maxTokens !== null && maxTokens > 0 ? Math.min(100, (usedTokens / maxTokens) * 100) : null; const remainingTokens = maxTokens !== null ? Math.max(0, Math.round(maxTokens - usedTokens)) : null; const remainingPercentage = usedPercentage !== null ? Math.max(0, 100 - usedPercentage) : null; return { usedTokens, totalProcessedTokens: asFiniteNumber(payload.beforeTokenCount), maxTokens, remainingTokens, usedPercentage, remainingPercentage, inputTokens: null, cachedInputTokens: null, outputTokens: null, reasoningOutputTokens: null, lastUsedTokens: null, lastInputTokens: null, lastCachedInputTokens: null, lastOutputTokens: null, lastReasoningOutputTokens: null, toolUses: null, durationMs: null, compactsAutomatically: true, autoCompactThreshold: null, updatedAt: DateTime.formatIso(payload.startedAt ?? payload.updatedAt), }; } return null;} export function formatContextWindowTokens(value: number | null): string { if (value === null || !Number.isFinite(value)) { return "0"; } if (value < 1_000) { return `${Math.round(value)}`; } if (value < 10_000) { return `${(value / 1_000).toFixed(1).replace(/\.0$/, "")}k`; } if (value < 1_000_000) { return `${Math.round(value / 1_000)}k`; } return `${(value / 1_000_000).toFixed(1).replace(/\.0$/, "")}m`;}
import type {
OrchestrationV2ProviderTurnTokenUsage,
OrchestrationV2TurnItem,
ThreadTokenUsageSnapshot,
} from "@t3tools/contracts";
import * as DateTime from "effect/DateTime";
function asFiniteNumber(value: unknown): number | null {
return typeof value === "number" && Number.isFinite(value) ? value : null;
}
type NullableContextWindowUsage = {
readonly [Key in keyof ThreadTokenUsageSnapshot]: undefined extends ThreadTokenUsageSnapshot[Key]
? Exclude<ThreadTokenUsageSnapshot[Key], undefined> | null
: ThreadTokenUsageSnapshot[Key];
};
export type ContextWindowSnapshot = NullableContextWindowUsage & {
readonly remainingTokens: number | null;
readonly usedPercentage: number | null;
readonly remainingPercentage: number | null;
readonly updatedAt: string;
};
/** Prefers the provider's live usage report (#8144); falls back to the last compaction item. */
export function deriveLatestContextWindowSnapshot(
entries: ReadonlyArray<{
readonly item: OrchestrationV2TurnItem;
}>,
liveUsage?: OrchestrationV2ProviderTurnTokenUsage | null,
): ContextWindowSnapshot | null {
if (liveUsage != null) {
const usedTokens = Math.max(0, liveUsage.usedTokens);
const maxTokens = liveUsage.maxTokens ?? null;
const usedPercentage =
maxTokens !== null && maxTokens > 0 ? Math.min(100, (usedTokens / maxTokens) * 100) : null;
const remainingTokens =
maxTokens !== null ? Math.max(0, Math.round(maxTokens - usedTokens)) : null;
const remainingPercentage = usedPercentage !== null ? Math.max(0, 100 - usedPercentage) : null;
return {
usedTokens,
totalProcessedTokens: null,
maxTokens,
remainingTokens,
usedPercentage,
remainingPercentage,
inputTokens: liveUsage.inputTokens ?? null,
cachedInputTokens: liveUsage.cachedInputTokens ?? null,
outputTokens: liveUsage.outputTokens ?? null,
reasoningOutputTokens: liveUsage.reasoningOutputTokens ?? null,
lastUsedTokens: null,
lastInputTokens: null,
lastCachedInputTokens: null,
lastOutputTokens: null,
lastReasoningOutputTokens: null,
toolUses: null,
durationMs: null,
compactsAutomatically: true,
autoCompactThreshold: null,
updatedAt: liveUsage.updatedAt,
};
}
for (let index = entries.length - 1; index >= 0; index -= 1) {
const entry = entries[index];
if (!entry || entry.item.type !== "compaction") {
continue;
}
const payload = entry.item;
const usedTokens = asFiniteNumber(payload.afterTokenCount);
if (usedTokens === null || usedTokens < 0) {
continue;
}
const maxTokens = null;
const usedPercentage =
maxTokens !== null && maxTokens > 0 ? Math.min(100, (usedTokens / maxTokens) * 100) : null;
const remainingTokens =
maxTokens !== null ? Math.max(0, Math.round(maxTokens - usedTokens)) : null;
const remainingPercentage = usedPercentage !== null ? Math.max(0, 100 - usedPercentage) : null;
return {
usedTokens,
totalProcessedTokens: asFiniteNumber(payload.beforeTokenCount),
maxTokens,
remainingTokens,
usedPercentage,
remainingPercentage,
inputTokens: null,
cachedInputTokens: null,
outputTokens: null,
reasoningOutputTokens: null,
lastUsedTokens: null,
lastInputTokens: null,
lastCachedInputTokens: null,
lastOutputTokens: null,
lastReasoningOutputTokens: null,
toolUses: null,
durationMs: null,
compactsAutomatically: true,
autoCompactThreshold: null,
updatedAt: DateTime.formatIso(payload.startedAt ?? payload.updatedAt),
};
}
return null;
}
export function formatContextWindowTokens(value: number | null): string {
if (value === null || !Number.isFinite(value)) {
return "0";
}
if (value < 1_000) {
return `${Math.round(value)}`;
}
if (value < 10_000) {
return `${(value / 1_000).toFixed(1).replace(/\.0$/, "")}k`;
}
if (value < 1_000_000) {
return `${Math.round(value / 1_000)}k`;
}
return `${(value / 1_000_000).toFixed(1).replace(/\.0$/, "")}m`;
}