返回 DeepSeek-Reasonix
contextMaintenanceTypes.ts
根目录 / desktop / frontend / src / lib / contextMaintenanceTypes.ts
1 import type { Translator } from "./i18n";
2
3 export type ContextMaintenanceStatus = "planned" | "applied" | "noop" | "blocked" | "failed";
4 /** New writers emit summary | noop | truncate (the lossy ceiling rescue). snip/prune/native are legacy restore-only. */
5 export type ContextMaintenanceAction = "summary" | "noop" | "truncate" | "snip" | "prune" | "native_tool_clear";
6
7 export interface WireContextMaintenance {
8 status?: ContextMaintenanceStatus;
9 action?: ContextMaintenanceAction;
10 trigger?: string;
11 operationId?: string;
12 inputTokens?: number;
13 resultTokens?: number;
14 savedTokens?: number;
15 affectedToolResults?: number;
16 projectionVersion?: number;
17 cacheBreak?: boolean;
18 reason?: string;
19 }
20
21 export interface ContextMaintenanceReceipt extends WireContextMaintenance {
22 sourceProjection?: number;
23 coveredCount?: number;
24 coveredPrefixHash?: string;
25 inputHash?: string;
26 outputHash?: string;
27 summaryHash?: string;
28 archive?: string;
29 blockedInputHash?: string;
30 createdAt?: string;
31 }
32
33 export interface ContextMaintenanceInfo {
34 canonicalTokens?: number;
35 projectedTokens?: number;
36 summaryTokens?: number;
37 lastSavedTokens?: number;
38 /** @deprecated always 0; use triggerTokens */
39 snipTrigger?: number;
40 /** @deprecated alias of triggerTokens */
41 foldTrigger?: number;
42 /** @deprecated always 0; use triggerTokens */
43 forceTrigger?: number;
44 triggerTokens?: number;
45 /** none | restored | applied — runtime only */
46 checkpointState?: "none" | "restored" | "applied";
47 hardInputCeiling?: number;
48 headroom?: number;
49 projectionVersion?: number;
50 blocked?: boolean;
51 lastReceipt?: ContextMaintenanceReceipt;
52 contextBudget?: ContextBudgetInfo;
53 }
54
55 export type ContextBudgetSource = "unknown" | "explicit" | "official" | "opencode" | "learned";
56 export type ContextBudgetRecovery = "none" | "proactive_clip" | "learned_retry" | "compacted" | "failed";
57
58 export interface ContextBudgetInfo {
59 windowMode?: string;
60 limitMode?: string;
61 source?: ContextBudgetSource | string;
62 windowTokens?: number;
63 promptTokens?: number;
64 autoOutputTokens?: number;
65 maxOutputTokens?: number;
66 requestedOutputTokens?: number;
67 effectiveOutputTokens?: number;
68 reserveTokens?: number;
69 physicalRemaining?: number;
70 clipped?: boolean;
71 lastRecovery?: ContextBudgetRecovery | string;
72 observedWindow?: number;
73 observedPrompt?: number;
74 observedCompletion?: number;
75 }
76
77 export function formatContextMaintenanceNotice(m: WireContextMaintenance, t: Translator): string {
78 switch (m.status) {
79 case "applied":
80 return m.action === "truncate"
81 ? t("context.maintenanceTruncatedSummary")
82 : t("context.maintenanceAppliedSummary");
83 case "blocked":
84 return t("context.maintenanceBlockedSummary");
85 case "failed":
86 return t("context.maintenanceFailedSummary");
87 default:
88 break;
89 }
90 const parts = [t("context.maintenanceTitle")];
91 if (m.action === "summary") parts.push(t("summary.detail"));
92 if (typeof m.inputTokens === "number" && typeof m.resultTokens === "number") {
93 parts.push(t("context.tokensValue", {
94 value: `${m.inputTokens.toLocaleString()} → ${m.resultTokens.toLocaleString()}`,
95 }));
96 }
97 if (typeof m.savedTokens === "number" && m.savedTokens > 0) {
98 parts.push(`−${t("context.tokensValue", { value: m.savedTokens.toLocaleString() })}`);
99 }
100 return parts.join(" · ");
101 }
102
103 const MAX_SEEN_MAINTENANCE_OPS = 64;
104
105 /** True when this operationId has not yet been rendered as a notice. */
106 export function isNewMaintenanceOperation(seen: readonly string[] | undefined, operationId?: string): boolean {
107 const id = (operationId ?? "").trim();
108 if (!id) return true;
109 return !(seen ?? []).includes(id);
110 }
111
112 /** Remember an operationId for reconnect/replay dedupe (bounded FIFO). */
113 export function rememberMaintenanceOperation(seen: readonly string[] | undefined, operationId?: string): string[] {
114 const id = (operationId ?? "").trim();
115 if (!id) return [...(seen ?? [])];
116 if ((seen ?? []).includes(id)) return [...(seen ?? [])];
117 return [...(seen ?? []), id].slice(-MAX_SEEN_MAINTENANCE_OPS);
118 }
119
119 lines TYPESCRIPT