murashit_codex-panel/src/runtime/view.ts

299 lines
13 KiB
TypeScript

import type { RateLimitWindow } from "../generated/app-server/v2/RateLimitWindow";
import type { ThreadTokenUsage } from "../generated/app-server/v2/ThreadTokenUsage";
import { jsonPreview } from "../utils";
import { sortedAvailableModels } from "./model";
import { readRuntimeConfig, type RuntimeConfigProjection } from "./config";
import {
currentApprovalsReviewer,
currentModel,
currentReasoningEffort,
autoReviewActive,
fastModeLabel,
runtimeOverrideLabel,
serviceTierLabel,
type RuntimeSnapshot,
} from "./state";
export interface ContextSummary {
label: string;
title: string;
percent: number | null;
level: "ok" | "warn" | "danger";
}
export interface RateLimitSummary {
title: string;
level: "ok" | "warn" | "danger";
rows: RateLimitSummaryRow[];
}
export interface RateLimitSummaryRow {
label: string;
value: string;
resetLabel: string | null;
title: string;
percent: number;
level: "ok" | "warn" | "danger";
}
export interface EffectiveConfigSection {
title: string;
rows: { key: string; value: string }[];
}
const CODEX_DEFAULT_LABEL = "(Codex default)";
const NOT_REPORTED_LABEL = "(not reported)";
export function contextSummary(snapshot: RuntimeSnapshot): ContextSummary | null {
const usage = snapshot.tokenUsage;
const config = readRuntimeConfig(snapshot.effectiveConfig);
const contextWindow = usage?.modelContextWindow ?? config.modelContextWindow;
if (!usage) {
if (!snapshot.activeThreadId) return null;
if (!snapshot.hasThreadTurns) {
return {
label: "Context 0%",
title: contextWindow
? `Context: 0 / ${formatTokenCount(contextWindow)} (0%). No turns in this thread yet.`
: "Context: 0 tokens. No turns in this thread yet.",
percent: 0,
level: "ok",
};
}
return {
label: "Context unknown",
title: contextWindow
? `Context usage is not available for this thread yet. It will update after the next token usage report. Context window: ${formatTokenCount(contextWindow)} tokens.`
: "Context usage is not available for this thread yet. It will update after the next token usage report.",
percent: null,
level: "ok",
};
}
const used = contextUsageTokens(usage);
const percent = contextWindow ? Math.min(100, Math.round((used / contextWindow) * 100)) : null;
const level = percent !== null && percent >= 90 ? "danger" : percent !== null && percent >= 70 ? "warn" : "ok";
const title = contextWindow
? `Context: ${formatTokenCount(used)} / ${formatTokenCount(contextWindow)} (${String(percent)}%). Last request: ${formatTokenCount(usage.last.inputTokens)} input, ${formatTokenCount(usage.last.outputTokens)} output, ${formatTokenCount(usage.last.reasoningOutputTokens)} reasoning. Total: ${formatTokenCount(usage.total.totalTokens)} tokens.`
: `Context: ${formatTokenCount(used)} tokens. Last request: ${formatTokenCount(usage.last.totalTokens)} total. Total: ${formatTokenCount(usage.total.totalTokens)} tokens.`;
return {
label: percent === null ? `${formatTokenCount(used)} tokens` : `Context ${String(percent)}%`,
title,
percent,
level,
};
}
export function rateLimitSummary(snapshot: RuntimeSnapshot, nowMs = Date.now()): RateLimitSummary | null {
const rateLimit = snapshot.rateLimit;
if (!rateLimit) return null;
const name = rateLimit.limitName ?? rateLimit.limitId ?? "Codex limit";
const reached = rateLimit.rateLimitReachedType !== null;
const rows = [
rateLimitWindowSummary("primary", rateLimit.primary, name, reached, rateLimit.rateLimitReachedType, nowMs),
rateLimitWindowSummary("secondary", rateLimit.secondary, name, reached, rateLimit.rateLimitReachedType, nowMs),
].filter((row): row is RateLimitSummaryRow => row !== null);
if (rows.length === 0) return null;
const level = rows.some((row) => row.level === "danger") ? "danger" : rows.some((row) => row.level === "warn") ? "warn" : "ok";
return {
title: `${name}: ${rows.map((row) => `${row.label} ${row.value}`).join(", ")}`,
rows,
level,
};
}
export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: string): EffectiveConfigSection[] {
const config = readRuntimeConfig(snapshot.effectiveConfig);
return [
{
title: "Scope",
rows: [
{ key: "cwd", value: vaultPath },
{ key: "profile", value: config.profile ?? "(default)" },
{ key: "model provider", value: stringValue(config.modelProvider, CODEX_DEFAULT_LABEL) },
],
},
{
title: "Runtime",
rows: [
{ key: "effective model", value: currentModel(snapshot, config) ?? CODEX_DEFAULT_LABEL },
{ key: "configured model", value: configuredModel(snapshot, config) ?? NOT_REPORTED_LABEL },
{ key: "thread model", value: activeRuntimeValueLabel(snapshot.activeModel) },
{ key: "requested model", value: runtimeOverrideLabel(snapshot.requestedModel) },
{ key: "effective effort", value: currentReasoningEffort(snapshot, config) ?? CODEX_DEFAULT_LABEL },
{ key: "configured effort", value: configuredReasoningEffort(snapshot, config) ?? NOT_REPORTED_LABEL },
{ key: "thread effort", value: activeRuntimeValueLabel(snapshot.activeReasoningEffort) },
{ key: "requested effort", value: runtimeOverrideLabel(snapshot.requestedReasoningEffort) },
{ key: "reasoning summary", value: stringValue(config.reasoningSummary, CODEX_DEFAULT_LABEL) },
{ key: "verbosity", value: stringValue(config.verbosity, CODEX_DEFAULT_LABEL) },
{ key: "effective mode", value: snapshot.activeCollaborationMode === "plan" ? "Plan" : "Default" },
{
key: "requested mode",
value:
snapshot.requestedCollaborationMode === snapshot.activeCollaborationMode
? "(none)"
: modeLabel(snapshot.requestedCollaborationMode),
},
{ key: "effective service tier", value: serviceTierLabel(snapshot, config) },
{ key: "configured service tier", value: config.serviceTier ?? CODEX_DEFAULT_LABEL },
{ key: "thread service tier", value: activeRuntimeValueLabel(snapshot.activeServiceTier) },
{ key: "requested service tier", value: snapshot.requestedServiceTier ?? "(none)" },
{ key: "fast mode", value: fastModeLabel(snapshot, config) },
{ key: "context window", value: tokenLimitLabel(config.modelContextWindow) },
{ key: "auto compact limit", value: tokenLimitLabel(config.autoCompactTokenLimit) },
],
},
{
title: "Policy",
rows: [
{ key: "approval", value: stringValue(config.approvalPolicy, CODEX_DEFAULT_LABEL) },
{ key: "effective reviewer", value: currentApprovalsReviewer(snapshot, config) ?? NOT_REPORTED_LABEL },
{ key: "auto-review", value: autoReviewActive(snapshot, config) ? "on" : "off" },
{ key: "configured reviewer", value: config.approvalsReviewer ?? CODEX_DEFAULT_LABEL },
{ key: "thread reviewer", value: activeRuntimeValueLabel(snapshot.activeApprovalsReviewer) },
{ key: "requested reviewer", value: snapshot.requestedApprovalsReviewer ?? "(none)" },
{ key: "sandbox", value: stringValue(config.sandboxMode, CODEX_DEFAULT_LABEL) },
{ key: "workspace network", value: stringValue(config.workspaceNetworkAccess, CODEX_DEFAULT_LABEL) },
{ key: "writable roots", value: writableRootsLabel(config.writableRoots) },
{ key: "web search", value: stringValue(config.webSearch, CODEX_DEFAULT_LABEL) },
],
},
{
title: "Features",
rows: [
{ key: "hooks", value: stringValue(config.hooksEnabled, CODEX_DEFAULT_LABEL) },
{ key: "apply_patch freeform", value: stringValue(config.applyPatchFreeformEnabled, CODEX_DEFAULT_LABEL) },
{ key: "tool web search", value: stringValue(config.toolWebSearch, CODEX_DEFAULT_LABEL) },
{ key: "apps", value: enabledAppsLabel(config.apps) },
],
},
];
}
function contextUsageTokens(usage: ThreadTokenUsage): number {
return usage.last.inputTokens > 0 ? usage.last.inputTokens : usage.last.totalTokens;
}
function configuredModel(snapshot: RuntimeSnapshot, config: RuntimeConfigProjection): string | null {
if (config.model) return config.model;
return sortedAvailableModels(snapshot.availableModels).find((model) => model.isDefault)?.model ?? null;
}
function configuredReasoningEffort(snapshot: RuntimeSnapshot, config: RuntimeConfigProjection): string | null {
if (config.rawReasoningEffort) return config.rawReasoningEffort;
const model = configuredModel(snapshot, config);
return (
sortedAvailableModels(snapshot.availableModels).find((availableModel) => availableModel.model === model)?.defaultReasoningEffort ?? null
);
}
function modeLabel(mode: RuntimeSnapshot["requestedCollaborationMode"]): string {
return mode === "plan" ? "Plan" : "Default";
}
function activeRuntimeValueLabel(value: string | null): string {
return value ?? NOT_REPORTED_LABEL;
}
function rateLimitWindowSummary(
fallbackLabel: string,
window: RateLimitWindow | null,
name: string,
reached: boolean,
reachedType: string | null,
nowMs: number,
): RateLimitSummaryRow | null {
if (!window) return null;
const percent = Math.max(0, Math.min(100, Math.round(window.usedPercent)));
const level = reached || percent >= 90 ? "danger" : percent >= 70 ? "warn" : "ok";
const label = window.windowDurationMins ? formatRateLimitDuration(window.windowDurationMins) : fallbackLabel;
const resetLabel = window.resetsAt ? formatRateLimitRemaining(window.resetsAt, nowMs) : null;
const resetText = window.resetsAt && resetLabel ? ` ${capitalize(resetLabel)}. Reset at ${formatRateLimitReset(window.resetsAt)}.` : "";
const reachedText = reached ? ` ${String(reachedType)}.` : "";
return {
label,
value: `${String(percent)}%`,
resetLabel,
title: `${name} ${label}: ${String(percent)}% used.${resetText}${reachedText}`,
percent,
level,
};
}
function formatRateLimitDuration(minutes: number): string {
if (minutes === 10_080) return "1w";
if (minutes % 60 === 0) return `${String(minutes / 60)}h`;
return `${String(minutes)}m`;
}
function formatRateLimitReset(resetsAt: number): string {
return new Date(resetsAt * 1000).toLocaleString(undefined, { dateStyle: "medium", timeStyle: "short" });
}
function formatRateLimitRemaining(resetsAt: number, nowMs: number): string {
const remainingSeconds = Math.ceil((resetsAt * 1000 - nowMs) / 1000);
if (remainingSeconds <= 0) return "reset due";
if (remainingSeconds < 60) return "reset in <1m";
const minutes = Math.ceil(remainingSeconds / 60);
if (minutes < 60) return `reset in ${String(minutes)}m`;
const hours = Math.floor(minutes / 60);
const remainderMinutes = minutes % 60;
if (hours < 24) return `reset in ${String(hours)}h${remainderMinutes > 0 ? ` ${String(remainderMinutes)}m` : ""}`;
const days = Math.floor(hours / 24);
const remainderHours = hours % 24;
return `reset in ${String(days)}d${remainderHours > 0 ? ` ${String(remainderHours)}h` : ""}`;
}
function capitalize(value: string): string {
return value.length === 0 ? value : value.charAt(0).toUpperCase() + value.slice(1);
}
function tokenLimitLabel(value: unknown): string {
const tokens = toNumber(value);
return tokens === null ? CODEX_DEFAULT_LABEL : formatTokenCount(tokens);
}
function writableRootsLabel(value: unknown): string {
if (!Array.isArray(value)) return CODEX_DEFAULT_LABEL;
if (value.length === 0) return "none";
if (value.length === 1) return String(value[0]);
return `${String(value.length)} roots`;
}
function enabledAppsLabel(apps: unknown): string {
const appConfig = asRecord(apps);
const enabled = Object.entries(appConfig)
.filter(([key, app]) => key !== "_default" && asRecord(app)["enabled"] === true)
.map(([key]) => key)
.sort();
if (enabled.length > 0) return enabled.join(", ");
const defaultConfig = asRecord(appConfig["_default"]);
return stringValue(defaultConfig["enabled"], CODEX_DEFAULT_LABEL);
}
function asRecord(value: unknown): Record<string, unknown> {
return value && typeof value === "object" ? (value as Record<string, unknown>) : {};
}
function stringValue(value: unknown, fallback = ""): string {
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
if (value === null || value === undefined) return fallback;
return jsonPreview(value);
}
function toNumber(value: unknown): number | null {
if (typeof value === "number") return Number.isFinite(value) ? value : null;
if (typeof value === "bigint") return Number(value);
return null;
}
function formatTokenCount(value: number): string {
return new Intl.NumberFormat("en-US").format(Math.round(value));
}