pi-mega-compact 0.20.50 → 0.20.52
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.
- package/assets/vector-cortex/encoder-v1/manifest.json +1 -1
- package/dist/config/vector-cortex-enc1b.js +46 -0
- package/dist/config/vector-cortex.js +1 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex-ledger.js +9 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/extensions/dashboard-server/routes-setup-enc1b.js +297 -0
- package/dist/extensions/dashboard-server/routes-setup-env-upsert.js +79 -0
- package/dist/extensions/dashboard-server/routes-setup.js +27 -26
- package/dist/extensions/dashboard-server/routes-vector-cortex-eval.js +4 -1
- package/dist/src/config/vector-cortex-enc1b.js +46 -0
- package/dist/src/config/vector-cortex.js +1 -0
- package/dist/src/config.js +1 -1
- package/extensions/dashboard-client/dist/assets/{AreaChart-CeVnaV-0.js → AreaChart-Dika24if.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-CeVnaV-0.js.map → AreaChart-Dika24if.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-DoNd35sw.js → BarChart-MxPpphaX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-DoNd35sw.js.map → BarChart-MxPpphaX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-BROshdFf.js → CacheTab-e90mt1aw.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-BROshdFf.js.map → CacheTab-e90mt1aw.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DAD6NeBR.js → EventsTab-CSl9CNXa.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DAD6NeBR.js.map → EventsTab-CSl9CNXa.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-BBVMM54F.js → HealthTab-CgUm8sp5.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-BBVMM54F.js.map → HealthTab-CgUm8sp5.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-f9VhlFco.js → MaintenanceTab-Dyhjzk6G.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-f9VhlFco.js.map → MaintenanceTab-Dyhjzk6G.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BaxfyzN2.js → MemoryMapTab-C1YR7CoA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BaxfyzN2.js.map → MemoryMapTab-C1YR7CoA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DkUvoeS_.js → MetricsTab-Bktg-486.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DkUvoeS_.js.map → MetricsTab-Bktg-486.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BCpK1vgt.js → OverviewTab-B7qTLQc2.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BCpK1vgt.js.map → OverviewTab-B7qTLQc2.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-cJ5neYIG.js → ReposTab-Cr9W3KFw.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-cJ5neYIG.js.map → ReposTab-Cr9W3KFw.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-8DyQv1Ry.js → SessionsTab-5x_LL9D8.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-8DyQv1Ry.js.map → SessionsTab-5x_LL9D8.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-vB72Y7pk.js +3 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-vB72Y7pk.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-8N7Vvlch.js → TimeSavedCard-hsMc2BFT.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-8N7Vvlch.js.map → TimeSavedCard-hsMc2BFT.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CCijkQoH.js → TurnsTab-CjUIvDlj.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CCijkQoH.js.map → TurnsTab-CjUIvDlj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-D9a7By8x.js → VcStatusBadge-yDtZGtnm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-D9a7By8x.js.map → VcStatusBadge-yDtZGtnm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-pviD6CCy.js → VectorCortexTab-CvbaaeXD.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-pviD6CCy.js.map → VectorCortexTab-CvbaaeXD.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{WikiTab-DLyicguz.js → WikiTab-c7K7kspY.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-DLyicguz.js.map → WikiTab-c7K7kspY.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-D8nKit8Y.js → button-vdqzHHyW.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-D8nKit8Y.js.map → button-vdqzHHyW.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-Xf5wHHBL.js → card-DEzbxZLz.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-Xf5wHHBL.js.map → card-DEzbxZLz.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{client-extra-CvxDLpQr.js → client-extra-CJe2UKEK.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{client-extra-CvxDLpQr.js.map → client-extra-CJe2UKEK.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DhQquRa8.js → generateCategoricalChart-Br3cS-GZ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DhQquRa8.js.map → generateCategoricalChart-Br3cS-GZ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-BUP3MK5S.js → index-CBMWirAB.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-BUP3MK5S.js.map → index-CBMWirAB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/index-C_aDd9kk.css +1 -0
- package/extensions/dashboard-client/dist/assets/{switch-B13rb8Z2.js → switch-D_uPnF8u.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-B13rb8Z2.js.map → switch-D_uPnF8u.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-4h6DUEB5.js → toggle-DIaGjpNm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-4h6DUEB5.js.map → toggle-DIaGjpNm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-Djom4z1K.js → useSSE-CJOcvXIe.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-Djom4z1K.js.map → useSSE-CJOcvXIe.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/tabs/SetupTab/CortexRuntimeCard.tsx +103 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/CortexRuntimeCardStyles.ts +49 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/CortexSetup.tsx +2 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/CustomEndpointSection.tsx +122 -1
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +57 -79
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetupHelpers.tsx +75 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +7 -5
- package/extensions/dashboard-client/src/types/vector-cortex.ts +6 -0
- package/extensions/dashboard-server/api-contracts/setup.ts +35 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-ledger.ts +39 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex.ts +10 -28
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/extensions/dashboard-server/routes-setup-enc1b.ts +336 -0
- package/extensions/dashboard-server/routes-setup-env-upsert.ts +93 -0
- package/extensions/dashboard-server/routes-setup.ts +26 -24
- package/extensions/dashboard-server/routes-vector-cortex-eval.ts +4 -1
- package/package.json +1 -1
- package/src/config/vector-cortex-enc1b.ts +50 -0
- package/src/config/vector-cortex.ts +8 -0
- package/src/config.ts +1 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-BQGPf9CI.js +0 -3
- package/extensions/dashboard-client/dist/assets/SetupTab-BQGPf9CI.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-DbuGwYD7.css +0 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api-contracts/vector-cortex-ledger.ts — VC1B occurrence-ledger surface.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `vector-cortex.ts` so the combined api-contracts module stays
|
|
5
|
+
* under the 400-line `extensions/` soft limit. Owns the reader-only ledger
|
|
6
|
+
* views (VC1B aggregate + identity rows). PREVENT-PI-004: type definitions
|
|
7
|
+
* only, no network code. PREVENT-011: no `any` type.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Live-state derivation shared across the VC views (mirrors vector-cortex.ts). */
|
|
11
|
+
type VcStatus = "live" | "awaiting_data" | "deferred" | "structural" | "off";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Reader-only occurrence-ledger identity view for GET /api/vector-cortex/ledger (VC1B).
|
|
15
|
+
* Built on the LedgerReader capability surface. Exposes occurrence IDENTITY
|
|
16
|
+
* (seq/eventId/kind/digest/toolCallId) and the per-session high-water/count —
|
|
17
|
+
* NEVER sourceBytes or prompt text, honoring the reader-only no-ledger-text rule.
|
|
18
|
+
*/
|
|
19
|
+
export interface VectorCortexLedgerView {
|
|
20
|
+
/** Whether the VC1B occurrence ledger flag is enabled in this process. */
|
|
21
|
+
readonly enabled: boolean;
|
|
22
|
+
/** The ledger session whose occurrences are returned. */
|
|
23
|
+
readonly session: string;
|
|
24
|
+
/** Durable contiguous high-water (stringified bigint) for the session. */
|
|
25
|
+
readonly highWater: string;
|
|
26
|
+
/** Number of accepted occurrences for the session. */
|
|
27
|
+
readonly count: number;
|
|
28
|
+
/** Capped identity rows (ascending seq). No source bytes, never payload text. */
|
|
29
|
+
readonly occurrences: readonly {
|
|
30
|
+
readonly seq: string;
|
|
31
|
+
readonly eventId: string;
|
|
32
|
+
readonly kind: string;
|
|
33
|
+
readonly digest: string;
|
|
34
|
+
readonly toolCallId?: string;
|
|
35
|
+
}[];
|
|
36
|
+
/** ISO timestamp of the snapshot. */
|
|
37
|
+
readonly updatedAt: string;
|
|
38
|
+
readonly status?: VcStatus;
|
|
39
|
+
}
|
|
@@ -44,6 +44,13 @@ export interface VectorCortexEvaluationSummary {
|
|
|
44
44
|
};
|
|
45
45
|
/** Evaluator rejections (EVAL_*) observed in this window. */
|
|
46
46
|
readonly rejects: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* ML5-D dashboard "Improve Cortex" flag state. Additive and omitted when
|
|
49
|
+
* MEGACOMPACT_ML5_D is off, so the client omits the ModelImprovementCard
|
|
50
|
+
* (byte-identical to the ML5-C-era tab). Present (true) only when the flag
|
|
51
|
+
* is enabled. Reader-only aggregate — never job verdicts or training bytes.
|
|
52
|
+
*/
|
|
53
|
+
readonly ml5dEnabled?: boolean;
|
|
47
54
|
/** ISO timestamp of the summary. */
|
|
48
55
|
readonly updatedAt: string;
|
|
49
56
|
readonly status?: VcStatus;
|
|
@@ -365,36 +372,11 @@ export interface VectorCortexRolloutView {
|
|
|
365
372
|
readonly status?: VcStatus;
|
|
366
373
|
}
|
|
367
374
|
|
|
368
|
-
/**
|
|
369
|
-
* Reader-only occurrence-ledger identity view for GET /api/vector-cortex/ledger (VC1B).
|
|
370
|
-
* Built on the LedgerReader capability surface. Exposes occurrence IDENTITY
|
|
371
|
-
* (seq/eventId/kind/digest/toolCallId) and the per-session high-water/count —
|
|
372
|
-
* NEVER sourceBytes or prompt text, honoring the reader-only no-ledger-text rule.
|
|
373
|
-
*/
|
|
374
|
-
export interface VectorCortexLedgerView {
|
|
375
|
-
/** Whether the VC1B occurrence ledger flag is enabled in this process. */
|
|
376
|
-
readonly enabled: boolean;
|
|
377
|
-
/** The ledger session whose occurrences are returned. */
|
|
378
|
-
readonly session: string;
|
|
379
|
-
/** Durable contiguous high-water (stringified bigint) for the session. */
|
|
380
|
-
readonly highWater: string;
|
|
381
|
-
/** Number of accepted occurrences for the session. */
|
|
382
|
-
readonly count: number;
|
|
383
|
-
/** Capped identity rows (ascending seq). No source bytes, never payload text. */
|
|
384
|
-
readonly occurrences: readonly {
|
|
385
|
-
readonly seq: string;
|
|
386
|
-
readonly eventId: string;
|
|
387
|
-
readonly kind: string;
|
|
388
|
-
readonly digest: string;
|
|
389
|
-
readonly toolCallId?: string;
|
|
390
|
-
}[];
|
|
391
|
-
/** ISO timestamp of the snapshot. */
|
|
392
|
-
readonly updatedAt: string;
|
|
393
|
-
readonly status?: VcStatus;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
375
|
export type {
|
|
397
376
|
VectorCortexClosureProofView,
|
|
398
377
|
VectorCortexRestoreView,
|
|
399
378
|
VectorCortexRepairView,
|
|
400
379
|
} from "./vector-cortex-heal.js";
|
|
380
|
+
export type {
|
|
381
|
+
VectorCortexLedgerView,
|
|
382
|
+
} from "./vector-cortex-ledger.js";
|
|
@@ -300,5 +300,11 @@ export const VECTOR_CORTEX_SETTINGS: SettingGroup = {
|
|
|
300
300
|
"ENC-1a adds a Settings-visible field pair for the external embedder endpoint URL + optional Bearer API key, persisted by the setup-configure writer branch to the per-repo .mega-compact.env (MEGACOMPACT_EMBEDDING_URL / MEGACOMPACT_EMBEDDING_KEY). The GET status route echoes the endpoint URL and reports embeddingApiKeySet as a boolean ONLY — the raw key is never returned. OFF = no new GET fields, no writer branch, no new Settings text rows (byte-identical ENC-0g predecessor).",
|
|
301
301
|
true,
|
|
302
302
|
),
|
|
303
|
+
boolDirect(
|
|
304
|
+
"MEGACOMPACT_ENC_1B",
|
|
305
|
+
"ENC-1b ONNX runtime backend + embedder API settings",
|
|
306
|
+
"ENC-1b completes the embedder API Settings surface (dim / headers / allow-remote persisted to the per-repo .mega-compact.env) and surfaces the ONNX runtime selection knob (MEGACOMPACT_ENCODER_NATIVE) as a toggle plus the current effective backend + demotion reason. OFF = no new GET fields, no writer branch, no new Settings rows or toggle (byte-identical ENC-1a predecessor).",
|
|
307
|
+
true,
|
|
308
|
+
),
|
|
303
309
|
],
|
|
304
310
|
};
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-setup-enc1b.ts — ENC-1b embedder API completion +
|
|
3
|
+
* ONNX runtime selection Settings read/write + the additive writer branch.
|
|
4
|
+
*
|
|
5
|
+
* Extracted out of routes-setup.ts (which hovers at the 300-line source soft
|
|
6
|
+
* cap, mirroring the ENC-1a sibling extract) so the ENC-1b additive read/write
|
|
7
|
+
* of the per-repo `.mega-compact.env` keys AND the runtime-backend computation
|
|
8
|
+
* live in a sibling impl file. Four keys are managed here:
|
|
9
|
+
* `MEGACOMPACT_EMBEDDING_DIM`, `MEGACOMPACT_EMBEDDING_HEADERS`,
|
|
10
|
+
* `MEGACOMPACT_ALLOW_REMOTE_EMBEDDER`, `MEGACOMPACT_ENCODER_NATIVE` — the exact
|
|
11
|
+
* names `embeddingConfigFromEnv` (src/httpEmbedder.ts) and the runtime selector
|
|
12
|
+
* read at runtime.
|
|
13
|
+
*
|
|
14
|
+
* The write is create-or-append: it upserts the four keys into the existing
|
|
15
|
+
* per-repo `.mega-compact.env`, preserving every unrelated line and never
|
|
16
|
+
* deleting another key. The read reports the persisted dim, booleans for
|
|
17
|
+
* headers-set / allow-remote / native-opt-in, and computes the current
|
|
18
|
+
* effective backend + demotion reason through the EXISTING `selectRuntimeBackend`
|
|
19
|
+
* (reader-only — the runtime's own selection, never a reimplemented literal,
|
|
20
|
+
* never install logic). The raw headers JSON is NEVER returned, logged or
|
|
21
|
+
* emitted (redaction invariant — it may carry secrets such as an Authorization
|
|
22
|
+
* header for a TEI/ONNX server).
|
|
23
|
+
*
|
|
24
|
+
* Guardrails: PREVENT-PI-004 (local filesystem reads/writes + in-memory
|
|
25
|
+
* runtime selection only, zero network), PREVENT-001 (null-safe JSON),
|
|
26
|
+
* PREVENT-011 (no `any`).
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { writeFileSync, mkdirSync, readFileSync, existsSync } from "node:fs";
|
|
30
|
+
import { join } from "node:path";
|
|
31
|
+
import type { ServerResponse } from "node:http";
|
|
32
|
+
import type { RouteContext } from "./routes-core.js";
|
|
33
|
+
import {
|
|
34
|
+
ENC_1B_ENABLED,
|
|
35
|
+
ENC_1B_MAX_EMBEDDING_DIM,
|
|
36
|
+
ENC_1B_EMBEDDING_DIM_ENV,
|
|
37
|
+
ENC_1B_EMBEDDING_HEADERS_ENV,
|
|
38
|
+
ENC_1B_ALLOW_REMOTE_EMBEDDER_ENV,
|
|
39
|
+
ENC_1B_ENCODER_NATIVE_ENV,
|
|
40
|
+
} from "../../src/config/vector-cortex.js";
|
|
41
|
+
import type { SetupConfigureRequest, SetupConfigureResponse } from "./api-contracts/setup.js";
|
|
42
|
+
import { selectRuntimeBackend } from "../../src/vector-cortex/encoder/runtime-select.js";
|
|
43
|
+
import { detectPlatform } from "../../src/vector-cortex/encoder/asset.js";
|
|
44
|
+
|
|
45
|
+
function envPath(stateDir: string): string {
|
|
46
|
+
return join(stateDir, ".mega-compact.env");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Extract the value of `export MEGACOMPACT_X="..."` (or unquoted) from a line. */
|
|
50
|
+
function lineValue(line: string, key: string): string | null {
|
|
51
|
+
const m = line.match(new RegExp(`^export\\s+${key}=(.*)$`));
|
|
52
|
+
if (!m) return null;
|
|
53
|
+
const rest = m[1].trim();
|
|
54
|
+
if (rest.length === 0) return null;
|
|
55
|
+
const q = rest.match(/^"([^"]*)"$/);
|
|
56
|
+
return q ? q[1] : rest;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** True when the payload carries any ENC-1b key (flag-gated). */
|
|
60
|
+
export function wantsEnc1b(body: SetupConfigureRequest): boolean {
|
|
61
|
+
return (
|
|
62
|
+
ENC_1B_ENABLED() &&
|
|
63
|
+
(typeof body.embeddingDim === "string" ||
|
|
64
|
+
typeof body.embeddingHeaders === "string" ||
|
|
65
|
+
typeof body.allowRemoteEmbedder === "boolean" ||
|
|
66
|
+
typeof body.encoderNativeOptIn === "boolean")
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Read the ENC-1b keys from the per-repo `.mega-compact.env`. The headers
|
|
71
|
+
* value is NEVER surfaced to callers — only its presence boolean. */
|
|
72
|
+
export function readEnc1bEnv(stateDir: string): {
|
|
73
|
+
dim: string | null;
|
|
74
|
+
headersSet: boolean;
|
|
75
|
+
allowRemote: boolean;
|
|
76
|
+
nativeOptIn: boolean;
|
|
77
|
+
} {
|
|
78
|
+
try {
|
|
79
|
+
const p = envPath(stateDir);
|
|
80
|
+
if (!existsSync(p)) return { dim: null, headersSet: false, allowRemote: false, nativeOptIn: false };
|
|
81
|
+
const lines = readFileSync(p, "utf8").split(/\r?\n/);
|
|
82
|
+
let dim: string | null = null;
|
|
83
|
+
let headersSet = false;
|
|
84
|
+
let allowRemote = false;
|
|
85
|
+
let nativeOptIn = false;
|
|
86
|
+
for (const line of lines) {
|
|
87
|
+
const d = lineValue(line, ENC_1B_EMBEDDING_DIM_ENV);
|
|
88
|
+
if (d !== null && d.length > 0) dim = d;
|
|
89
|
+
const h = lineValue(line, ENC_1B_EMBEDDING_HEADERS_ENV);
|
|
90
|
+
if (h !== null && h.length > 0) headersSet = true;
|
|
91
|
+
const a = lineValue(line, ENC_1B_ALLOW_REMOTE_EMBEDDER_ENV);
|
|
92
|
+
if (a !== null && ["1", "true", "yes"].includes(a.trim().toLowerCase())) allowRemote = true;
|
|
93
|
+
const n = lineValue(line, ENC_1B_ENCODER_NATIVE_ENV);
|
|
94
|
+
if (n !== null && ["1", "true", "yes"].includes(n.trim().toLowerCase())) nativeOptIn = true;
|
|
95
|
+
}
|
|
96
|
+
return { dim, headersSet, allowRemote, nativeOptIn };
|
|
97
|
+
} catch {
|
|
98
|
+
return { dim: null, headersSet: false, allowRemote: false, nativeOptIn: false };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* ENC-1b additive GET status fields. All omitted when flag-off. The Cortex
|
|
104
|
+
* trio (native opt-in + effective backend + demotion reason) is computed here
|
|
105
|
+
* (reader-only): the stored opt-in + current platform drive the EXISTING
|
|
106
|
+
* `selectRuntimeBackend`, whose own demotion reason is surfaced verbatim when
|
|
107
|
+
* the runtime falls back. `modeB` (flag-off selection) is projected to `wasm`
|
|
108
|
+
* for display. Returns `{}` when the flag is off (byte-identical predecessor).
|
|
109
|
+
*/
|
|
110
|
+
export function enc1bStatusFields(stateDir: string): {
|
|
111
|
+
embeddingDim?: string;
|
|
112
|
+
embeddingHeadersSet?: boolean;
|
|
113
|
+
allowRemoteEmbedder?: boolean;
|
|
114
|
+
encoderNativeOptIn?: boolean;
|
|
115
|
+
encoderBackend?: "wasm" | "native";
|
|
116
|
+
encoderDemotionReason?: string | null;
|
|
117
|
+
} {
|
|
118
|
+
if (!ENC_1B_ENABLED()) return {};
|
|
119
|
+
const env = readEnc1bEnv(stateDir);
|
|
120
|
+
const platform = detectPlatform();
|
|
121
|
+
const chosen = selectRuntimeBackend({
|
|
122
|
+
platform: platform ?? "unsupported",
|
|
123
|
+
benchRecord: null,
|
|
124
|
+
nativeOptIn: env.nativeOptIn,
|
|
125
|
+
});
|
|
126
|
+
const backend: "wasm" | "native" =
|
|
127
|
+
chosen.backend === "native" ? "native" : "wasm";
|
|
128
|
+
return {
|
|
129
|
+
...(env.dim !== null ? { embeddingDim: env.dim } : {}),
|
|
130
|
+
embeddingHeadersSet: env.headersSet,
|
|
131
|
+
allowRemoteEmbedder: env.allowRemote,
|
|
132
|
+
encoderNativeOptIn: env.nativeOptIn,
|
|
133
|
+
encoderBackend: backend,
|
|
134
|
+
encoderDemotionReason: chosen.demotionReason,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Upsert the ENC-1b keys into the per-repo `.mega-compact.env`. Creates the
|
|
139
|
+
* file if absent; preserves every unrelated line; never deletes other keys.
|
|
140
|
+
* A `null` entry leaves that key's line untouched. The headers value is
|
|
141
|
+
* wrapped in single quotes so the inner JSON double quotes survive the env
|
|
142
|
+
* loader's outer-quote strip (shell-sourceable + loader-compatible). */
|
|
143
|
+
export function writeEnc1bEnv(
|
|
144
|
+
stateDir: string,
|
|
145
|
+
entries: {
|
|
146
|
+
dim?: string | null;
|
|
147
|
+
headers?: string | null;
|
|
148
|
+
allowRemote?: boolean | null;
|
|
149
|
+
nativeOptIn?: boolean | null;
|
|
150
|
+
},
|
|
151
|
+
): string {
|
|
152
|
+
const p = envPath(stateDir);
|
|
153
|
+
const existingLines: string[] = existsSync(p) ? readFileSync(p, "utf8").split(/\r?\n/) : [];
|
|
154
|
+
const out: string[] = [];
|
|
155
|
+
const keys = new Set<{ key: string; present: () => boolean; push: () => void }>([
|
|
156
|
+
{
|
|
157
|
+
key: ENC_1B_EMBEDDING_DIM_ENV,
|
|
158
|
+
present: () => entries.dim !== null,
|
|
159
|
+
push: () => out.push(`export ${ENC_1B_EMBEDDING_DIM_ENV}="${entries.dim ?? ""}"`),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
key: ENC_1B_EMBEDDING_HEADERS_ENV,
|
|
163
|
+
present: () => entries.headers !== null,
|
|
164
|
+
push: () => out.push(`export ${ENC_1B_EMBEDDING_HEADERS_ENV}='${entries.headers ?? ""}'`),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
key: ENC_1B_ALLOW_REMOTE_EMBEDDER_ENV,
|
|
168
|
+
present: () => entries.allowRemote !== null,
|
|
169
|
+
push: () =>
|
|
170
|
+
out.push(
|
|
171
|
+
entries.allowRemote
|
|
172
|
+
? `export ${ENC_1B_ALLOW_REMOTE_EMBEDDER_ENV}="1"`
|
|
173
|
+
: `export ${ENC_1B_ALLOW_REMOTE_EMBEDDER_ENV}="0"`,
|
|
174
|
+
),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
key: ENC_1B_ENCODER_NATIVE_ENV,
|
|
178
|
+
present: () => entries.nativeOptIn !== null,
|
|
179
|
+
push: () =>
|
|
180
|
+
out.push(
|
|
181
|
+
entries.nativeOptIn
|
|
182
|
+
? `export ${ENC_1B_ENCODER_NATIVE_ENV}="1"`
|
|
183
|
+
: `export ${ENC_1B_ENCODER_NATIVE_ENV}="0"`,
|
|
184
|
+
),
|
|
185
|
+
},
|
|
186
|
+
]);
|
|
187
|
+
const written = new Set<string>();
|
|
188
|
+
for (const line of existingLines) {
|
|
189
|
+
let replaced = false;
|
|
190
|
+
for (const k of keys) {
|
|
191
|
+
if (k.present() && lineValue(line, k.key) !== null) {
|
|
192
|
+
k.push();
|
|
193
|
+
written.add(k.key);
|
|
194
|
+
replaced = true;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!replaced) out.push(line);
|
|
199
|
+
}
|
|
200
|
+
for (const k of keys) {
|
|
201
|
+
if (k.present() && !written.has(k.key)) k.push();
|
|
202
|
+
}
|
|
203
|
+
mkdirSync(stateDir, { recursive: true });
|
|
204
|
+
writeFileSync(p, out.join("\n"), "utf-8");
|
|
205
|
+
return p;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Validate `embeddingDim` as a positive integer string within the ENC-1b cap.
|
|
209
|
+
* Returns `null` when valid, else the error code. Exported so the routes host
|
|
210
|
+
* (combined-payload path) and the aggregator share the same rule. */
|
|
211
|
+
export function validateDim(value: unknown): string | null {
|
|
212
|
+
if (typeof value !== "string" || value.trim().length === 0) return "invalid_embedding_dim";
|
|
213
|
+
if (!/^\d+$/.test(value)) return "invalid_embedding_dim";
|
|
214
|
+
const n = Number(value);
|
|
215
|
+
if (!Number.isSafeInteger(n) || n < 1 || n > ENC_1B_MAX_EMBEDDING_DIM) {
|
|
216
|
+
return "invalid_embedding_dim";
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Validate `embeddingHeaders` as a string that parses to a JSON object.
|
|
222
|
+
* Returns `null` when valid, else the error code. Exported so the routes host
|
|
223
|
+
* (combined-payload path) and the aggregator share the same rule. */
|
|
224
|
+
export function validateHeaders(value: unknown): string | null {
|
|
225
|
+
if (typeof value !== "string" || value.trim().length === 0) return "invalid_embedding_headers";
|
|
226
|
+
let parsed: unknown;
|
|
227
|
+
try {
|
|
228
|
+
parsed = JSON.parse(value);
|
|
229
|
+
} catch {
|
|
230
|
+
return "invalid_embedding_headers";
|
|
231
|
+
}
|
|
232
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
233
|
+
return "invalid_embedding_headers";
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Combined-payload upsert: after the main embedder write has freshly written
|
|
240
|
+
* the per-repo env, append any ENC-1b keys carried alongside a valid embedder
|
|
241
|
+
* selection (flag-gated, additive). No-op when flag-off or no ENC-1b key.
|
|
242
|
+
*/
|
|
243
|
+
export function tryEnc1bInto(stateDir: string, body: SetupConfigureRequest): void {
|
|
244
|
+
if (!wantsEnc1b(body)) return;
|
|
245
|
+
writeEnc1bEnv(stateDir, {
|
|
246
|
+
dim: typeof body.embeddingDim === "string" ? body.embeddingDim : null,
|
|
247
|
+
headers: typeof body.embeddingHeaders === "string" ? body.embeddingHeaders : null,
|
|
248
|
+
allowRemote: typeof body.allowRemoteEmbedder === "boolean" ? body.allowRemoteEmbedder : null,
|
|
249
|
+
nativeOptIn:
|
|
250
|
+
typeof body.encoderNativeOptIn === "boolean" ? body.encoderNativeOptIn : null,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* If the payload is a pure ENC-1b configure (new keys, no embedder selection),
|
|
256
|
+
* validate + write them additively to the per-repo env and reply. Returns true
|
|
257
|
+
* when it fully handled the request. On a validation failure it replies 400
|
|
258
|
+
* with the code and leaves the file byte-unchanged. Flag-off = keys are not
|
|
259
|
+
* recognized and this returns false (byte-identical ENC-1a predecessor).
|
|
260
|
+
*/
|
|
261
|
+
/**
|
|
262
|
+
* Combined-path validation: the standalone `tryEnc1bConfigure` handles the
|
|
263
|
+
* pure-ENC-1b shape; when a payload ALSO carries a valid embedder the sibling
|
|
264
|
+
* writer returns false and the routes host is responsible for running the same
|
|
265
|
+
* dim/headers validation before the combined upsert — returned as the error
|
|
266
|
+
* code string, or `null` if everything passes (or the flag is off).
|
|
267
|
+
*/
|
|
268
|
+
export function enc1bValidateCombined(body: SetupConfigureRequest): string | null {
|
|
269
|
+
if (!ENC_1B_ENABLED()) return null;
|
|
270
|
+
if (body.embeddingDim !== undefined) {
|
|
271
|
+
const e = validateDim(body.embeddingDim);
|
|
272
|
+
if (e !== null) return e;
|
|
273
|
+
}
|
|
274
|
+
if (body.embeddingHeaders !== undefined) {
|
|
275
|
+
const e = validateHeaders(body.embeddingHeaders);
|
|
276
|
+
if (e !== null) return e;
|
|
277
|
+
}
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function tryEnc1bConfigure(
|
|
282
|
+
body: SetupConfigureRequest,
|
|
283
|
+
res: ServerResponse,
|
|
284
|
+
ctx: RouteContext,
|
|
285
|
+
): boolean {
|
|
286
|
+
if (!wantsEnc1b(body)) return false;
|
|
287
|
+
const embedder = body.embedder;
|
|
288
|
+
const embedderValid =
|
|
289
|
+
!!embedder &&
|
|
290
|
+
(embedder === "ollama" || embedder === "llama" || embedder === "trigram" ||
|
|
291
|
+
embedder === "custom" || embedder === "onnx");
|
|
292
|
+
if (embedderValid) return false; // combined payload — integrated after the embedder write
|
|
293
|
+
// Each key is optional: only validate the ones actually carried in the
|
|
294
|
+
// payload (absent keys are left untouched, never rejected).
|
|
295
|
+
const dimError = body.embeddingDim === undefined ? null : validateDim(body.embeddingDim);
|
|
296
|
+
if (dimError !== null) {
|
|
297
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
298
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
299
|
+
res.end(JSON.stringify({ error: dimError }));
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
const headersError =
|
|
303
|
+
body.embeddingHeaders === undefined ? null : validateHeaders(body.embeddingHeaders);
|
|
304
|
+
if (headersError !== null) {
|
|
305
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
306
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
307
|
+
res.end(JSON.stringify({ error: headersError }));
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const envPath = writeEnc1bEnv(ctx.stateDir, {
|
|
312
|
+
dim: typeof body.embeddingDim === "string" ? body.embeddingDim : null,
|
|
313
|
+
headers: typeof body.embeddingHeaders === "string" ? body.embeddingHeaders : null,
|
|
314
|
+
allowRemote: typeof body.allowRemoteEmbedder === "boolean" ? body.allowRemoteEmbedder : null,
|
|
315
|
+
nativeOptIn:
|
|
316
|
+
typeof body.encoderNativeOptIn === "boolean" ? body.encoderNativeOptIn : null,
|
|
317
|
+
});
|
|
318
|
+
const resp: SetupConfigureResponse = {
|
|
319
|
+
embedder: "custom",
|
|
320
|
+
url: null,
|
|
321
|
+
envPath,
|
|
322
|
+
restartRequired: true,
|
|
323
|
+
alreadyActive: false,
|
|
324
|
+
};
|
|
325
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
326
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
327
|
+
res.end(JSON.stringify(resp));
|
|
328
|
+
return true;
|
|
329
|
+
} catch (e) {
|
|
330
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
331
|
+
res.end(
|
|
332
|
+
JSON.stringify({ error: `write_failed: ${e instanceof Error ? e.message : String(e)}` }),
|
|
333
|
+
);
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* routes-setup-env-upsert.ts — upsert-style write of the per-repo
|
|
3
|
+
* `.mega-compact.env` for the primary embedder selection.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from routes-setup.ts so the route stays under the 300-line soft
|
|
6
|
+
* cap. The writer preserves every unrelated line (ENC-1a's endpoint/key,
|
|
7
|
+
* ENC-1b's dim/headers, operator comments) and replaces only the three keys
|
|
8
|
+
* this primary write owns — MEGACOMPACT_EMBEDDING_URL,
|
|
9
|
+
* MEGACOMPACT_ALLOW_REMOTE_EMBEDDER, MEGACOMPACT_MINILM. URLs already persisted
|
|
10
|
+
* by enc1a/enc1b helpers are NOT clobbered across a later native-opt-in POST
|
|
11
|
+
* (the ENC-1b defect class caught in live review).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { writeFileSync, mkdirSync, readFileSync, existsSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
/** Line-prefix recognizer for an owned key (covers active, commented, and prose forms). */
|
|
18
|
+
function ownsKey(line: string, key: string): boolean {
|
|
19
|
+
return (
|
|
20
|
+
line.startsWith(`export ${key}=`) ||
|
|
21
|
+
line.startsWith(`# export ${key}=`) ||
|
|
22
|
+
line.startsWith(`# ${key} `)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const OWNED_PREFIXES = [
|
|
27
|
+
"MEGACOMPACT_EMBEDDING_URL",
|
|
28
|
+
"MEGACOMPACT_ALLOW_REMOTE_EMBEDDER",
|
|
29
|
+
"MEGACOMPACT_MINILM",
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const SCAFFOLD_COMMENTS = new Set([
|
|
33
|
+
"# Mega-Compact Embedder Configuration",
|
|
34
|
+
"# trigram: built-in embedder, no URL needed",
|
|
35
|
+
"# unset MEGACOMPACT_EMBEDDING_URL (commented to override any shell-set value)",
|
|
36
|
+
"# MEGACOMPACT_ALLOW_REMOTE_EMBEDDER not set (loopback-only)",
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
function isScaffoldComment(line: string): boolean {
|
|
40
|
+
return (
|
|
41
|
+
SCAFFOLD_COMMENTS.has(line) ||
|
|
42
|
+
line.startsWith("# Configured via dashboard Setup tab at ")
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Write the embedder selection upsert-style into `<stateDir>/.mega-compact.env`.
|
|
48
|
+
* `resolvedUrl === null` selects the trigram (built-in) path — the emitted
|
|
49
|
+
* lines carry only the scaffold comments for that case (the URL/remote lines
|
|
50
|
+
* are intentionally absent, matching the pre-refactor byte shape).
|
|
51
|
+
*/
|
|
52
|
+
export function writeEmbedderEnv(
|
|
53
|
+
stateDir: string,
|
|
54
|
+
resolvedUrl: string | null,
|
|
55
|
+
allowRemote: boolean,
|
|
56
|
+
): string {
|
|
57
|
+
const envPath = join(stateDir, ".mega-compact.env");
|
|
58
|
+
const existingLines: string[] = (() => {
|
|
59
|
+
try {
|
|
60
|
+
return existsSync(envPath) ? readFileSync(envPath, "utf-8").split("\n") : [];
|
|
61
|
+
} catch {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
})();
|
|
65
|
+
const preserved: string[] = existingLines.filter(
|
|
66
|
+
(l) =>
|
|
67
|
+
l.trim().length > 0 &&
|
|
68
|
+
!isScaffoldComment(l) &&
|
|
69
|
+
!OWNED_PREFIXES.some((p) => ownsKey(l, p)),
|
|
70
|
+
);
|
|
71
|
+
const next: string[] = [
|
|
72
|
+
"# Mega-Compact Embedder Configuration",
|
|
73
|
+
`# Configured via dashboard Setup tab at ${new Date().toISOString()}`,
|
|
74
|
+
...preserved,
|
|
75
|
+
];
|
|
76
|
+
if (resolvedUrl !== null) {
|
|
77
|
+
next.push(`export MEGACOMPACT_EMBEDDING_URL="${resolvedUrl}"`);
|
|
78
|
+
if (allowRemote) {
|
|
79
|
+
next.push(`export MEGACOMPACT_ALLOW_REMOTE_EMBEDDER="1"`);
|
|
80
|
+
} else {
|
|
81
|
+
next.push(`# MEGACOMPACT_ALLOW_REMOTE_EMBEDDER not set (loopback-only)`);
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
next.push("# trigram: built-in embedder, no URL needed");
|
|
85
|
+
next.push("# unset MEGACOMPACT_EMBEDDING_URL (commented to override any shell-set value)");
|
|
86
|
+
next.push("# export MEGACOMPACT_EMBEDDING_URL=");
|
|
87
|
+
next.push("# export MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=");
|
|
88
|
+
}
|
|
89
|
+
next.push("");
|
|
90
|
+
mkdirSync(stateDir, { recursive: true });
|
|
91
|
+
writeFileSync(envPath, next.join("\n"), "utf-8");
|
|
92
|
+
return envPath;
|
|
93
|
+
}
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
* Each decoration line carries a guardrails-allow annotation.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
15
15
|
import type { RouteContext } from "./routes-core.js";
|
|
16
16
|
import { VC9D_ENABLED } from "../../src/config.js";
|
|
17
17
|
import { enc1aStatusFields, writeEnc1aEnv, tryEnc1aConfigure, wantsEnc1a } from "./routes-setup-enc1a.js";
|
|
18
|
+
import { enc1bStatusFields, tryEnc1bConfigure, tryEnc1bInto, enc1bValidateCombined } from "./routes-setup-enc1b.js";
|
|
19
|
+
import { writeEmbedderEnv } from "./routes-setup-env-upsert.js";
|
|
18
20
|
import {
|
|
19
21
|
detectOllama,
|
|
20
22
|
detectLlamaCpp,
|
|
@@ -91,7 +93,7 @@ export function handleSetupStatus(
|
|
|
91
93
|
minilm: ["1", "true", "yes"].includes(
|
|
92
94
|
(process.env["MEGACOMPACT_MINILM"] ?? "").trim().toLowerCase(),
|
|
93
95
|
),
|
|
94
|
-
...enc1aStatusFields(ctx.stateDir),
|
|
96
|
+
...enc1aStatusFields(ctx.stateDir), ...enc1bStatusFields(ctx.stateDir),
|
|
95
97
|
};
|
|
96
98
|
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
97
99
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -215,6 +217,21 @@ export function handleSetupConfigure(
|
|
|
215
217
|
// Flag-off = the keys are simply not recognized, falling through to the
|
|
216
218
|
// pre-ENC-1a embedder path below (byte-identical predecessor).
|
|
217
219
|
if (tryEnc1aConfigure(body, res, ctx)) return;
|
|
220
|
+
if (tryEnc1bConfigure(body, res, ctx)) return; // pure ENC-1b configure (dim/headers/allow-remote/native)
|
|
221
|
+
// ENC-1b combined-payload validation: when a payload carries a valid
|
|
222
|
+
// embedder PLUS the ENC-1b keys, tryEnc1bConfigure above returned false
|
|
223
|
+
// (it handles only the pure-ENC-1b shape) and tryEnc1bInto below would
|
|
224
|
+
// write WITHOUT validating. Run the same dim/headers validation here so
|
|
225
|
+
// the combined path is rejected with the same 400 codes. Flag-off:
|
|
226
|
+
// enc1bValidateCombined returns null (byte-identical predecessor — the
|
|
227
|
+
// unknown keys fall through untouched).
|
|
228
|
+
const combinedError = enc1bValidateCombined(body);
|
|
229
|
+
if (combinedError !== null) {
|
|
230
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
231
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
232
|
+
res.end(JSON.stringify({ error: combinedError }));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
218
235
|
const embedder = body.embedder;
|
|
219
236
|
if (embedder !== "ollama" && embedder !== "llama" && embedder !== "trigram" && embedder !== "custom" && embedder !== "onnx") {
|
|
220
237
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
@@ -239,30 +256,14 @@ export function handleSetupConfigure(
|
|
|
239
256
|
allowRemote = true;
|
|
240
257
|
} else resolvedUrl = null;
|
|
241
258
|
|
|
242
|
-
//
|
|
259
|
+
// Upsert-style write of the per-repo .mega-compact.env (sibling impl):
|
|
260
|
+
// preserves ENC-1a's endpoint/key + ENC-1b's dim/headers lines and any
|
|
261
|
+
// operator comments, replacing only the three keys this primary embedder
|
|
262
|
+
// write owns (URL / ALLOW_REMOTE / MINILM).
|
|
243
263
|
const stateDir = ctx.stateDir;
|
|
244
|
-
|
|
245
|
-
const lines: string[] = [
|
|
246
|
-
"# Mega-Compact Embedder Configuration",
|
|
247
|
-
`# Configured via dashboard Setup tab at ${new Date().toISOString()}`,
|
|
248
|
-
];
|
|
249
|
-
if (resolvedUrl) {
|
|
250
|
-
lines.push(`export MEGACOMPACT_EMBEDDING_URL="${resolvedUrl}"`);
|
|
251
|
-
if (allowRemote) {
|
|
252
|
-
lines.push(`export MEGACOMPACT_ALLOW_REMOTE_EMBEDDER="1"`);
|
|
253
|
-
} else {
|
|
254
|
-
lines.push(`# MEGACOMPACT_ALLOW_REMOTE_EMBEDDER not set (loopback-only)`);
|
|
255
|
-
}
|
|
256
|
-
} else {
|
|
257
|
-
lines.push("# trigram: built-in embedder, no URL needed");
|
|
258
|
-
lines.push("# unset MEGACOMPACT_EMBEDDING_URL (commented to override any shell-set value)");
|
|
259
|
-
lines.push("# export MEGACOMPACT_EMBEDDING_URL=");
|
|
260
|
-
lines.push("# export MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=");
|
|
261
|
-
}
|
|
262
|
-
lines.push("");
|
|
264
|
+
let envPath: string;
|
|
263
265
|
try {
|
|
264
|
-
|
|
265
|
-
writeFileSync(envPath, lines.join("\n"), "utf-8");
|
|
266
|
+
envPath = writeEmbedderEnv(stateDir, resolvedUrl, allowRemote);
|
|
266
267
|
} catch (e) {
|
|
267
268
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
268
269
|
res.end(JSON.stringify({ error: `write_failed: ${e instanceof Error ? e.message : String(e)}` }));
|
|
@@ -279,6 +280,7 @@ export function handleSetupConfigure(
|
|
|
279
280
|
apiKey: typeof body.embeddingApiKey === "string" ? body.embeddingApiKey : null,
|
|
280
281
|
});
|
|
281
282
|
}
|
|
283
|
+
tryEnc1bInto(stateDir, body); // ENC-1b combined upsert (dim/headers/allow-remote/native)
|
|
282
284
|
// Detect if the new config matches what's already active (no restart needed).
|
|
283
285
|
const currentUrl = process.env["MEGACOMPACT_EMBEDDING_URL"];
|
|
284
286
|
const alreadyActive = (resolvedUrl === null && !currentUrl) || (resolvedUrl !== null && currentUrl === resolvedUrl);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
14
14
|
import type { RouteContext } from "./routes-core.js";
|
|
15
|
-
import { VC0A_ENABLED } from "../../src/config.js";
|
|
15
|
+
import { VC0A_ENABLED, ML5D_ENABLED } from "../../src/config.js";
|
|
16
16
|
import { readEvalRows } from "../../src/vector-cortex/eval/persist.js";
|
|
17
17
|
import { summarizeEvalRows } from "../../src/vector-cortex/eval/reader.js";
|
|
18
18
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
@@ -53,6 +53,9 @@ export function handleVectorCortexEvaluation(
|
|
|
53
53
|
total: summary.histogram.total,
|
|
54
54
|
},
|
|
55
55
|
rejects: [], // VC0C wires live breaker/reject telemetry here
|
|
56
|
+
// ML5-D: additive, present only when the flag is enabled → the client can
|
|
57
|
+
// omit the ModelImprovementCard when off (byte-identical to ML5-C-era tab).
|
|
58
|
+
...(ML5D_ENABLED() ? { ml5dEnabled: true } : {}),
|
|
56
59
|
updatedAt: new Date().toISOString(),
|
|
57
60
|
status: deriveVcStatus({ enabled, hasData: summary.samples > 0 }),
|
|
58
61
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mega-compact",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.52",
|
|
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",
|