pi-mega-compact 0.20.32 → 0.20.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/config/vector-cortex-pcc.js +30 -0
  2. package/dist/config/vector-cortex.js +2 -2
  3. package/dist/config.js +1 -1
  4. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +7 -0
  5. package/dist/extensions/dashboard-server/api-contracts/prefix-stability.js +8 -0
  6. package/dist/extensions/dashboard-server/route-dispatch.js +3 -1
  7. package/dist/extensions/dashboard-server/routes-prefix-stability.js +132 -0
  8. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
  9. package/dist/extensions/dashboard-server/routes.js +1 -0
  10. package/dist/extensions/mega-events/context-handler/tailResult.js +5 -1
  11. package/dist/src/config/vector-cortex-pcc.js +30 -0
  12. package/dist/src/config/vector-cortex.js +2 -2
  13. package/dist/src/config.js +1 -1
  14. package/extensions/dashboard-client/dist/assets/{AreaChart-EL8l2Fcj.js → AreaChart-DjXp8u2Y.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{AreaChart-EL8l2Fcj.js.map → AreaChart-DjXp8u2Y.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/{BarChart-TrwfSh0w.js → BarChart-BZbus-dR.js} +2 -2
  17. package/extensions/dashboard-client/dist/assets/{BarChart-TrwfSh0w.js.map → BarChart-BZbus-dR.js.map} +1 -1
  18. package/extensions/dashboard-client/dist/assets/CacheTab-DQ2CjxVW.js +2 -0
  19. package/extensions/dashboard-client/dist/assets/CacheTab-DQ2CjxVW.js.map +1 -0
  20. package/extensions/dashboard-client/dist/assets/{EventsTab-CNrT-b7t.js → EventsTab-DUpnOV1p.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{EventsTab-CNrT-b7t.js.map → EventsTab-DUpnOV1p.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{HealthTab-CkBCFPk6.js → HealthTab-Bul_xjcn.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{HealthTab-CkBCFPk6.js.map → HealthTab-Bul_xjcn.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CcbKszwx.js → MaintenanceTab-DLUjdKd3.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CcbKszwx.js.map → MaintenanceTab-DLUjdKd3.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-B2LvwScj.js → MemoryMapTab-BFy0hb6F.js} +2 -2
  27. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-B2LvwScj.js.map → MemoryMapTab-BFy0hb6F.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{MetricsTab-Dv_xZtOG.js → MetricsTab-BpYuUkq3.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{MetricsTab-Dv_xZtOG.js.map → MetricsTab-BpYuUkq3.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{OverviewTab-D7xwhpOl.js → OverviewTab-z7yuT-uq.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{OverviewTab-D7xwhpOl.js.map → OverviewTab-z7yuT-uq.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{ReposTab-BfhiPXdA.js → ReposTab-ClORoDy_.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{ReposTab-BfhiPXdA.js.map → ReposTab-ClORoDy_.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{SessionsTab-tQM0TQLp.js → SessionsTab-CUpehIt9.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{SessionsTab-tQM0TQLp.js.map → SessionsTab-CUpehIt9.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/SetupTab-Cii80Fdz.js +3 -0
  37. package/extensions/dashboard-client/dist/assets/{SetupTab-G-MkdQiR.js.map → SetupTab-Cii80Fdz.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CYltysD3.js → TimeSavedCard-BV2iCSdV.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CYltysD3.js.map → TimeSavedCard-BV2iCSdV.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/assets/{TurnsTab-1Y_Lpxx-.js → TurnsTab-1T86rHnD.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{TurnsTab-1Y_Lpxx-.js.map → TurnsTab-1T86rHnD.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-BNHVeTG7.js → VcStatusBadge-DKPleja8.js} +2 -2
  43. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-BNHVeTG7.js.map → VcStatusBadge-DKPleja8.js.map} +1 -1
  44. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-goacPxL1.js → VectorCortexTab-BRzvd_pU.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-goacPxL1.js.map → VectorCortexTab-BRzvd_pU.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/{WikiTab-DTOemYtE.js → WikiTab-DKTILa1M.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{WikiTab-DTOemYtE.js.map → WikiTab-DKTILa1M.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{button-B_4j_PVR.js → button-5fSU8BZj.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{button-B_4j_PVR.js.map → button-5fSU8BZj.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{card-Ce58rSXG.js → card-BFUnpXE_.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{card-Ce58rSXG.js.map → card-BFUnpXE_.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/client-extra-BZbw21wu.js +2 -0
  53. package/extensions/dashboard-client/dist/assets/client-extra-BZbw21wu.js.map +1 -0
  54. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DtNoJ6fZ.js → generateCategoricalChart-xCzi6pWn.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DtNoJ6fZ.js.map → generateCategoricalChart-xCzi6pWn.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{index-eoCm0uxj.js → index-DqjmZ88m.js} +21 -21
  57. package/extensions/dashboard-client/dist/assets/index-DqjmZ88m.js.map +1 -0
  58. package/extensions/dashboard-client/dist/assets/{switch-B9kM0N7R.js → switch-CeZUPf_e.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{switch-B9kM0N7R.js.map → switch-CeZUPf_e.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{toggle-BwoHYpMa.js → toggle-MQQwdkwD.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{toggle-BwoHYpMa.js.map → toggle-MQQwdkwD.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/assets/{useSSE-DohG5AGv.js → useSSE-BetS7QHN.js} +2 -2
  63. package/extensions/dashboard-client/dist/assets/{useSSE-DohG5AGv.js.map → useSSE-BetS7QHN.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/index.html +1 -1
  65. package/extensions/dashboard-client/src/api/client-extra.ts +53 -0
  66. package/extensions/dashboard-client/src/api/client-http.ts +81 -0
  67. package/extensions/dashboard-client/src/api/client.ts +11 -100
  68. package/extensions/dashboard-client/src/components/PrefixStabilityCard.tsx +98 -0
  69. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +27 -0
  70. package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +15 -0
  71. package/extensions/dashboard-server/api-contracts/index.ts +6 -0
  72. package/extensions/dashboard-server/api-contracts/prefix-stability.ts +40 -0
  73. package/extensions/dashboard-server/route-dispatch.ts +2 -0
  74. package/extensions/dashboard-server/routes-prefix-stability.ts +142 -0
  75. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
  76. package/extensions/dashboard-server/routes.ts +1 -0
  77. package/extensions/mega-events/context-handler/tailResult.ts +5 -1
  78. package/package.json +1 -1
  79. package/src/config/vector-cortex-pcc.ts +32 -0
  80. package/src/config/vector-cortex.ts +2 -2
  81. package/src/config.ts +1 -0
  82. package/extensions/dashboard-client/dist/assets/CacheTab-C3KWDFDm.js +0 -2
  83. package/extensions/dashboard-client/dist/assets/CacheTab-C3KWDFDm.js.map +0 -1
  84. package/extensions/dashboard-client/dist/assets/SetupTab-G-MkdQiR.js +0 -3
  85. package/extensions/dashboard-client/dist/assets/index-eoCm0uxj.js.map +0 -1
@@ -54,9 +54,6 @@ import type {
54
54
  SettingsUpdateRequest,
55
55
  SettingsResponsePost,
56
56
  RagMetricsResponse,
57
- ModelThresholdsResponse,
58
- ModelThresholdPutRequest,
59
- ModelThresholdPutResponse,
60
57
  WikiIndexResponse,
61
58
  WikiPageResponse,
62
59
  CurationResult,
@@ -67,74 +64,17 @@ import type {
67
64
  TopicEvolutionResponse,
68
65
  } from "@contracts";
69
66
 
70
- /** Error thrown when a dashboard API response is not 2xx. */
71
- export class ApiError extends Error {
72
- readonly status: number;
73
- constructor(status: number, message: string) {
74
- super(`dashboard API ${status}: ${message}`);
75
- this.name = "ApiError";
76
- this.status = status;
77
- }
78
- }
79
-
80
- /** Internal: typed GET that throws ApiError on non-2xx. */
81
- async function getJson<T>(path: string): Promise<T> {
82
- // guardrails-allow PREVENT-PI-004: relative-path fetch to same-origin dashboard server (loopback-only, static bundle served by the same Node HTTP server).
83
- const res = await fetch(path);
84
- if (!res.ok) {
85
- throw new ApiError(
86
- res.status,
87
- await res.text().catch(() => res.statusText),
88
- );
89
- }
90
- return res.json() as Promise<T>;
91
- }
92
-
93
- /** Internal: typed PUT that throws ApiError on non-2xx. */
94
- async function putJson<T>(path: string, body: unknown): Promise<T> {
95
- // guardrails-allow PREVENT-PI-004: relative-path fetch to same-origin dashboard server (loopback-only).
96
- const res = await fetch(path, {
97
- method: "PUT",
98
- headers: { "Content-Type": "application/json" },
99
- body: JSON.stringify(body),
100
- });
101
- if (!res.ok) {
102
- throw new ApiError(
103
- res.status,
104
- await res.text().catch(() => res.statusText),
105
- );
106
- }
107
- return res.json() as Promise<T>;
108
- }
109
-
110
- /** Internal: typed POST that throws ApiError on non-2xx. */
111
- async function postJson<T>(path: string, body: unknown): Promise<T> {
112
- // guardrails-allow PREVENT-PI-004: relative-path fetch to same-origin dashboard server (loopback-only, static bundle served by the same Node HTTP server).
113
- const res = await fetch(path, {
114
- method: "POST",
115
- headers: { "Content-Type": "application/json" },
116
- body: JSON.stringify(body),
117
- });
118
- if (!res.ok) {
119
- throw new ApiError(
120
- res.status,
121
- await res.text().catch(() => res.statusText),
122
- );
123
- }
124
- return res.json() as Promise<T>;
125
- }
126
-
127
- /** Build a query string from a record, skipping undefined/null values. */
128
- function query(
129
- params: Record<string, string | number | undefined | null>,
130
- ): string {
131
- const sp = new URLSearchParams();
132
- for (const [k, v] of Object.entries(params)) {
133
- if (v !== undefined && v !== null) sp.set(k, String(v));
134
- }
135
- const qs = sp.toString();
136
- return qs ? `?${qs}` : "";
137
- }
67
+ // Shared HTTP helpers (ApiError/getJson/putJson/postJson/query) live in
68
+ // client-http.ts (delegate-shell split keeps client.ts under 400 lines).
69
+ import { getJson, putJson, postJson, query } from "./client-http.js";
70
+ // Newer endpoint groups (model thresholds, PC-C prefix-stability) live in
71
+ // client-extra.ts; re-exported here so downstream imports are unchanged.
72
+ export {
73
+ fetchModelThresholds,
74
+ putModelThreshold,
75
+ deleteModelThreshold,
76
+ fetchPrefixStability,
77
+ } from "./client-extra.js";
138
78
 
139
79
  // ─── Endpoint wrappers ──────────────────────────────────────────────────────
140
80
 
@@ -456,32 +396,3 @@ export function fetchTopicTimeline(
456
396
  export function fetchTopicEvolution(): Promise<TopicEvolutionResponse> {
457
397
  return getJson<TopicEvolutionResponse>(ENDPOINTS.topicEvolution.path);
458
398
  }
459
-
460
- // ─── Per-model compaction thresholds (S52 / v0.16.1) ────────────────────
461
-
462
- /** GET /api/model-thresholds — list known models with their thresholds. */
463
- export function fetchModelThresholds(): Promise<ModelThresholdsResponse> {
464
- return getJson<ModelThresholdsResponse>(ENDPOINTS.modelThresholds.path);
465
- }
466
-
467
- /** PUT /api/model-thresholds — upsert a per-model override. */
468
- export function putModelThreshold(
469
- body: ModelThresholdPutRequest,
470
- ): Promise<ModelThresholdPutResponse> {
471
- return putJson<ModelThresholdPutResponse>(
472
- ENDPOINTS.modelThresholds.path,
473
- body,
474
- );
475
- }
476
-
477
- /** DELETE /api/model-thresholds/:modelId — delete an override (revert). */
478
- export async function deleteModelThreshold(
479
- modelId: string,
480
- ): Promise<{ deleted: boolean }> {
481
- const res = await fetch(
482
- `${ENDPOINTS.modelThresholds.path}/${encodeURIComponent(modelId)}`,
483
- { method: "DELETE" },
484
- );
485
- if (!res.ok) throw new Error(`deleteModelThreshold ${res.status}`);
486
- return res.json() as Promise<{ deleted: boolean }>;
487
- }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * dashboard-client/src/components/PrefixStabilityCard.tsx -- Prompt-cache per-turn
3
+ * stable-prefix ratio trend (PC-C).
4
+ *
5
+ * Renders a sparkline of the per-turn stable-prefix ratio (stablePrefix /
6
+ * totalMessages) read from /api/prefix-stability, with the average ratio and a
7
+ * three-point trend badge ("improving" | "stable" | "degrading"). Each bar is one
8
+ * turn. Uses the same .ov-sparkline / .ov-bar-* CSS classes as CacheHitRateTrendCard.
9
+ * No external charting dependencies.
10
+ */
11
+
12
+ import type React from "react";
13
+ import type { PrefixStabilityResponse } from "@contracts";
14
+ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
15
+
16
+ export interface PrefixStabilityCardProps {
17
+ data: PrefixStabilityResponse;
18
+ }
19
+
20
+ function fmtRatio(n: number): string {
21
+ return `${(n * 100).toFixed(1)}%`;
22
+ }
23
+
24
+ /** Map a ratio (0–1) to a CSS color class (mirrors pctColorClass thresholds). */
25
+ function ratioColorClass(ratio: number): string {
26
+ const pct = ratio * 100;
27
+ if (pct >= 80) return "ov-bar-green";
28
+ if (pct >= 60) return "ov-bar-teal";
29
+ if (pct >= 40) return "ov-bar-yellow";
30
+ if (pct >= 20) return "ov-bar-orange";
31
+ return "ov-bar-red";
32
+ }
33
+
34
+ const TREND_LABEL: Record<PrefixStabilityResponse["trend"], string> = {
35
+ improving: "Improving",
36
+ stable: "Stable",
37
+ degrading: "Degrading",
38
+ };
39
+
40
+ export const PrefixStabilityCard: React.FC<PrefixStabilityCardProps> = ({
41
+ data,
42
+ }) => {
43
+ const { turns, avgRatio, trend } = data;
44
+
45
+ return (
46
+ <Card className="electric-hover">
47
+ <CardHeader>
48
+ <CardTitle>Per-Turn Stable Prefix</CardTitle>
49
+ </CardHeader>
50
+ <CardContent>
51
+ <div className="mb-3 flex gap-4 text-sm text-muted-foreground">
52
+ <div>
53
+ Avg:{" "}
54
+ <strong className="text-foreground">{fmtRatio(avgRatio)}</strong>
55
+ </div>
56
+ <div>
57
+ Trend:{" "}
58
+ <strong className="text-foreground">{TREND_LABEL[trend]}</strong>
59
+ </div>
60
+ <div>
61
+ Turns: <strong className="text-foreground">{turns.length}</strong>
62
+ </div>
63
+ </div>
64
+
65
+ {turns.length > 0 ? (
66
+ <>
67
+ <div
68
+ className="ov-sparkline"
69
+ role="img"
70
+ aria-label={`Per-turn stable-prefix ratio trend: ${turns.length} turns, average ${fmtRatio(avgRatio)}, trend ${TREND_LABEL[trend]}`}
71
+ >
72
+ {turns.map((t, i) => {
73
+ const barH = Math.max(2, Math.round(t.ratio * 60));
74
+ const colorClass = ratioColorClass(t.ratio);
75
+ const isLatest = i === turns.length - 1;
76
+ return (
77
+ <div
78
+ key={i}
79
+ className={`ov-sparkline-bar ${colorClass}${isLatest ? " ov-bar-latest" : ""}`}
80
+ style={{ height: `${barH}px` }}
81
+ title={`Turn ${t.turnIndex}: ${fmtRatio(t.ratio)} (${t.stablePrefix}/${t.totalMessages} msg) @ ${new Date(t.timestamp).toLocaleTimeString()}`}
82
+ />
83
+ );
84
+ })}
85
+ </div>
86
+ <div className="mt-1 text-xs text-muted-foreground">
87
+ Shared prompt-cache prefix ratio per turn — higher is better.
88
+ </div>
89
+ </>
90
+ ) : (
91
+ <div className="text-sm text-muted-foreground">
92
+ No stable-prefix samples yet
93
+ </div>
94
+ )}
95
+ </CardContent>
96
+ </Card>
97
+ );
98
+ };
@@ -17,12 +17,14 @@ import type {
17
17
  ProviderCacheResponse,
18
18
  CacheStripesResponse,
19
19
  PerfResponse,
20
+ PrefixStabilityResponse,
20
21
  } from "@contracts";
21
22
  import { useApi } from "../hooks/useApi";
22
23
  import {
23
24
  fetchSnapshot,
24
25
  fetchProviderCache,
25
26
  fetchCacheStripes,
27
+ fetchPrefixStability,
26
28
  fetchPerf,
27
29
  } from "../api/client";
28
30
  import { CacheHitsCard } from "../components/CacheHitsCard";
@@ -30,6 +32,7 @@ import { TimeSavedCard } from "../components/TimeSavedCard";
30
32
  import { ProviderCacheCard } from "../components/ProviderCacheCard";
31
33
  import { StripeDistributionCard } from "../components/StripeDistributionCard";
32
34
  import { CacheHitRateTrendCard } from "../components/CacheHitRateTrendCard";
35
+ import { PrefixStabilityCard } from "../components/PrefixStabilityCard";
33
36
  import { Button } from "../components/ui/button";
34
37
  import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
35
38
 
@@ -65,6 +68,15 @@ export default function CacheTab(): React.ReactElement {
65
68
  { pollInterval: 15000 },
66
69
  );
67
70
 
71
+ /* --- Per-turn stable-prefix ratio trend (PC-C, 15s poll) --- */
72
+ const {
73
+ data: prefixStability,
74
+ loading: psLoading,
75
+ } = useApi<PrefixStabilityResponse>(
76
+ useCallback(() => fetchPrefixStability(50), []),
77
+ { pollInterval: 15000 },
78
+ );
79
+
68
80
  /* --- Dedup cache snapshot (5s poll) --- */
69
81
  const {
70
82
  data: snapshot,
@@ -164,6 +176,21 @@ export default function CacheTab(): React.ReactElement {
164
176
  <CacheHitRateTrendCard perf={perf} />
165
177
  ) : null}
166
178
 
179
+ {/* ==============================================================
180
+ Section 3b -- Per-Turn Stable Prefix (PC-C)
181
+ Omitted when flag-off: the endpoint 404s, so psError is set and
182
+ this section stays empty. No sample/time-series data, only
183
+ per-turn prefix ratios read from the local events log.
184
+ ============================================================== */}
185
+ {prefixStability && !psLoading ? (
186
+ <div>
187
+ <h2 className="font-heading text-lg font-semibold">
188
+ Per-Turn Stable Prefix
189
+ </h2>
190
+ <PrefixStabilityCard data={prefixStability} />
191
+ </div>
192
+ ) : null}
193
+
167
194
  {/* ==============================================================
168
195
  Section 4 -- Mega-Compact Dedup Cache
169
196
  ============================================================== */}
@@ -24,6 +24,7 @@ import type {
24
24
  SetupCortexActionLogQuery,
25
25
  SetupCortexActionLogResponse,
26
26
  } from "../setup-cortex.js";
27
+ import type { PrefixStabilityResponse } from "../prefix-stability.js";
27
28
 
28
29
  /** Additive endpoint entries spread into the ENDPOINTS registry. */
29
30
  export const EXTRA_ENDPOINTS = {
@@ -108,4 +109,18 @@ export const EXTRA_ENDPOINTS = {
108
109
  SetupCortexActionLogQuery,
109
110
  SetupCortexActionLogResponse
110
111
  >,
112
+
113
+ // ─── PC-C Prompt-cache prefix stability (dashboard Cache tab) ───────
114
+
115
+ /** GET /api/prefix-stability — per-turn stable-prefix ratio trend (PC-C). */
116
+ prefixStability: {
117
+ method: "GET",
118
+ path: "/api/prefix-stability",
119
+ description:
120
+ "Per-turn prompt-cache stable-prefix ratio trend (GET /api/prefix-stability?limit=N) read from prefix_stability rows in the local events log. Flag-off (MEGACOMPACT_PC_C=0) returns 404.",
121
+ } as const satisfies EndpointDef<
122
+ "GET",
123
+ undefined,
124
+ PrefixStabilityResponse
125
+ >,
111
126
  } as const;
@@ -269,6 +269,12 @@ export type {
269
269
  CacheStripesResponse,
270
270
  } from "./cache-stripes.js";
271
271
 
272
+ // PC-C — prompt-cache prefix-stability per-turn trend
273
+ export type {
274
+ PrefixStabilitySample,
275
+ PrefixStabilityResponse,
276
+ } from "./prefix-stability.js";
277
+
272
278
  // RAG Settings — comprehensive adjustable settings (B6)
273
279
  export type {
274
280
  SettingState,
@@ -0,0 +1,40 @@
1
+ /**
2
+ * api-contracts/prefix-stability.ts — Prompt-cache prefix-stability API contract (PC-C).
3
+ *
4
+ * Response shape for GET /api/prefix-stability?limit=50: per-turn stable-prefix
5
+ * ratio trend surfaced from the local monitoring events log (prefix_stability rows
6
+ * appended by tailResult.ts). Loopback-only data; zero network (PREVENT-PI-004).
7
+ */
8
+
9
+ /** A single per-turn prefix-stability sample. */
10
+ export interface PrefixStabilitySample {
11
+ /** Monotonic turn index (order of emission, 0-based). */
12
+ readonly turnIndex: number;
13
+ /** Number of messages sharing the stable prefix (cache-able head). */
14
+ readonly stablePrefix: number;
15
+ /** Total messages in the assembled prompt for that turn. */
16
+ readonly totalMessages: number;
17
+ /** stablePrefix / totalMessages (0.0–1.0); 0 when totalMessages is 0. */
18
+ readonly ratio: number;
19
+ /** Ollama-style striping mode at emit time: "v3" (cache-striping) | "v2" | "off". */
20
+ readonly striping: string;
21
+ /** ISO-8601 timestamp of the event (from the events log row). */
22
+ readonly timestamp: string;
23
+ }
24
+
25
+ /** Three-point trend classification across the returned window. */
26
+ export type PrefixStabilityTrend = "improving" | "stable" | "degrading";
27
+
28
+ /** Response body for GET /api/prefix-stability. */
29
+ export interface PrefixStabilityResponse {
30
+ /** Per-turn samples in chronological order (oldest first), at most `limit`. */
31
+ readonly turns: PrefixStabilitySample[];
32
+ /** Mean ratio across returned samples (0.0–1.0); 0 when empty. */
33
+ readonly avgRatio: number;
34
+ /** Trend classification of the tail of the window vs its head. */
35
+ readonly trend: PrefixStabilityTrend;
36
+ /** Number of samples returned. */
37
+ readonly count: number;
38
+ /** Epoch-millis timestamp the endpoint last scanned the events log. */
39
+ readonly lastScanAt: number;
40
+ }
@@ -28,6 +28,7 @@ import {
28
28
  handleProviderCache,
29
29
  handleMemoryStatus,
30
30
  handleCacheStripes,
31
+ handlePrefixStability,
31
32
  handleSetupStatus,
32
33
  handleSetupDetect,
33
34
  handleSetupConfigure,
@@ -114,6 +115,7 @@ export function dispatchRoutes(
114
115
  if (handleProviderCache(req, res, ctx)) return true;
115
116
  if (handleMemoryStatus(req, res, ctx)) return true;
116
117
  if (handleCacheStripes(req, res, ctx)) return true;
118
+ if (handlePrefixStability(req, res, ctx)) return true;
117
119
  if (handleSetupStatus(req, res, ctx)) return true;
118
120
  if (handleSetupDetect(req, res, ctx)) return true;
119
121
  if (handleSetupConfigure(req, res, ctx)) return true;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * dashboard-server/routes-prefix-stability.ts — Prompt-cache prefix-stability route (PC-C).
3
+ *
4
+ * GET /api/prefix-stability?limit=50 — reads recent prefix_stability rows from the
5
+ * local monitoring events log (ctx.eventsPath) and returns the per-turn stable-prefix
6
+ * ratio trend. Flag-off (MEGACOMPACT_PC_C=0) → 404, byte-identical to PC-B predecessor.
7
+ *
8
+ * Guardrails: PREVENT-PI-004 (loopback-only local dashboard), PREVENT-001 (null-safe
9
+ * JSON.parse), PREVENT-011 (no `any`). Zero network reads.
10
+ */
11
+
12
+ import { readFileSync } from "node:fs";
13
+ import type { IncomingMessage, ServerResponse } from "node:http";
14
+
15
+ import type { PrefixStabilityResponse } from "./api-contracts/prefix-stability.js";
16
+ import type { RouteContext } from "./routes-core.js";
17
+
18
+ /** Parse one events.log line into a generic JSON object, null-safe (PREVENT-001). */
19
+ function parseEventLine(line: string): Record<string, unknown> | null {
20
+ try {
21
+ const parsed: unknown = JSON.parse(line);
22
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
23
+ return parsed as Record<string, unknown>;
24
+ }
25
+ return null;
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ /** Read the tail of events.log and return only prefix_stability rows, newest last. */
32
+ function readPrefixStabilityEvents(
33
+ eventsPath: string,
34
+ limit: number,
35
+ ): Array<{ ts: number; stablePrefix: number; totalMessages: number; separation: string; striping: string }> {
36
+ const samples: Array<{
37
+ ts: number;
38
+ stablePrefix: number;
39
+ totalMessages: number;
40
+ separation: string;
41
+ striping: string;
42
+ }> = [];
43
+ let raw = "";
44
+ try {
45
+ raw = readFileSync(eventsPath, "utf-8"); // guardrails-allow PREVENT-PI-004: local events.log read (loopback dashboard)
46
+ } catch {
47
+ return samples;
48
+ }
49
+ for (const line of raw.split("\n")) {
50
+ if (!line.includes('"prefix_stability"')) continue;
51
+ const obj = parseEventLine(line);
52
+ if (!obj) continue;
53
+ // Only rows we appended (event === "prefix_stability").
54
+ if (obj.event !== "prefix_stability") continue;
55
+ const ts = typeof obj.ts === "number" ? obj.ts : 0;
56
+ const stablePrefix = typeof obj.stablePrefix === "number" ? obj.stablePrefix : 0;
57
+ const totalMessages = typeof obj.totalMessages === "number" ? obj.totalMessages : 0;
58
+ const striping = typeof obj.striping === "string" ? obj.striping : "off";
59
+ const separation = typeof obj.separation === "string" ? obj.separation : "off";
60
+ samples.push({ ts, stablePrefix, totalMessages, separation, striping });
61
+ }
62
+ return samples.slice(-limit);
63
+ }
64
+
65
+ /** Classify the three-point trend across the returned window (head-mean vs tail-mean). */
66
+ function classifyTrend(ratios: number[]): PrefixStabilityResponse["trend"] {
67
+ if (ratios.length < 3) return "stable";
68
+ const third = Math.max(1, Math.floor(ratios.length / 3));
69
+ const head = ratios.slice(0, third).reduce((a, b) => a + b, 0) / third;
70
+ const tail = ratios.slice(-third).reduce((a, b) => a + b, 0) / third;
71
+ const delta = tail - head;
72
+ if (delta > 0.05) return "improving";
73
+ if (delta < -0.05) return "degrading";
74
+ return "stable";
75
+ }
76
+
77
+ /** Positive sprint-flag check (matches sprintFlag: `=0`/`=false`/`_DISABLED=true` → OFF). */
78
+ function prefixStabilityEnabled(): boolean {
79
+ const v = process.env.MEGACOMPACT_PC_C;
80
+ if (v === "0" || v === "false") return false;
81
+ const disabled = process.env.MEGACOMPACT_PC_C_DISABLED;
82
+ if (disabled === "true" || disabled === "1") return false;
83
+ return true;
84
+ }
85
+
86
+ export function handlePrefixStability(
87
+ req: IncomingMessage,
88
+ res: ServerResponse,
89
+ ctx: RouteContext,
90
+ ): boolean {
91
+ if (!req.url?.startsWith("/api/prefix-stability")) return false;
92
+ if (!prefixStabilityEnabled()) {
93
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
94
+ res.writeHead(404, { "Content-Type": "application/json" });
95
+ res.end(JSON.stringify({ error: "not_found" }));
96
+ return true;
97
+ }
98
+ if (req.method !== "GET") {
99
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
100
+ res.writeHead(405, { "Content-Type": "application/json" });
101
+ res.end(JSON.stringify({ error: "method_not_allowed" }));
102
+ return true;
103
+ }
104
+ let limit = 50;
105
+ if (req.url.includes("?")) {
106
+ const params = new URLSearchParams(req.url.slice(req.url.indexOf("?")));
107
+ const l = params.get("limit");
108
+ if (l != null) {
109
+ const n = parseInt(l, 10);
110
+ if (Number.isFinite(n) && n > 0) limit = Math.min(n, 500);
111
+ }
112
+ }
113
+ try {
114
+ const events = readPrefixStabilityEvents(ctx.eventsPath, limit);
115
+ const turns = events.map((e, i) => ({
116
+ turnIndex: i,
117
+ stablePrefix: e.stablePrefix,
118
+ totalMessages: e.totalMessages,
119
+ ratio: e.totalMessages > 0 ? e.stablePrefix / e.totalMessages : 0,
120
+ striping: e.striping,
121
+ timestamp: new Date(e.ts).toISOString(),
122
+ }));
123
+ const avgRatio = turns.length
124
+ ? turns.reduce((a, t) => a + t.ratio, 0) / turns.length
125
+ : 0;
126
+ const body: PrefixStabilityResponse = {
127
+ turns,
128
+ avgRatio: Math.round(avgRatio * 1000) / 1000,
129
+ trend: classifyTrend(turns.map((t) => t.ratio)),
130
+ count: turns.length,
131
+ lastScanAt: Date.now(),
132
+ };
133
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
134
+ res.writeHead(200, { "Content-Type": "application/json" });
135
+ res.end(JSON.stringify(body));
136
+ } catch (e) {
137
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
138
+ res.writeHead(500, { "Content-Type": "application/json" });
139
+ res.end(JSON.stringify({ error: "prefix_stability_unavailable", detail: String(e) }));
140
+ }
141
+ return true;
142
+ }
@@ -216,5 +216,11 @@ export const VECTOR_CORTEX_SETTINGS: SettingGroup = {
216
216
  "Embedder-detect consolidation + VC9 workstream roll-up: memoizes /api/setup-detect against the mutable input (resolved binary path + mtime) so consecutive requests reuse the result without re-spawning, and unifies the embedder + cortex sub-tabs' 5s poll contract. OFF = byte-identical predecessor (VC9C-era): detect spawns fresh per request and the embedder poll keeps its previous cadence.",
217
217
  true,
218
218
  ),
219
+ boolDirect(
220
+ "MEGACOMPACT_PC_C",
221
+ "PC-C Dashboard Cache Visibility",
222
+ "Dashboard per-turn prompt-cache visibility: surfaces the per-turn stable-prefix ratio trend (GET /api/prefix-stability) in the CacheTab PrefixStabilityCard. Reads aggregate ratios/counts from the local monitoring events log only — no payload bytes. OFF = byte-identical predecessor (PC-B-era): /api/prefix-stability returns 404 and the CacheTab omits the PrefixStabilityCard.",
223
+ true,
224
+ ),
219
225
  ],
220
226
  };
@@ -30,6 +30,7 @@ export {
30
30
  export { handleMemoryMap } from "./routes-memory-map.js";
31
31
  export { handleRaptorTree, handleRaptorBuildHistory } from "./routes-raptor.js";
32
32
  export { handleCacheStripes } from "./routes-cache.js";
33
+ export { handlePrefixStability } from "./routes-prefix-stability.js";
33
34
  export {
34
35
  handleContextHealth,
35
36
  handleCachePoison,
@@ -87,7 +87,11 @@ export function buildTailResult(
87
87
  }
88
88
  }
89
89
  lastTurnPrefix.set(runtime, { sessionId, turn, fingerprints });
90
- runtime.logger.info("prefix_stability", {
90
+ // PC-C: write to the always-on monitoring events log (appendEvent),
91
+ // not the debug-gated runtime logger (mega-compact.log), so the
92
+ // dashboard /api/prefix-stability endpoint can read this per-turn
93
+ // stable-prefix ratio from ctx.eventsPath. Same field shape.
94
+ runtime.appendEvent("prefix_stability", {
91
95
  stablePrefix,
92
96
  totalMessages: result.length,
93
97
  separation: config.messageSeparation ? "v2" : "off",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.20.32",
3
+ "version": "0.20.34",
4
4
  "description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
5
5
  "type": "module",
6
6
  "license": "BSD-3-Clause",
@@ -0,0 +1,32 @@
1
+ /**
2
+ * config/vector-cortex-pcc.ts — PC-C dashboard prompt-cache visibility flag.
3
+ *
4
+ * Extracted from vector-cortex.ts so that file stays under the 300-line soft
5
+ * limit (soft-as-hard gate), exactly as the vector-cortex-vc9{a,b,c,d}.ts
6
+ * siblings were. This is the PC-C dashboard per-turn prefix-stability flag.
7
+ * vector-cortex.ts re-exports it below and root src/config.ts re-exports it,
8
+ * so no consumer import path changes.
9
+ *
10
+ * The split is purely mechanical: PCC_ENABLED is byte-identical in name,
11
+ * semantics, and default to the sprint-flag convention it follows, and
12
+ * vector-cortex.ts re-exports it so every existing `from
13
+ * "./config/vector-cortex.js"` import keeps resolving unchanged.
14
+ *
15
+ * Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
16
+ */
17
+
18
+ import { sprintFlag } from "./vector-cortex-flag.js";
19
+
20
+ /**
21
+ * PC-C — dashboard per-turn prefix-stability visibility. Default ON.
22
+ * `MEGACOMPACT_PC_C=0` disables and is byte-identical to the predecessor
23
+ * (PC-B-era): /api/prefix-stability returns 404/disabled and the CacheTab
24
+ * renders exactly as before (stripe distribution + hit-rate trend only). When
25
+ * ON, the endpoint surfaces the per-turn stable-prefix ratio trend from the
26
+ * `prefix_stability` events in the monitoring log. The response contains
27
+ * aggregate ratios/counts only, never message content (EVAL-REDACT-002), and
28
+ * reads only the local events log (PREVENT-PI-004). This flag MUST also be a
29
+ * dashboard SETTINGS toggle (visible in config UI, never in EXCLUDED_SETTINGS),
30
+ * mirroring the other PC/VC flags.
31
+ */
32
+ export const PCC_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_PC_C");
@@ -280,9 +280,9 @@ export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
280
280
  export { VC9B_ENABLED } from "./vector-cortex-vc9b.js";
281
281
  export { VC9C_ENABLED } from "./vector-cortex-vc9c.js";
282
282
  export { VC9D_ENABLED } from "./vector-cortex-vc9d.js";
283
+ export { PCC_ENABLED } from "./vector-cortex-pcc.js";
283
284
 
284
- // Breaker state machine constants (TRIAD_RESILIENCE.md §breaker) extracted to
285
- // vector-cortex-breakers.ts to keep this file under the 300-line soft limit.
285
+ // Breaker constants (TRIAD_RESILIENCE.md §breaker) extracted to vector-cortex-breakers.ts.
286
286
  export {
287
287
  BREAKER_WINDOW_MS,
288
288
  BREAKER_MIN_ATTEMPTS,
package/src/config.ts CHANGED
@@ -182,6 +182,7 @@ export {
182
182
  VC9B_ENABLED,
183
183
  VC9C_ENABLED,
184
184
  VC9D_ENABLED,
185
+ PCC_ENABLED,
185
186
  BREAKER_WINDOW_MS,
186
187
  BREAKER_MIN_ATTEMPTS,
187
188
  BREAKER_PERF_FAILURES,
@@ -1,2 +0,0 @@
1
- import{j as e,r as h,u as j,A as L,D as $,z as H,l as M}from"./index-eoCm0uxj.js";import{C as I,T as k}from"./TimeSavedCard-CYltysD3.js";import{b as m,c as u,d as w,e as W,f as d}from"./format-COjDIVGj.js";import{l as D}from"./pricing-DkYp8-vi.js";import{C as g,a as f,b as C,c as S}from"./card-Ce58rSXG.js";import{B as _}from"./button-B_4j_PVR.js";function R(a){return a>=80?"ov-stat-value-green":a>=50?"ov-stat-value-yellow":"ov-stat-value-red"}function F(a){return a==null?"":a>=0?"ov-stat-value-green":"ov-stat-value-red"}function r({label:a,value:s,className:t,title:l}){return e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",title:l,children:a}),e.jsx("span",{className:`font-semibold${t?` ${t}`:""}`,children:s})]})}function O(a){return e.jsxs(g,{className:"electric-hover",children:[e.jsx(f,{children:e.jsx(C,{children:"Provider Prompt Cache"})}),e.jsxs(S,{children:[e.jsx(r,{label:"Cache Hit Rate",value:`${a.hitPct.toFixed(1)}%`,className:R(a.hitPct)}),e.jsx(r,{label:"Turns Recorded",value:String(a.turnCount)}),e.jsx(r,{label:"Cache Read Tokens",value:m(a.totalCacheRead)}),e.jsx(r,{label:"Cache Write Tokens",value:m(a.totalCacheWrite)}),e.jsx(r,{label:"Input Tokens",value:m(a.totalInput)}),e.jsx(r,{label:"$ Saved (reads)",value:u(a.cacheReadSaved)}),e.jsx(r,{label:"Write Investment",value:u(a.cacheWriteCost)}),e.jsx(r,{label:"Net Saved",value:u(a.netSaved),className:F(a.netSaved)}),e.jsx(r,{label:"Model",value:a.modelLabel??"—"}),e.jsx(r,{label:"Tracked Since",value:w(a.firstTurnAt)}),e.jsx(r,{label:"Last Updated",value:W(a.latestTurnAt)}),a.byModel.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mt-2 text-xs font-semibold text-muted-foreground",children:"Per Model"}),a.byModel.map(s=>{const t=D(s.model),l=t!=null?s.totalCacheRead/1e6*t:null,n=t!=null?s.totalCacheWrite/1e6*t:null;return e.jsxs("div",{className:"mt-2",children:[e.jsx(r,{label:"Model",value:s.model}),e.jsx(r,{label:"Hit Rate",value:`${s.hitPct.toFixed(1)}%`,className:R(s.hitPct)}),e.jsx(r,{label:"Cache Read",value:m(s.totalCacheRead)}),e.jsx(r,{label:"Cache Write",value:m(s.totalCacheWrite)}),e.jsx(r,{label:"Samples",value:String(s.sampleCount)}),e.jsx(r,{label:"$ Saved (reads)",value:l!=null?u(l):"—"}),e.jsx(r,{label:"Write Investment",value:n!=null?u(n):"—"})]},s.model)})]})]})]})}const G=["ov-bar-green","ov-bar-blue","ov-bar-teal","ov-bar-yellow","ov-bar-gray"],B=["Permanent","Epoch","Topic","Thread","Volatile"],z={good:"ov-text-green",fair:"ov-text-yellow",degraded:"ov-text-orange",poor:"ov-text-red"};function K({data:a}){const s=Math.max(...a.buckets.map(l=>l.count),1),t=z[a.health.label]??"ov-text-gray";return e.jsxs("div",{className:"ov-card",children:[e.jsx("h3",{className:"ov-card-title",children:"Cache Stripe Distribution"}),e.jsxs("div",{className:"ov-stripe-health-summary",children:[e.jsx("span",{className:`ov-stripe-health-badge ${t}`,children:a.health.label}),e.jsx("span",{className:"ov-stripe-health-score",children:d(a.health.score)}),e.jsxs("span",{className:"ov-stripe-churn",children:["Churn: ",d(a.health.churnRate)]}),e.jsxs("span",{className:"ov-stripe-total",children:[a.totalChunks," total chunks"]})]}),e.jsx("div",{className:"ov-stripe-bars",children:a.buckets.map(l=>{const n=s>0?Math.max(0,Math.min(100,l.count/s*100)):0,o=G[l.stripe]??"ov-bar-gray",c=l.label||(B[l.stripe]??`Stripe ${l.stripe}`);return e.jsxs("div",{className:"ov-stripe-row",children:[e.jsx("span",{className:"ov-stripe-label",title:c,children:c}),e.jsx("div",{className:"ov-bar-track",children:e.jsx("div",{className:`ov-bar-fill ${o}`,style:{width:`${n}%`}})}),e.jsx("span",{className:"ov-stripe-count",children:l.count}),e.jsx("span",{className:"ov-stripe-stability",title:`min ${d(l.minStability)} / max ${d(l.maxStability)}`,children:d(l.avgStability)})]},l.stripe)})}),e.jsxs("div",{className:"ov-stripe-footer",children:["Epoch: ",a.epochId??"—","· Dominant tier: ",d(a.health.dominantTier)]})]})}function x(a){return`${a.toFixed(1)}%`}function U(a){return a>=80?"ov-bar-green":a>=60?"ov-bar-teal":a>=40?"ov-bar-yellow":a>=20?"ov-bar-orange":"ov-bar-red"}const V=({perf:a})=>{const{cache_hit_pct:s}=a,t=s.samples&&s.samples.length>0?s.samples:[];return e.jsxs(g,{className:"electric-hover",children:[e.jsx(f,{children:e.jsx(C,{children:"Cache Hit-Rate Trend"})}),e.jsxs(S,{children:[e.jsxs("div",{className:"mb-3 flex gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{children:["Avg: ",e.jsx("strong",{className:"text-foreground",children:x(s.avg)})]}),e.jsxs("div",{children:["Latest: ",e.jsx("strong",{className:"text-foreground",children:x(s.latest)})]}),e.jsxs("div",{children:["Samples: ",e.jsx("strong",{className:"text-foreground",children:s.n})]})]}),t.length>0?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"ov-sparkline",role:"img","aria-label":`Cache hit rate trend: ${s.n} samples, average ${x(s.avg)}, latest ${x(s.latest)}`,children:t.map((l,n)=>{const o=Math.max(2,Math.round(l.pct*.6)),c=U(l.pct),v=n===t.length-1;return e.jsx("div",{className:`ov-sparkline-bar ${c}${v?" ov-bar-latest":""}`,style:{height:`${o}px`},title:`${x(l.pct)} at ${new Date(l.ts).toLocaleTimeString()}`},n)})}),e.jsxs("div",{className:"mt-1 text-xs text-muted-foreground",children:[t.length," sample",t.length!==1?"s":""," over"," ",t.length>1?`${Math.round((t[t.length-1].ts-t[0].ts)/1e3)}s`:"latest turn"]})]}):e.jsx("div",{className:"text-sm text-muted-foreground",children:"No cache-hit samples yet"})]})]})};function ee(){const[a,s]=h.useState(!1),{data:t,loading:l,error:n}=j(h.useCallback(()=>L(),[]),{pollInterval:5e3}),{data:o,loading:c,error:v}=j(h.useCallback(()=>$(),[]),{pollInterval:15e3}),{data:N,loading:A,error:T}=j(h.useCallback(()=>H({minutes:30}),[]),{pollInterval:15e3}),{data:i,loading:E,error:y}=j(h.useCallback(()=>M(),[]),{pollInterval:5e3});return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{children:[e.jsx(_,{type:"button",variant:"outline",onClick:()=>s(!a),children:a?"Hide Guidance":"Show Cache-Friendly Prompt Ordering Guidance"}),a&&e.jsxs(g,{className:"mt-3",children:[e.jsx(f,{children:e.jsx(C,{children:"Cache-Friendly Prompt Ordering"})}),e.jsxs(S,{children:[e.jsxs("ul",{className:"list-disc space-y-1 pl-5",children:[e.jsx("li",{children:"Keep system prompts and stable context at the top of your conversation — the provider caches the leading prefix."}),e.jsxs("li",{children:["Tool results and volatile content are automatically moved to the tail by message separation (",e.jsx("code",{children:"MEGACOMPACT_MESSAGE_SEPARATION"}),") so they don't invalidate the cache prefix."]}),e.jsxs("li",{children:["Cache striping (",e.jsx("code",{children:"MEGACOMPACT_CACHE_STRIPING"}),") further orders stable context by a stability score so the most durable chunks lead."]}),e.jsx("li",{children:"Avoid inserting new instructions mid-conversation — prepend them instead."})]}),i&&e.jsxs("div",{className:"mt-2 text-sm",children:[e.jsx("strong",{children:"Status:"})," ",i.config.auto?"Auto-compaction Enabled":"Auto-compaction Disabled"," |"," ","fast-gate ",i.config.fastGatePct,"% / threshold"," ",i.config.thresholdTokens.toLocaleString()," tokens"]})]})]})]}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Provider Prompt Cache"}),l?e.jsx("p",{className:"tab-stub",children:"Loading..."}):n?e.jsxs("p",{className:"tab-stub",children:["Provider cache unavailable: ",n.message]}):t?e.jsx(O,{hitPct:t.cache.avgHitPct,turnCount:t.cache.turnCount,totalCacheRead:t.cache.totalCacheRead,totalCacheWrite:t.cache.totalCacheWrite,totalInput:t.cache.totalInput,cacheReadSaved:t.savings?.cacheReadSaved??null,cacheWriteCost:t.savings?.cacheWriteCost??null,netSaved:t.savings?.netSaved??null,modelLabel:t.savings?.model??null,firstTurnAt:t.cache.firstTurnAt,latestTurnAt:t.cache.latestTurnAt,byModel:t.cache.byModel??[]}):null,e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Cache Stripe Distribution"}),c?e.jsx("p",{className:"tab-stub",children:"Loading..."}):v?e.jsxs("p",{className:"tab-stub",children:["Cache stripe data unavailable: ",v.message]}):o?e.jsx(K,{data:o}):null,e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Cache Hit-Rate Trend"}),A?e.jsx("p",{className:"tab-stub",children:"Loading..."}):T?e.jsxs("p",{className:"tab-stub",children:["Hit-rate trend unavailable: ",T.message]}):N?e.jsx(V,{perf:N}):null,e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Mega-Compact Dedup Cache"}),E?e.jsx("p",{className:"tab-stub",children:"Loading..."}):y?e.jsxs("p",{className:"tab-stub",children:["Snapshot unavailable: ",y.message]}):i&&(()=>{const{cacheHits:p,compacts:P,timeSaved:b}=i;return e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:[e.jsx(I,{cacheHitsSession:p.session,cacheHitsTotal:p.total,tokensSavedSession:p.sessionTokensSaved,tokensSavedTotal:p.totalTokensSaved,compactionsSession:P.session,compactionsTotal:P.total}),e.jsx(k,{compactSessionSec:b.compact.sessionSec,compactTotalSec:b.compact.totalSec,cacheHitSessionSec:b.cacheHit.sessionSec,cacheHitTotalSec:b.cacheHit.totalSec})]})})()]})}export{ee as default};
2
- //# sourceMappingURL=CacheTab-C3KWDFDm.js.map