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,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SetupTab/CortexRuntimeCard.tsx — Encoder Runtime selection card (ENC-1b).
|
|
3
|
+
*
|
|
4
|
+
* Rendered on the Setup Cortex sub-tab. Reads the ENC-1b Cortex trio from the
|
|
5
|
+
* SAME /api/setup-status endpoint (and /api/setup-configure writer) the
|
|
6
|
+
* Embedder sub-tab uses — a single endpoint, no /api/setup-cortex-status read.
|
|
7
|
+
*
|
|
8
|
+
* The native opt-in toggle POSTs `encoderNativeOptIn`; the effective backend
|
|
9
|
+
* (`wasm` | `native`) and any demotion reason are surfaced reader-only from the
|
|
10
|
+
* status — no selection/install logic is reimplemented on the client.
|
|
11
|
+
*
|
|
12
|
+
* PREVENT-PI-004: all data comes from localhost dashboard API endpoints.
|
|
13
|
+
*/
|
|
14
|
+
import type React from "react";
|
|
15
|
+
import { useState, useEffect, useCallback } from "react";
|
|
16
|
+
import type { SetupStatusResponse } from "@contracts";
|
|
17
|
+
import { fetchSetupStatus, configureEmbedder } from "../../api/client";
|
|
18
|
+
import { styles } from "./CortexRuntimeCardStyles";
|
|
19
|
+
|
|
20
|
+
export default function CortexRuntimeCard(): React.ReactElement {
|
|
21
|
+
const [status, setStatus] = useState<SetupStatusResponse | null>(null);
|
|
22
|
+
const [error, setError] = useState<string | null>(null);
|
|
23
|
+
const [saving, setSaving] = useState(false);
|
|
24
|
+
|
|
25
|
+
const loadStatus = useCallback(() => {
|
|
26
|
+
fetchSetupStatus()
|
|
27
|
+
.then(setStatus)
|
|
28
|
+
.catch((e: unknown) => setError(e instanceof Error ? e.message : String(e)));
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
loadStatus();
|
|
33
|
+
}, [loadStatus]);
|
|
34
|
+
|
|
35
|
+
// Poll status every 5s — the same cadence as the Embedder sub-tab so the
|
|
36
|
+
// runtime card reflects persisted opt-in + effective backend changes live.
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const id = setInterval(loadStatus, 5000);
|
|
39
|
+
return () => clearInterval(id);
|
|
40
|
+
}, [loadStatus]);
|
|
41
|
+
|
|
42
|
+
// The card is only meaningful when the ENC-1b surface is active (the server
|
|
43
|
+
// carries the Cortex trio). Flag off → the keys are absent → hide the card.
|
|
44
|
+
const enabled = status !== null && "encoderNativeOptIn" in status;
|
|
45
|
+
|
|
46
|
+
const toggleNative = useCallback(
|
|
47
|
+
(next: boolean) => {
|
|
48
|
+
setSaving(true);
|
|
49
|
+
setError(null);
|
|
50
|
+
configureEmbedder({
|
|
51
|
+
embedder: "custom",
|
|
52
|
+
url: status?.embeddingEndpointUrl ?? undefined,
|
|
53
|
+
encoderNativeOptIn: next,
|
|
54
|
+
})
|
|
55
|
+
.then(() => {
|
|
56
|
+
setSaving(false);
|
|
57
|
+
loadStatus();
|
|
58
|
+
})
|
|
59
|
+
.catch((e: unknown) => {
|
|
60
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
61
|
+
setSaving(false);
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
[status, loadStatus],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (!enabled) return <></>;
|
|
68
|
+
|
|
69
|
+
const backend = status?.encoderBackend ?? "wasm";
|
|
70
|
+
const demotion = status?.encoderDemotionReason ?? null;
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div style={styles.section}>
|
|
74
|
+
<h3 style={styles.sectionTitle}>Encoder Runtime</h3>
|
|
75
|
+
<p style={styles.subtitle}>ONNX backend selection</p>
|
|
76
|
+
<div style={styles.toggleRow}>
|
|
77
|
+
<input
|
|
78
|
+
type="checkbox"
|
|
79
|
+
checked={status?.encoderNativeOptIn === true}
|
|
80
|
+
onChange={(e) => toggleNative(e.target.checked)}
|
|
81
|
+
disabled={saving}
|
|
82
|
+
aria-label="Native ONNX runtime (onnxruntime-node)"
|
|
83
|
+
/>
|
|
84
|
+
<label>Native ONNX runtime (onnxruntime-node)</label>
|
|
85
|
+
{saving && (
|
|
86
|
+
<span style={{ fontSize: "0.8rem", color: "#a0a0c0" }}>saving...</span>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
<div style={styles.row}>
|
|
90
|
+
<span style={styles.label}>Effective backend:</span>
|
|
91
|
+
<span style={styles.value}>{backend}</span>
|
|
92
|
+
</div>
|
|
93
|
+
{demotion !== null && (
|
|
94
|
+
<div style={styles.warning}>
|
|
95
|
+
<strong>Demoted:</strong> {demotion}
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
{error && (
|
|
99
|
+
<p style={{ color: "#f44336", fontSize: "0.85rem" }}>Error: {error}</p>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SetupTab/CortexRuntimeCardStyles.ts — extracted styles for CortexRuntimeCard.
|
|
3
|
+
*
|
|
4
|
+
* Split from CortexRuntimeCard.tsx to respect the extensions/ 400-line soft
|
|
5
|
+
* limit (mirrors the EmbedderSetupStyles.tsx convention).
|
|
6
|
+
*/
|
|
7
|
+
import type React from "react";
|
|
8
|
+
|
|
9
|
+
export const styles: Record<string, React.CSSProperties> = {
|
|
10
|
+
section: {
|
|
11
|
+
background: "#1a1a2e",
|
|
12
|
+
borderRadius: "8px",
|
|
13
|
+
padding: "1rem",
|
|
14
|
+
marginBottom: "1rem",
|
|
15
|
+
border: "1px solid #2a2a4e",
|
|
16
|
+
},
|
|
17
|
+
sectionTitle: {
|
|
18
|
+
fontSize: "1.1rem",
|
|
19
|
+
fontWeight: 700,
|
|
20
|
+
marginTop: 0,
|
|
21
|
+
marginBottom: "0.25rem",
|
|
22
|
+
color: "#e0e0e0",
|
|
23
|
+
},
|
|
24
|
+
subtitle: {
|
|
25
|
+
fontSize: "0.85rem",
|
|
26
|
+
color: "#a0a0c0",
|
|
27
|
+
marginTop: 0,
|
|
28
|
+
marginBottom: "0.75rem",
|
|
29
|
+
},
|
|
30
|
+
row: { marginBottom: "0.4rem", fontSize: "0.9rem" },
|
|
31
|
+
label: { fontWeight: 600, color: "#a0a0c0", marginRight: "0.5rem" },
|
|
32
|
+
value: { color: "#e0e0e0" },
|
|
33
|
+
warning: {
|
|
34
|
+
background: "#3a2a00",
|
|
35
|
+
border: "1px solid #665500",
|
|
36
|
+
borderRadius: "8px",
|
|
37
|
+
padding: "0.75rem",
|
|
38
|
+
marginTop: "0.5rem",
|
|
39
|
+
color: "#ffcc00",
|
|
40
|
+
fontSize: "0.85rem",
|
|
41
|
+
},
|
|
42
|
+
toggleRow: {
|
|
43
|
+
display: "flex",
|
|
44
|
+
alignItems: "center",
|
|
45
|
+
gap: "0.5rem",
|
|
46
|
+
marginBottom: "0.75rem",
|
|
47
|
+
fontSize: "0.9rem",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
@@ -14,6 +14,7 @@ import { useSetupCortexPoll } from "../useSetupCortexPoll";
|
|
|
14
14
|
import { CortexEncoderCard } from "./CortexEncoderCard";
|
|
15
15
|
import { CortexBlockersCard } from "./CortexBlockersCard";
|
|
16
16
|
import { CortexActionsCard } from "./CortexActionsCard";
|
|
17
|
+
import CortexRuntimeCard from "./CortexRuntimeCard";
|
|
17
18
|
import { styles } from "./CortexSetupStyles";
|
|
18
19
|
|
|
19
20
|
export default function CortexSetup(): React.ReactElement {
|
|
@@ -39,6 +40,7 @@ export default function CortexSetup(): React.ReactElement {
|
|
|
39
40
|
</p>
|
|
40
41
|
|
|
41
42
|
<CortexEncoderCard data={state.data} error={state.error} />
|
|
43
|
+
<CortexRuntimeCard />
|
|
42
44
|
<CortexBlockersCard
|
|
43
45
|
blockers={state.data?.blockers ?? []}
|
|
44
46
|
highlight={highlight}
|
|
@@ -25,10 +25,21 @@ interface CustomEndpointSectionProps {
|
|
|
25
25
|
embedder: "ollama" | "llama" | "trigram" | "custom" | "onnx",
|
|
26
26
|
url?: string,
|
|
27
27
|
apiKey?: string,
|
|
28
|
+
dim?: string,
|
|
29
|
+
headers?: string,
|
|
30
|
+
allowRemote?: boolean,
|
|
28
31
|
) => void;
|
|
29
32
|
configuring: string | null;
|
|
30
33
|
/** ENC-1a surface active — true when the new setup-status fields are present. */
|
|
31
34
|
inputEnabled: boolean;
|
|
35
|
+
/** Server-reported "key is set" marker (the key itself is never returned). */
|
|
36
|
+
apiKeySet: boolean;
|
|
37
|
+
/** ENC-1b: the persisted `embeddingDim` value (numeric string), or undefined. One-shot seed. */
|
|
38
|
+
embeddingDim: string | undefined;
|
|
39
|
+
/** ENC-1b: server-reported "headers are set" marker (the raw JSON is never returned). */
|
|
40
|
+
embeddingHeadersSet: boolean;
|
|
41
|
+
/** ENC-1b: the persisted allow-remote flag, or undefined. One-shot seed. */
|
|
42
|
+
allowRemoteEmbedder: boolean | undefined;
|
|
32
43
|
configureResult: SetupConfigureResponse | null;
|
|
33
44
|
configureError: string | null;
|
|
34
45
|
}
|
|
@@ -39,12 +50,36 @@ export default function CustomEndpointSection({
|
|
|
39
50
|
applyEmbedder,
|
|
40
51
|
configuring,
|
|
41
52
|
inputEnabled,
|
|
53
|
+
apiKeySet,
|
|
54
|
+
embeddingDim,
|
|
55
|
+
embeddingHeadersSet,
|
|
56
|
+
allowRemoteEmbedder,
|
|
42
57
|
configureResult,
|
|
43
58
|
configureError,
|
|
44
59
|
}: CustomEndpointSectionProps): React.ReactElement {
|
|
45
60
|
// The API key is intentionally local-only state: it always renders blank and
|
|
46
61
|
// is never seeded from the persisted value (the server never returns it).
|
|
47
62
|
const [customApiKey, setCustomApiKey] = useState("");
|
|
63
|
+
// ENC-1b: the embedding dim, seeded once from the persisted value (never
|
|
64
|
+
// re-seeded after a poll so the user's in-flight edits survive the 5s poll).
|
|
65
|
+
const [dim, setDim] = useState("");
|
|
66
|
+
const [dimSeeded, setDimSeeded] = useState(false);
|
|
67
|
+
// ENC-1b: the headers JSON is local-only, write-only state: NEVER prefilled,
|
|
68
|
+
// never seeded, never shown back — the server persists it verbatim and only
|
|
69
|
+
// ever reports its presence via `embeddingHeadersSet`.
|
|
70
|
+
const [headers, setHeaders] = useState("");
|
|
71
|
+
// ENC-1b: allow-remote toggle, seeded once from the persisted flag.
|
|
72
|
+
const [allowRemote, setAllowRemote] = useState(false);
|
|
73
|
+
const [allowRemoteSeeded, setAllowRemoteSeeded] = useState(false);
|
|
74
|
+
|
|
75
|
+
if (inputEnabled && !dimSeeded && typeof embeddingDim === "string") {
|
|
76
|
+
setDim(embeddingDim);
|
|
77
|
+
setDimSeeded(true);
|
|
78
|
+
}
|
|
79
|
+
if (inputEnabled && !allowRemoteSeeded && typeof allowRemoteEmbedder === "boolean") {
|
|
80
|
+
setAllowRemote(allowRemoteEmbedder);
|
|
81
|
+
setAllowRemoteSeeded(true);
|
|
82
|
+
}
|
|
48
83
|
|
|
49
84
|
return (
|
|
50
85
|
<div style={styles.section}>
|
|
@@ -93,14 +128,100 @@ export default function CustomEndpointSection({
|
|
|
93
128
|
}}
|
|
94
129
|
/>
|
|
95
130
|
)}
|
|
131
|
+
{inputEnabled && apiKeySet && (
|
|
132
|
+
<span
|
|
133
|
+
style={{
|
|
134
|
+
fontSize: "0.75rem",
|
|
135
|
+
color: "#81c784",
|
|
136
|
+
border: "1px solid #2a4e2a",
|
|
137
|
+
borderRadius: "4px",
|
|
138
|
+
padding: "0.15rem 0.45rem",
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
API key saved
|
|
142
|
+
</span>
|
|
143
|
+
)}
|
|
144
|
+
{inputEnabled && embeddingHeadersSet && (
|
|
145
|
+
<span
|
|
146
|
+
style={{
|
|
147
|
+
fontSize: "0.75rem",
|
|
148
|
+
color: "#81c784",
|
|
149
|
+
border: "1px solid #2a4e2a",
|
|
150
|
+
borderRadius: "4px",
|
|
151
|
+
padding: "0.15rem 0.45rem",
|
|
152
|
+
}}
|
|
153
|
+
>
|
|
154
|
+
Headers saved
|
|
155
|
+
</span>
|
|
156
|
+
)}
|
|
96
157
|
<button
|
|
97
158
|
style={{ ...styles.button, opacity: customUrl ? 1 : 0.4 }}
|
|
98
|
-
onClick={() =>
|
|
159
|
+
onClick={() =>
|
|
160
|
+
applyEmbedder("custom", customUrl, customApiKey, dim, headers, allowRemote)
|
|
161
|
+
}
|
|
99
162
|
disabled={!customUrl || configuring !== null}
|
|
100
163
|
>
|
|
101
164
|
{configuring === "custom" ? "Writing..." : "Use Custom URL"}
|
|
102
165
|
</button>
|
|
103
166
|
</div>
|
|
167
|
+
{inputEnabled && (
|
|
168
|
+
<div style={{ marginTop: "0.75rem" }}>
|
|
169
|
+
<div style={{ marginBottom: "0.5rem" }}>
|
|
170
|
+
<label style={{ ...styles.label, display: "block", marginBottom: "0.25rem" }}>
|
|
171
|
+
Embedding dim (optional)
|
|
172
|
+
</label>
|
|
173
|
+
<input
|
|
174
|
+
type="number"
|
|
175
|
+
min={1}
|
|
176
|
+
placeholder="e.g. 384"
|
|
177
|
+
value={dim}
|
|
178
|
+
onChange={(e) => setDim(e.target.value)}
|
|
179
|
+
style={{
|
|
180
|
+
width: "200px",
|
|
181
|
+
background: "#12122a",
|
|
182
|
+
color: "#e0e0e0",
|
|
183
|
+
border: "1px solid #2a2a4e",
|
|
184
|
+
borderRadius: "6px",
|
|
185
|
+
padding: "0.4rem 0.6rem",
|
|
186
|
+
fontSize: "0.85rem",
|
|
187
|
+
fontFamily: "monospace",
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
<div style={{ marginBottom: "0.5rem" }}>
|
|
192
|
+
<label style={{ ...styles.label, display: "block", marginBottom: "0.25rem" }}>
|
|
193
|
+
Embedding headers (JSON, write-only — never re-displayed)
|
|
194
|
+
</label>
|
|
195
|
+
<textarea
|
|
196
|
+
placeholder={'{"Authorization": "Bearer ..."}'}
|
|
197
|
+
value={headers}
|
|
198
|
+
onChange={(e) => setHeaders(e.target.value)}
|
|
199
|
+
aria-label="Embedding headers JSON (write-only — never re-displayed)"
|
|
200
|
+
rows={2}
|
|
201
|
+
style={{
|
|
202
|
+
width: "100%",
|
|
203
|
+
background: "#12122a",
|
|
204
|
+
color: "#e0e0e0",
|
|
205
|
+
border: "1px solid #2a2a4e",
|
|
206
|
+
borderRadius: "6px",
|
|
207
|
+
padding: "0.4rem 0.6rem",
|
|
208
|
+
fontSize: "0.85rem",
|
|
209
|
+
fontFamily: "monospace",
|
|
210
|
+
resize: "vertical",
|
|
211
|
+
}}
|
|
212
|
+
/>
|
|
213
|
+
</div>
|
|
214
|
+
<label style={{ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.85rem" }}>
|
|
215
|
+
<input
|
|
216
|
+
type="checkbox"
|
|
217
|
+
checked={allowRemote}
|
|
218
|
+
onChange={(e) => setAllowRemote(e.target.checked)}
|
|
219
|
+
aria-label="Allow remote embedder (skips loopback-only check)"
|
|
220
|
+
/>
|
|
221
|
+
Allow remote embedder (skips loopback-only check)
|
|
222
|
+
</label>
|
|
223
|
+
</div>
|
|
224
|
+
)}
|
|
104
225
|
{configureError !== null && (
|
|
105
226
|
<p style={{ color: "#f44336", fontSize: "0.85rem", marginTop: "0.5rem" }}>
|
|
106
227
|
Configure error: {configureError}
|
|
@@ -16,7 +16,7 @@ import EmbedderHealthCard from "./EmbedderHealthCard";
|
|
|
16
16
|
import SettingsPanel from "./SettingsPanel";
|
|
17
17
|
import CustomEndpointSection from "./CustomEndpointSection";
|
|
18
18
|
import { styles } from "./EmbedderSetupStyles";
|
|
19
|
-
import {
|
|
19
|
+
import { detectBadge, CurrentConfigSection } from "./EmbedderSetupHelpers";
|
|
20
20
|
|
|
21
21
|
export default function EmbedderSetup(): React.ReactElement {
|
|
22
22
|
const [status, setStatus] = useState<SetupStatusResponse | null>(null);
|
|
@@ -28,6 +28,10 @@ export default function EmbedderSetup(): React.ReactElement {
|
|
|
28
28
|
const [configResult, setConfigResult] = useState<SetupConfigureResponse | null>(null);
|
|
29
29
|
const [configError, setConfigError] = useState<string | null>(null);
|
|
30
30
|
const [customUrl, setCustomUrl] = useState("");
|
|
31
|
+
// True once the URL field has been seeded from the persisted endpoint URL —
|
|
32
|
+
// seeding runs only on the first status load that carries the field so the
|
|
33
|
+
// user's in-flight edits are never clobbered by a poll refresh.
|
|
34
|
+
const [customUrlSeeded, setCustomUrlSeeded] = useState(false);
|
|
31
35
|
|
|
32
36
|
const loadStatus = useCallback(() => {
|
|
33
37
|
fetchSetupStatus()
|
|
@@ -37,22 +41,43 @@ export default function EmbedderSetup(): React.ReactElement {
|
|
|
37
41
|
);
|
|
38
42
|
}, []);
|
|
39
43
|
|
|
40
|
-
const applyEmbedder = useCallback(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
const applyEmbedder = useCallback(
|
|
45
|
+
(
|
|
46
|
+
embedder: "ollama" | "llama" | "trigram" | "custom" | "onnx",
|
|
47
|
+
url?: string,
|
|
48
|
+
apiKey?: string,
|
|
49
|
+
dim?: string,
|
|
50
|
+
headers?: string,
|
|
51
|
+
allowRemote?: boolean,
|
|
52
|
+
) => {
|
|
53
|
+
setConfiguring(embedder);
|
|
54
|
+
setConfigError(null);
|
|
55
|
+
setConfigResult(null);
|
|
56
|
+
// ENC-1a: optional custom-endpoint URL + bearer key ride on the setup-configure POST (additive; flag-off ignores them).
|
|
57
|
+
// ENC-1b: the dim / headers / allow-remote fields are forwarded additively, gated on the same
|
|
58
|
+
// `embeddingHeadersSet` presence marker the aggregator/server uses (no separate client env read).
|
|
59
|
+
const enc1bOn = "embeddingHeadersSet" in (status ?? {});
|
|
60
|
+
configureEmbedder({
|
|
61
|
+
embedder,
|
|
62
|
+
url,
|
|
63
|
+
embeddingEndpointUrl: url,
|
|
64
|
+
embeddingApiKey: apiKey,
|
|
65
|
+
...(enc1bOn
|
|
66
|
+
? { embeddingDim: dim, embeddingHeaders: headers, allowRemoteEmbedder: allowRemote }
|
|
67
|
+
: {}),
|
|
50
68
|
})
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
.then((r) => {
|
|
70
|
+
setConfigResult(r);
|
|
71
|
+
setConfiguring(null);
|
|
72
|
+
loadStatus();
|
|
73
|
+
})
|
|
74
|
+
.catch((e: unknown) => {
|
|
75
|
+
setConfigError(e instanceof Error ? e.message : String(e));
|
|
76
|
+
setConfiguring(null);
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
[loadStatus, status],
|
|
80
|
+
);
|
|
56
81
|
|
|
57
82
|
const runDetect = useCallback(() => {
|
|
58
83
|
setRunningDetect(true);
|
|
@@ -72,6 +97,17 @@ export default function EmbedderSetup(): React.ReactElement {
|
|
|
72
97
|
loadStatus();
|
|
73
98
|
}, [loadStatus]);
|
|
74
99
|
|
|
100
|
+
// Seed the custom-endpoint URL field once from the persisted
|
|
101
|
+
// `embeddingEndpointUrl` (ENC-1a). Later poll refreshes do NOT re-seed —
|
|
102
|
+
// only the first load, so typed edits survive the 5s status poll.
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (customUrlSeeded) return;
|
|
105
|
+
if (status && typeof status.embeddingEndpointUrl === "string" && status.embeddingEndpointUrl.length > 0) {
|
|
106
|
+
setCustomUrl(status.embeddingEndpointUrl);
|
|
107
|
+
setCustomUrlSeeded(true);
|
|
108
|
+
}
|
|
109
|
+
}, [status, customUrlSeeded]);
|
|
110
|
+
|
|
75
111
|
// Poll status every 5s — the same cadence the Setup Cortex sub-tab uses
|
|
76
112
|
// (see useSetupCortexPoll) so the embedder + cortex sub-tabs share one poll
|
|
77
113
|
// contract (VC9D consolidation). Detection is memoized server-side, so the
|
|
@@ -99,69 +135,7 @@ export default function EmbedderSetup(): React.ReactElement {
|
|
|
99
135
|
<EmbedderHealthCard />
|
|
100
136
|
|
|
101
137
|
{/* Current Config Section */}
|
|
102
|
-
<
|
|
103
|
-
<h3 style={styles.sectionTitle}>Current Embedder Configuration</h3>
|
|
104
|
-
{statusError && (
|
|
105
|
-
<p style={{ color: "#f44336", fontSize: "0.85rem" }}>
|
|
106
|
-
Error: {statusError}
|
|
107
|
-
</p>
|
|
108
|
-
)}
|
|
109
|
-
{status && (
|
|
110
|
-
<>
|
|
111
|
-
<div style={styles.row}>
|
|
112
|
-
<span style={styles.label}>Active Embedder:</span>
|
|
113
|
-
<span style={styles.value}>
|
|
114
|
-
{embedderLabel(status.currentEmbedder)}
|
|
115
|
-
</span>
|
|
116
|
-
</div>
|
|
117
|
-
{"configuredEmbedder" in status && status.configuredEmbedder !== status.currentEmbedder && (
|
|
118
|
-
<div style={styles.warning}>
|
|
119
|
-
<strong>Configured but not active:</strong>{" "}
|
|
120
|
-
{embedderLabel(status.configuredEmbedder)} is configured in
|
|
121
|
-
.mega-compact.env but not yet loaded.{" "}
|
|
122
|
-
<strong>Restart pi</strong> to activate it.
|
|
123
|
-
{status.configuredUrl && (
|
|
124
|
-
<> ({status.configuredUrl})</>
|
|
125
|
-
)}
|
|
126
|
-
</div>
|
|
127
|
-
)}
|
|
128
|
-
{"restartRequired" in status && status.restartRequired && (
|
|
129
|
-
<div style={{ ...styles.row, color: "#ff9800" }}>
|
|
130
|
-
<span style={styles.label}>Status:</span>
|
|
131
|
-
<span style={styles.value}>
|
|
132
|
-
Restart required to activate the configured embedder
|
|
133
|
-
</span>
|
|
134
|
-
</div>
|
|
135
|
-
)}
|
|
136
|
-
<div style={styles.row}>
|
|
137
|
-
<span style={styles.label}>Embedding URL:</span>
|
|
138
|
-
<span style={styles.value}>
|
|
139
|
-
{status.embeddingUrl ?? (
|
|
140
|
-
<span style={{ color: "#888" }}>not set</span>
|
|
141
|
-
)}
|
|
142
|
-
</span>
|
|
143
|
-
</div>
|
|
144
|
-
<div style={styles.row}>
|
|
145
|
-
<span style={styles.label}>Embed Cache:</span>
|
|
146
|
-
<span style={styles.value}>
|
|
147
|
-
{status.embedCache ?? (
|
|
148
|
-
<span style={{ color: "#888" }}>not set</span>
|
|
149
|
-
)}
|
|
150
|
-
</span>
|
|
151
|
-
</div>
|
|
152
|
-
<div style={styles.row}>
|
|
153
|
-
<span style={styles.label}>MiniLM:</span>
|
|
154
|
-
<span style={styles.value}>{status.minilm ? "enabled" : "disabled"}</span>
|
|
155
|
-
</div>
|
|
156
|
-
{trigramWarning(status)}
|
|
157
|
-
</>
|
|
158
|
-
)}
|
|
159
|
-
{!status && !statusError && (
|
|
160
|
-
<p style={{ color: "#888", fontSize: "0.85rem" }}>
|
|
161
|
-
Loading configuration...
|
|
162
|
-
</p>
|
|
163
|
-
)}
|
|
164
|
-
</div>
|
|
138
|
+
<CurrentConfigSection status={status} statusError={statusError} />
|
|
165
139
|
|
|
166
140
|
{/* Detection Section */}
|
|
167
141
|
<div style={styles.section}>
|
|
@@ -324,6 +298,10 @@ export default function EmbedderSetup(): React.ReactElement {
|
|
|
324
298
|
applyEmbedder={applyEmbedder}
|
|
325
299
|
configuring={configuring}
|
|
326
300
|
inputEnabled={status !== null && "embeddingApiKeySet" in status}
|
|
301
|
+
apiKeySet={status?.embeddingApiKeySet === true}
|
|
302
|
+
embeddingDim={status?.embeddingDim}
|
|
303
|
+
embeddingHeadersSet={status?.embeddingHeadersSet === true}
|
|
304
|
+
allowRemoteEmbedder={status?.allowRemoteEmbedder}
|
|
327
305
|
configureResult={configResult}
|
|
328
306
|
configureError={configError}
|
|
329
307
|
/>
|
|
@@ -48,3 +48,78 @@ export function detectBadge(installed: boolean): React.ReactElement {
|
|
|
48
48
|
</span>
|
|
49
49
|
);
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
/** The "Current Embedder Configuration" readout block. */
|
|
53
|
+
export function CurrentConfigSection({
|
|
54
|
+
status,
|
|
55
|
+
statusError,
|
|
56
|
+
}: {
|
|
57
|
+
status: SetupStatusResponse | null;
|
|
58
|
+
statusError: string | null;
|
|
59
|
+
}): React.ReactElement {
|
|
60
|
+
return (
|
|
61
|
+
<div style={styles.section}>
|
|
62
|
+
<h3 style={styles.sectionTitle}>Current Embedder Configuration</h3>
|
|
63
|
+
{statusError && (
|
|
64
|
+
<p style={{ color: "#f44336", fontSize: "0.85rem" }}>
|
|
65
|
+
Error: {statusError}
|
|
66
|
+
</p>
|
|
67
|
+
)}
|
|
68
|
+
{status && (
|
|
69
|
+
<>
|
|
70
|
+
<div style={styles.row}>
|
|
71
|
+
<span style={styles.label}>Active Embedder:</span>
|
|
72
|
+
<span style={styles.value}>
|
|
73
|
+
{embedderLabel(status.currentEmbedder)}
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
76
|
+
{"configuredEmbedder" in status && status.configuredEmbedder !== status.currentEmbedder && (
|
|
77
|
+
<div style={styles.warning}>
|
|
78
|
+
<strong>Configured but not active:</strong>{" "}
|
|
79
|
+
{embedderLabel(status.configuredEmbedder)} is configured in
|
|
80
|
+
.mega-compact.env but not yet loaded.{" "}
|
|
81
|
+
<strong>Restart pi</strong> to activate it.
|
|
82
|
+
{status.configuredUrl && (
|
|
83
|
+
<> ({status.configuredUrl})</>
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
87
|
+
{"restartRequired" in status && status.restartRequired && (
|
|
88
|
+
<div style={{ ...styles.row, color: "#ff9800" }}>
|
|
89
|
+
<span style={styles.label}>Status:</span>
|
|
90
|
+
<span style={styles.value}>
|
|
91
|
+
Restart required to activate the configured embedder
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
94
|
+
)}
|
|
95
|
+
<div style={styles.row}>
|
|
96
|
+
<span style={styles.label}>Embedding URL:</span>
|
|
97
|
+
<span style={styles.value}>
|
|
98
|
+
{status.embeddingUrl ?? (
|
|
99
|
+
<span style={{ color: "#888" }}>not set</span>
|
|
100
|
+
)}
|
|
101
|
+
</span>
|
|
102
|
+
</div>
|
|
103
|
+
<div style={styles.row}>
|
|
104
|
+
<span style={styles.label}>Embed Cache:</span>
|
|
105
|
+
<span style={styles.value}>
|
|
106
|
+
{status.embedCache ?? (
|
|
107
|
+
<span style={{ color: "#888" }}>not set</span>
|
|
108
|
+
)}
|
|
109
|
+
</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div style={styles.row}>
|
|
112
|
+
<span style={styles.label}>MiniLM:</span>
|
|
113
|
+
<span style={styles.value}>{status.minilm ? "enabled" : "disabled"}</span>
|
|
114
|
+
</div>
|
|
115
|
+
{trigramWarning(status)}
|
|
116
|
+
</>
|
|
117
|
+
)}
|
|
118
|
+
{!status && !statusError && (
|
|
119
|
+
<p style={{ color: "#888", fontSize: "0.85rem" }}>
|
|
120
|
+
Loading configuration...
|
|
121
|
+
</p>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -194,11 +194,13 @@ export default function VectorCortexTab(): React.ReactElement {
|
|
|
194
194
|
)}
|
|
195
195
|
</CardContent>
|
|
196
196
|
</Card>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
{data.ml5dEnabled && (
|
|
198
|
+
<ModelImprovementCard
|
|
199
|
+
encoderMode={health?.encoderMode ?? "B"}
|
|
200
|
+
encoderAssetDigest={health?.encoderAssetDigest ?? null}
|
|
201
|
+
status={data.status}
|
|
202
|
+
/>
|
|
203
|
+
)}
|
|
202
204
|
<VectorCortexTopologyCard topology={poll.topology} query={poll.query} />
|
|
203
205
|
<VectorCortexShardsCard view={poll.shards} />
|
|
204
206
|
<VectorCortexReconstructCard view={poll.reconstruct} />
|
|
@@ -18,6 +18,12 @@ export interface VectorCortexEvaluationSummary {
|
|
|
18
18
|
total: number;
|
|
19
19
|
};
|
|
20
20
|
rejects: string[];
|
|
21
|
+
/**
|
|
22
|
+
* ML5-D dashboard "Improve Cortex" flag state. Additive/omitted when
|
|
23
|
+
* MEGACOMPACT_ML5_D is off — the client omits the ModelImprovementCard
|
|
24
|
+
* (byte-identical to the ML5-C-era tab). Present (true) only when enabled.
|
|
25
|
+
*/
|
|
26
|
+
readonly ml5dEnabled?: boolean;
|
|
21
27
|
updatedAt: string;
|
|
22
28
|
}
|
|
23
29
|
|
|
@@ -33,6 +33,28 @@ export interface SetupStatusResponse {
|
|
|
33
33
|
/** ENC-1a: whether an external embedder API key is configured. The raw key is
|
|
34
34
|
* NEVER returned — only this boolean presence marker (additive, flag-gated). */
|
|
35
35
|
readonly embeddingApiKeySet?: boolean;
|
|
36
|
+
/** ENC-1b: the persisted `MEGACOMPACT_EMBEDDING_DIM` value as its numeric
|
|
37
|
+
* string, when one is configured (additive, flag-gated). */
|
|
38
|
+
readonly embeddingDim?: string;
|
|
39
|
+
/** ENC-1b: whether `MEGACOMPACT_EMBEDDING_HEADERS` is configured. The raw
|
|
40
|
+
* headers JSON is NEVER returned — only this boolean presence marker
|
|
41
|
+
* (additive, flag-gated, redaction mirrors embeddingApiKeySet). */
|
|
42
|
+
readonly embeddingHeadersSet?: boolean;
|
|
43
|
+
/** ENC-1b: whether `MEGACOMPACT_ALLOW_REMOTE_EMBEDDER` is set (default off —
|
|
44
|
+
* a deliberate escape hatch that skips the loopback-only check; additive,
|
|
45
|
+
* flag-gated). */
|
|
46
|
+
readonly allowRemoteEmbedder?: boolean;
|
|
47
|
+
/** ENC-1b: whether `MEGACOMPACT_ENCODER_NATIVE=1` is set, i.e. the operator
|
|
48
|
+
* opted into the onnxruntime-node native backend (additive, flag-gated). */
|
|
49
|
+
readonly encoderNativeOptIn?: boolean;
|
|
50
|
+
/** ENC-1b: the current effective ONNX runtime backend, computed live through
|
|
51
|
+
* the existing `selectRuntimeBackend`. `modeB` (flag-off / no runtime) is
|
|
52
|
+
* projected to `wasm` for display (additive, flag-gated). */
|
|
53
|
+
readonly encoderBackend?: "wasm" | "native";
|
|
54
|
+
/** ENC-1b: the runtime's own demotion reason when the effective backend
|
|
55
|
+
* falls back (e.g. native selected but onnxruntime-node absent / darwin-x64
|
|
56
|
+
* demoted), surfaced verbatim; null when no demotion (additive, flag-gated). */
|
|
57
|
+
readonly encoderDemotionReason?: string | null;
|
|
36
58
|
}
|
|
37
59
|
|
|
38
60
|
/**
|
|
@@ -84,6 +106,19 @@ export interface SetupConfigureRequest {
|
|
|
84
106
|
/** ENC-1a: external embedder API key, persisted to the per-repo
|
|
85
107
|
* `.mega-compact.env` only — never returned by any GET (additive, flag-gated). */
|
|
86
108
|
readonly embeddingApiKey?: string;
|
|
109
|
+
/** ENC-1b: persisted `MEGACOMPACT_EMBEDDING_DIM` as a positive integer string
|
|
110
|
+
* within `ENC_1B_MAX_EMBEDDING_DIM` (validated; additive, flag-gated). */
|
|
111
|
+
readonly embeddingDim?: string;
|
|
112
|
+
/** ENC-1b: persisted `MEGACOMPACT_EMBEDDING_HEADERS` JSON object string
|
|
113
|
+
* (secret-bearing — written verbatim, NEVER echoed back; validated to parse
|
|
114
|
+
* as a JSON object; additive, flag-gated). */
|
|
115
|
+
readonly embeddingHeaders?: string;
|
|
116
|
+
/** ENC-1b: opt in to `MEGACOMPACT_ALLOW_REMOTE_EMBEDDER` (default off — a
|
|
117
|
+
* deliberate escape hatch; additive, flag-gated). */
|
|
118
|
+
readonly allowRemoteEmbedder?: boolean;
|
|
119
|
+
/** ENC-1b: opt in to `MEGACOMPACT_ENCODER_NATIVE` (onnxruntime-node native
|
|
120
|
+
* backend; additive, flag-gated). */
|
|
121
|
+
readonly encoderNativeOptIn?: boolean;
|
|
87
122
|
}
|
|
88
123
|
|
|
89
124
|
/** Response for POST /api/setup-configure. */
|