@ddtcorex/dsh-maestro-config 0.1.0 → 0.1.1
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/lib/client.js
CHANGED
|
@@ -2299,6 +2299,29 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
2299
2299
|
document.removeEventListener("keydown", onKey);
|
|
2300
2300
|
};
|
|
2301
2301
|
}, [open]);
|
|
2302
|
+
const getModelId = (m) => typeof m === "string" ? m : m.id;
|
|
2303
|
+
const getModelName = (m) => typeof m === "string" ? m : m.name ?? m.id;
|
|
2304
|
+
const selectedModelInfo = (() => {
|
|
2305
|
+
if (!selectedProvider || !value?.model) return null;
|
|
2306
|
+
const raw = (providerGroup?.models ?? []).find((mm) => getModelId(mm) === value.model);
|
|
2307
|
+
if (raw === void 0) return null;
|
|
2308
|
+
if (typeof raw === "string") return { id: raw, supportsReasoning: false, reasoningEfforts: [] };
|
|
2309
|
+
return raw;
|
|
2310
|
+
})();
|
|
2311
|
+
const supportsReasoning = (() => {
|
|
2312
|
+
if (!selectedModelInfo) return false;
|
|
2313
|
+
if (typeof selectedModelInfo.supportsReasoning === "boolean") return selectedModelInfo.supportsReasoning;
|
|
2314
|
+
const efforts = selectedModelInfo.reasoningEfforts ?? selectedModelInfo.reasoning?.efforts?.map((e) => e.id) ?? [];
|
|
2315
|
+
return efforts.filter((e) => e !== "off").length > 0;
|
|
2316
|
+
})();
|
|
2317
|
+
const availableEfforts = (() => {
|
|
2318
|
+
if (!supportsReasoning) return [];
|
|
2319
|
+
const efforts = selectedModelInfo?.reasoningEfforts ?? selectedModelInfo?.reasoning?.efforts?.map((e) => e.id) ?? [];
|
|
2320
|
+
const filtered = efforts.filter((e) => e !== "off" && e !== "");
|
|
2321
|
+
if (filtered.length > 0) return filtered;
|
|
2322
|
+
return ["low", "medium", "high"];
|
|
2323
|
+
})();
|
|
2324
|
+
const warning = selectedEffort !== "" && !supportsReasoning && selectedModelInfo !== null ? `\u26A0\uFE0F This model does not support reasoning effort "${selectedEffort}" \u2014 reviews will fail. Clear effort or choose a reasoning-capable model.` : null;
|
|
2302
2325
|
const update = (field, newVal) => {
|
|
2303
2326
|
if (newVal === "" && field === "provider") {
|
|
2304
2327
|
onChange(null);
|
|
@@ -2309,8 +2332,9 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
2309
2332
|
const next = { provider: value?.provider ?? "", model: value?.model ?? "", ...value?.reasoningEffort ? { reasoningEffort: value.reasoningEffort } : {} };
|
|
2310
2333
|
if (field === "provider") {
|
|
2311
2334
|
const g = groups.find((x) => x.provider === newVal);
|
|
2335
|
+
const first = g?.models[0];
|
|
2312
2336
|
next.provider = newVal;
|
|
2313
|
-
next.model =
|
|
2337
|
+
next.model = first !== void 0 ? getModelId(first) : "";
|
|
2314
2338
|
} else if (field === "model") {
|
|
2315
2339
|
next.model = newVal;
|
|
2316
2340
|
} else if (field === "reasoningEffort") {
|
|
@@ -2418,7 +2442,8 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
2418
2442
|
(0, import_react.createElement)("span", { style: { display: "flex", alignItems: "center", gap: 8, color: "var(--dsw-alias-label-secondary)" } }, effortLabel, chevronRight)
|
|
2419
2443
|
),
|
|
2420
2444
|
value && (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 2px" } }, `Selected: ${value.provider} / ${value.model}${value.reasoningEffort ? ` (${value.reasoningEffort})` : ""}`),
|
|
2421
|
-
!value && effectiveFallback && (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 2px" } }, `${effectiveFallbackLabel === "Use Global" ? "Using Global" : "Using DSH default"}: ${effectiveFallback.provider} / ${effectiveFallback.model}${effectiveFallback.reasoningEffort ? ` (${effectiveFallback.reasoningEffort})` : ""}`)
|
|
2445
|
+
!value && effectiveFallback && (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 2px" } }, `${effectiveFallbackLabel === "Use Global" ? "Using Global" : "Using DSH default"}: ${effectiveFallback.provider} / ${effectiveFallback.model}${effectiveFallback.reasoningEffort ? ` (${effectiveFallback.reasoningEffort})` : ""}`),
|
|
2446
|
+
warning && (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "4px 4px 2px", color: "var(--dsw-alias-state-error-primary)" } }, warning)
|
|
2422
2447
|
),
|
|
2423
2448
|
pane === "model" && (0, import_react.createElement)(
|
|
2424
2449
|
"div",
|
|
@@ -2437,15 +2462,20 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
2437
2462
|
ms.length === 0 ? (0, import_react.createElement)("p", { style: { ...captionStyle, padding: "2px 10px 2px 28px" } }, "No models") : (0, import_react.createElement)(
|
|
2438
2463
|
"div",
|
|
2439
2464
|
{ style: { marginLeft: 12, borderLeft: "1px solid var(--dsw-alias-border-l2)", paddingLeft: 6, display: "flex", flexDirection: "column", gap: 2 } },
|
|
2440
|
-
ms.map((m) =>
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2465
|
+
ms.map((m) => {
|
|
2466
|
+
const mid = getModelId(m);
|
|
2467
|
+
const mname = getModelName(m);
|
|
2468
|
+
const active = value?.provider === p && value?.model === mid;
|
|
2469
|
+
return (0, import_react.createElement)("button", { key: mid, type: "button", style: { ...rowStyle, paddingLeft: 10, background: active ? "var(--dsw-alias-bg-layer-2)" : "transparent" }, onClick: () => {
|
|
2470
|
+
update("model", mid);
|
|
2471
|
+
if (value?.provider !== p) update("provider", p);
|
|
2472
|
+
else {
|
|
2473
|
+
const next = { provider: p, model: mid, ...selectedEffort ? { reasoningEffort: selectedEffort } : {} };
|
|
2474
|
+
onChange(next);
|
|
2475
|
+
setPane("root");
|
|
2476
|
+
}
|
|
2477
|
+
} }, (0, import_react.createElement)("span", { style: { overflow: "hidden", textOverflow: "ellipsis" } }, mname), check(active));
|
|
2478
|
+
})
|
|
2449
2479
|
)
|
|
2450
2480
|
);
|
|
2451
2481
|
})
|
|
@@ -2455,18 +2485,31 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
2455
2485
|
"div",
|
|
2456
2486
|
null,
|
|
2457
2487
|
(0, import_react.createElement)("button", { type: "button", style: { ...rowStyle, color: "var(--dsw-alias-label-secondary)" }, onClick: () => setPane("root") }, (0, import_react.createElement)("span", null, "\u2190 Back"), (0, import_react.createElement)("span", { style: { fontSize: 12 } }, "Effort")),
|
|
2458
|
-
(0, import_react.createElement)(
|
|
2488
|
+
selectedModelInfo === null ? (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 2px" } }, "Select a model first to configure effort.") : !supportsReasoning ? (0, import_react.createElement)(
|
|
2489
|
+
"div",
|
|
2490
|
+
null,
|
|
2491
|
+
(0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 6px" } }, "This model does not support reasoning effort \u2014 using provider default"),
|
|
2492
|
+
(0, import_react.createElement)(
|
|
2493
|
+
"div",
|
|
2494
|
+
{ style: { marginTop: 4 } },
|
|
2495
|
+
[{ id: "", label: "Default effort" }].map((e) => (0, import_react.createElement)("button", { key: e.id || "default", type: "button", style: { ...rowStyle, background: selectedEffort === e.id ? "var(--dsw-alias-bg-layer-2)" : "transparent" }, onClick: () => {
|
|
2496
|
+
update("reasoningEffort", e.id);
|
|
2497
|
+
setPane("root");
|
|
2498
|
+
} }, (0, import_react.createElement)("span", null, e.label), check(selectedEffort === e.id)))
|
|
2499
|
+
),
|
|
2500
|
+
warning && (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 2px", color: "var(--dsw-alias-state-error-primary)" } }, warning)
|
|
2501
|
+
) : (0, import_react.createElement)(
|
|
2459
2502
|
"div",
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
{
|
|
2464
|
-
{ id: "
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2503
|
+
null,
|
|
2504
|
+
(0, import_react.createElement)(
|
|
2505
|
+
"div",
|
|
2506
|
+
{ style: { marginTop: 4 } },
|
|
2507
|
+
[{ id: "", label: "Default effort" }, ...availableEfforts.map((id) => ({ id, label: id }))].map((e) => (0, import_react.createElement)("button", { key: e.id || "default", type: "button", style: { ...rowStyle, background: selectedEffort === e.id ? "var(--dsw-alias-bg-layer-2)" : "transparent" }, onClick: () => {
|
|
2508
|
+
update("reasoningEffort", e.id);
|
|
2509
|
+
setPane("root");
|
|
2510
|
+
} }, (0, import_react.createElement)("span", null, e.label), check(selectedEffort === e.id)))
|
|
2511
|
+
),
|
|
2512
|
+
warning && (0, import_react.createElement)("p", { style: { ...captionStyle, margin: "8px 4px 2px", color: "var(--dsw-alias-state-error-primary)" } }, warning)
|
|
2470
2513
|
)
|
|
2471
2514
|
)
|
|
2472
2515
|
)
|
|
@@ -2674,7 +2717,7 @@ function PublicAccess({ status, pin, showPin, onRevealPin, onHidePin, onRotatePi
|
|
|
2674
2717
|
(0, import_react.createElement)("p", { style: captionStyle }, "Stays the same across tunnel and DSH restarts; use Rotate when you need a new PIN.")
|
|
2675
2718
|
);
|
|
2676
2719
|
}
|
|
2677
|
-
function MaestroSettingsTab({ rpcCall }) {
|
|
2720
|
+
function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
2678
2721
|
const [status, setStatus] = (0, import_react.useState)(null);
|
|
2679
2722
|
const [proxyStatus, setProxyStatus] = (0, import_react.useState)(null);
|
|
2680
2723
|
const [config, setConfig] = (0, import_react.useState)({ tunnelMode: "quick", projectMappings: [] });
|
|
@@ -2704,6 +2747,14 @@ function MaestroSettingsTab({ rpcCall }) {
|
|
|
2704
2747
|
(0, import_react.useEffect)(() => {
|
|
2705
2748
|
call(MAESTRO_ENDPOINTS.getConfig, {}).then((saved) => setConfig((prev) => ({ ...prev, ...saved }))).catch(() => {
|
|
2706
2749
|
});
|
|
2750
|
+
if (configRpcCall) {
|
|
2751
|
+
configRpcCall("get", { domain: "supervisor" }).then((res) => {
|
|
2752
|
+
if (res?.ok && res.value?.model) {
|
|
2753
|
+
setConfig((prev) => ({ ...prev, supervisorModel: res.value.model }));
|
|
2754
|
+
}
|
|
2755
|
+
}).catch(() => {
|
|
2756
|
+
});
|
|
2757
|
+
}
|
|
2707
2758
|
call(MAESTRO_ENDPOINTS.lanPinStatus, {}).then((value) => {
|
|
2708
2759
|
setLanPinEnabled(value.enabled);
|
|
2709
2760
|
if (value.enabled) setLanPin(value.pin ?? null);
|
|
@@ -2801,6 +2852,13 @@ function MaestroSettingsTab({ rpcCall }) {
|
|
|
2801
2852
|
const saveField = async (field, value) => {
|
|
2802
2853
|
setError(null);
|
|
2803
2854
|
setConfig((prev) => ({ ...prev, [field]: value }));
|
|
2855
|
+
if (field === "supervisorModel" && configRpcCall) {
|
|
2856
|
+
try {
|
|
2857
|
+
const res = await configRpcCall("set", { domain: "supervisor", patch: { model: value } });
|
|
2858
|
+
if (res?.ok) return;
|
|
2859
|
+
} catch (e) {
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2804
2862
|
try {
|
|
2805
2863
|
await call(MAESTRO_ENDPOINTS.saveConfig, { [field]: value });
|
|
2806
2864
|
} catch (err) {
|
|
@@ -2930,6 +2988,20 @@ function MaestroSettingsTab({ rpcCall }) {
|
|
|
2930
2988
|
label: "Global review model"
|
|
2931
2989
|
})
|
|
2932
2990
|
),
|
|
2991
|
+
(0, import_react.createElement)(
|
|
2992
|
+
"div",
|
|
2993
|
+
{ style: sectionStyle },
|
|
2994
|
+
(0, import_react.createElement)("h4", { style: headingStyle }, "Supervisor LLM"),
|
|
2995
|
+
(0, import_react.createElement)("p", { style: captionStyle }, "Model used by the supervisor debug-agent to auto-fix DSH Web crashes. Empty = DSH default (or Review model if set). Uses the same provider catalog as Review."),
|
|
2996
|
+
(0, import_react.createElement)(ReviewModelSelector, {
|
|
2997
|
+
value: config.supervisorModel ?? null,
|
|
2998
|
+
catalog,
|
|
2999
|
+
fallbackValue: catalog?.current ?? null,
|
|
3000
|
+
fallbackLabel: "Use DSH default",
|
|
3001
|
+
onChange: (v) => saveField("supervisorModel", v),
|
|
3002
|
+
label: "Supervisor model"
|
|
3003
|
+
})
|
|
3004
|
+
),
|
|
2933
3005
|
(0, import_react.createElement)(
|
|
2934
3006
|
"div",
|
|
2935
3007
|
{ style: sectionStyle },
|
|
@@ -3012,12 +3084,17 @@ function apply(ctx) {
|
|
|
3012
3084
|
if (!connection?.rpc?.call) return Promise.reject(new Error("RPC not available"));
|
|
3013
3085
|
return connection.rpc.call(MAESTRO_RPC_CHANNEL, endpoint, payload, signal);
|
|
3014
3086
|
};
|
|
3087
|
+
const configRpcCall = (endpoint, payload, signal) => {
|
|
3088
|
+
const connection = ctx.get?.("connection");
|
|
3089
|
+
if (!connection?.rpc?.call) return Promise.reject(new Error("RPC not available"));
|
|
3090
|
+
return connection.rpc.call("/dsh-maestro-config", endpoint, payload, signal);
|
|
3091
|
+
};
|
|
3015
3092
|
ctx.effect(() => registerSettingsNavIcon(() => "Maestro"), "maestro: settings nav icon");
|
|
3016
3093
|
ctx.effect(installNavIconStyle, "maestro: settings nav css");
|
|
3017
3094
|
slots.inject(
|
|
3018
3095
|
"settings.section",
|
|
3019
3096
|
() => slots.register(
|
|
3020
|
-
{ name: "settings.section", id: "maestro", order: 25, label: () => "Maestro", inject: () => ({ rpcCall }) },
|
|
3097
|
+
{ name: "settings.section", id: "maestro", order: 25, label: () => "Maestro", inject: () => ({ rpcCall, configRpcCall }) },
|
|
3021
3098
|
MaestroSettingsTab
|
|
3022
3099
|
)
|
|
3023
3100
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAuCA,UAAU,SAAS;IACjB,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,MAAM,CAAC,EAAE,EAAE,MAAM,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACtD;AAaD,wBAAgB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAuCA,UAAU,SAAS;IACjB,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,MAAM,CAAC,EAAE,EAAE,MAAM,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACtD;AAaD,wBAAgB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CA+B1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maestro-card.d.ts","sourceRoot":"","sources":["../../../src/client/maestro-card.jsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"maestro-card.d.ts","sourceRoot":"","sources":["../../../src/client/maestro-card.jsx"],"names":[],"mappings":"AAkeA;;;;;;;;gBAoRC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ddtcorex/dsh-maestro-config",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"private": false,
|
|
4
5
|
"description": "Maestro Config — shared settings service for the dsh-maestro-* suite over the single namespaced store (~/.dsh/maestro/settings.json)",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./lib/index.js",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@ddtcorex/dsh-maestro-config-lib": "^0.1.
|
|
41
|
+
"@ddtcorex/dsh-maestro-config-lib": "^0.1.1"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@deepseek-ai/cordis": "^4.0.1",
|
package/src/client/index.tsx
CHANGED
|
@@ -65,6 +65,14 @@ export function apply(ctx: ClientCtx): void {
|
|
|
65
65
|
if (!connection?.rpc?.call) return Promise.reject(new Error('RPC not available'))
|
|
66
66
|
return connection.rpc.call(MAESTRO_RPC_CHANNEL, endpoint, payload, signal)
|
|
67
67
|
}
|
|
68
|
+
// Generic config RPC for supervisor (independent of review — works when review not installed)
|
|
69
|
+
const configRpcCall: RpcCall = (endpoint, payload, signal) => {
|
|
70
|
+
const connection = ctx.get?.('connection') as
|
|
71
|
+
| { rpc: { call(ch: string, ep: string, p?: unknown, s?: AbortSignal): Promise<unknown> } }
|
|
72
|
+
| undefined
|
|
73
|
+
if (!connection?.rpc?.call) return Promise.reject(new Error('RPC not available'))
|
|
74
|
+
return connection.rpc.call('/dsh-maestro-config', endpoint, payload, signal)
|
|
75
|
+
}
|
|
68
76
|
|
|
69
77
|
// Reversible effects: nav-row marker observer + owned style tag.
|
|
70
78
|
ctx.effect(() => registerSettingsNavIcon(() => 'Maestro'), 'maestro: settings nav icon')
|
|
@@ -72,8 +80,8 @@ export function apply(ctx: ClientCtx): void {
|
|
|
72
80
|
|
|
73
81
|
slots.inject('settings.section', () =>
|
|
74
82
|
slots.register(
|
|
75
|
-
{ name: 'settings.section', id: 'maestro', order: 25, label: () => 'Maestro', inject: () => ({ rpcCall }) },
|
|
76
|
-
MaestroSettingsTab,
|
|
83
|
+
{ name: 'settings.section', id: 'maestro', order: 25, label: () => 'Maestro', inject: () => ({ rpcCall, configRpcCall }) },
|
|
84
|
+
MaestroSettingsTab as unknown as (props: { rpcCall: RpcCall }) => unknown,
|
|
77
85
|
),
|
|
78
86
|
)
|
|
79
87
|
}
|
|
@@ -147,10 +147,35 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
147
147
|
document.addEventListener('keydown', onKey)
|
|
148
148
|
return () => { document.removeEventListener('mousedown', onDown); document.removeEventListener('keydown', onKey) }
|
|
149
149
|
}, [open])
|
|
150
|
+
const getModelId = (m) => typeof m === 'string' ? m : m.id
|
|
151
|
+
const getModelName = (m) => typeof m === 'string' ? m : (m.name ?? m.id)
|
|
152
|
+
const selectedModelInfo = (() => {
|
|
153
|
+
if (!selectedProvider || !value?.model) return null
|
|
154
|
+
const raw = (providerGroup?.models ?? []).find(mm => getModelId(mm) === value.model)
|
|
155
|
+
if (raw === undefined) return null
|
|
156
|
+
if (typeof raw === 'string') return { id: raw, supportsReasoning: false, reasoningEfforts: [] }
|
|
157
|
+
return raw
|
|
158
|
+
})()
|
|
159
|
+
const supportsReasoning = (() => {
|
|
160
|
+
if (!selectedModelInfo) return false
|
|
161
|
+
if (typeof selectedModelInfo.supportsReasoning === 'boolean') return selectedModelInfo.supportsReasoning
|
|
162
|
+
const efforts = selectedModelInfo.reasoningEfforts ?? selectedModelInfo.reasoning?.efforts?.map(e => e.id) ?? []
|
|
163
|
+
return efforts.filter(e => e !== 'off').length > 0
|
|
164
|
+
})()
|
|
165
|
+
const availableEfforts = (() => {
|
|
166
|
+
if (!supportsReasoning) return []
|
|
167
|
+
const efforts = selectedModelInfo?.reasoningEfforts ?? selectedModelInfo?.reasoning?.efforts?.map(e => e.id) ?? []
|
|
168
|
+
const filtered = efforts.filter(e => e !== 'off' && e !== '')
|
|
169
|
+
if (filtered.length > 0) return filtered
|
|
170
|
+
return ['low', 'medium', 'high']
|
|
171
|
+
})()
|
|
172
|
+
const warning = selectedEffort !== '' && !supportsReasoning && selectedModelInfo !== null
|
|
173
|
+
? `⚠️ This model does not support reasoning effort "${selectedEffort}" — reviews will fail. Clear effort or choose a reasoning-capable model.`
|
|
174
|
+
: null
|
|
150
175
|
const update = (field, newVal) => {
|
|
151
176
|
if (newVal === '' && field === 'provider') { onChange(null); setOpen(false); setPane('root'); return }
|
|
152
177
|
const next = { provider: value?.provider ?? '', model: value?.model ?? '', ...(value?.reasoningEffort ? { reasoningEffort: value.reasoningEffort } : {}) }
|
|
153
|
-
if (field === 'provider') { const g = groups.find(x => x.provider === newVal); next.provider = newVal; next.model =
|
|
178
|
+
if (field === 'provider') { const g = groups.find(x => x.provider === newVal); const first = g?.models[0]; next.provider = newVal; next.model = first !== undefined ? getModelId(first) : '' }
|
|
154
179
|
else if (field === 'model') { next.model = newVal }
|
|
155
180
|
else if (field === 'reasoningEffort') { if (newVal === '') delete next.reasoningEffort; else next.reasoningEffort = newVal }
|
|
156
181
|
if (!next.provider || !next.model) { onChange(null) } else { onChange(next) }
|
|
@@ -235,6 +260,7 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
235
260
|
),
|
|
236
261
|
value && h('p', { style: { ...captionStyle, margin: '8px 4px 2px' } }, `Selected: ${value.provider} / ${value.model}${value.reasoningEffort ? ` (${value.reasoningEffort})` : ''}`),
|
|
237
262
|
!value && effectiveFallback && h('p', { style: { ...captionStyle, margin: '8px 4px 2px' } }, `${effectiveFallbackLabel === 'Use Global' ? 'Using Global' : 'Using DSH default'}: ${effectiveFallback.provider} / ${effectiveFallback.model}${effectiveFallback.reasoningEffort ? ` (${effectiveFallback.reasoningEffort})` : ''}`),
|
|
263
|
+
warning && h('p', { style: { ...captionStyle, margin: '4px 4px 2px', color: 'var(--dsw-alias-state-error-primary)' } }, warning),
|
|
238
264
|
),
|
|
239
265
|
pane === 'model' && h('div', null,
|
|
240
266
|
h('button', { type: 'button', style: { ...rowStyle, color: 'var(--dsw-alias-label-secondary)' }, onClick: () => setPane('root') }, h('span', null, '← Back'), h('span', { style: { fontSize: 12 } }, 'Model')),
|
|
@@ -247,20 +273,31 @@ function ReviewModelSelector({ value, catalog, fallbackValue, fallbackLabel, onC
|
|
|
247
273
|
h('div', { style: { fontSize: 11, fontWeight: 600, color: 'var(--dsw-alias-label-secondary)', padding: '6px 10px 2px', textTransform: 'uppercase', letterSpacing: 0.4, display: 'flex', alignItems: 'center', gap: 6 } }, h('span', { style: { width: 6, height: 6, borderRadius: 3, background: 'var(--dsw-alias-border-l2)', flex: 'none' } }), g?.name ?? p),
|
|
248
274
|
ms.length === 0 ? h('p', { style: { ...captionStyle, padding: '2px 10px 2px 28px' } }, 'No models') :
|
|
249
275
|
h('div', { style: { marginLeft: 12, borderLeft: '1px solid var(--dsw-alias-border-l2)', paddingLeft: 6, display: 'flex', flexDirection: 'column', gap: 2 } },
|
|
250
|
-
ms.map(m =>
|
|
276
|
+
ms.map(m => {
|
|
277
|
+
const mid = getModelId(m)
|
|
278
|
+
const mname = getModelName(m)
|
|
279
|
+
const active = value?.provider === p && value?.model === mid
|
|
280
|
+
return h('button', { key: mid, type: 'button', style: { ...rowStyle, paddingLeft: 10, background: active ? 'var(--dsw-alias-bg-layer-2)' : 'transparent' }, onClick: () => { update('model', mid); if (value?.provider !== p) update('provider', p); else { const next = { provider: p, model: mid, ...(selectedEffort ? { reasoningEffort: selectedEffort } : {}) }; onChange(next); setPane('root') } } }, h('span', { style: { overflow: 'hidden', textOverflow: 'ellipsis' } }, mname), check(active))
|
|
281
|
+
})),
|
|
251
282
|
)
|
|
252
283
|
}),
|
|
253
284
|
),
|
|
254
285
|
),
|
|
255
286
|
pane === 'effort' && h('div', null,
|
|
256
287
|
h('button', { type: 'button', style: { ...rowStyle, color: 'var(--dsw-alias-label-secondary)' }, onClick: () => setPane('root') }, h('span', null, '← Back'), h('span', { style: { fontSize: 12 } }, 'Effort')),
|
|
257
|
-
h('
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
{ id: '
|
|
262
|
-
|
|
263
|
-
|
|
288
|
+
selectedModelInfo === null ? h('p', { style: { ...captionStyle, margin: '8px 4px 2px' } }, 'Select a model first to configure effort.') :
|
|
289
|
+
!supportsReasoning ? h('div', null,
|
|
290
|
+
h('p', { style: { ...captionStyle, margin: '8px 4px 6px' } }, 'This model does not support reasoning effort — using provider default'),
|
|
291
|
+
h('div', { style: { marginTop: 4 } },
|
|
292
|
+
[{ id: '', label: 'Default effort' }].map(e => h('button', { key: e.id || 'default', type: 'button', style: { ...rowStyle, background: selectedEffort === e.id ? 'var(--dsw-alias-bg-layer-2)' : 'transparent' }, onClick: () => { update('reasoningEffort', e.id); setPane('root') } }, h('span', null, e.label), check(selectedEffort === e.id))),
|
|
293
|
+
),
|
|
294
|
+
warning && h('p', { style: { ...captionStyle, margin: '8px 4px 2px', color: 'var(--dsw-alias-state-error-primary)' } }, warning),
|
|
295
|
+
) :
|
|
296
|
+
h('div', null,
|
|
297
|
+
h('div', { style: { marginTop: 4 } },
|
|
298
|
+
[{ id: '', label: 'Default effort' }, ...availableEfforts.map(id => ({ id, label: id }))].map(e => h('button', { key: e.id || 'default', type: 'button', style: { ...rowStyle, background: selectedEffort === e.id ? 'var(--dsw-alias-bg-layer-2)' : 'transparent' }, onClick: () => { update('reasoningEffort', e.id); setPane('root') } }, h('span', null, e.label), check(selectedEffort === e.id))),
|
|
299
|
+
),
|
|
300
|
+
warning && h('p', { style: { ...captionStyle, margin: '8px 4px 2px', color: 'var(--dsw-alias-state-error-primary)' } }, warning),
|
|
264
301
|
),
|
|
265
302
|
),
|
|
266
303
|
),
|
|
@@ -443,7 +480,7 @@ function PublicAccess({ status, pin, showPin, onRevealPin, onHidePin, onRotatePi
|
|
|
443
480
|
)
|
|
444
481
|
}
|
|
445
482
|
|
|
446
|
-
export function MaestroSettingsTab({ rpcCall }) {
|
|
483
|
+
export function MaestroSettingsTab({ rpcCall, configRpcCall }) {
|
|
447
484
|
const [status, setStatus] = useState(null)
|
|
448
485
|
const [proxyStatus, setProxyStatus] = useState(null)
|
|
449
486
|
const [config, setConfig] = useState({ tunnelMode: 'quick', projectMappings: [] })
|
|
@@ -474,6 +511,16 @@ export function MaestroSettingsTab({ rpcCall }) {
|
|
|
474
511
|
call(MAESTRO_ENDPOINTS.getConfig, {})
|
|
475
512
|
.then(saved => setConfig(prev => ({ ...prev, ...saved })))
|
|
476
513
|
.catch(() => { /* first run, no config saved yet — keep defaults */ })
|
|
514
|
+
// Supervisor model may be stored via generic config service when review not installed — try fallback
|
|
515
|
+
if (configRpcCall) {
|
|
516
|
+
configRpcCall('get', { domain: 'supervisor' })
|
|
517
|
+
.then(res => {
|
|
518
|
+
if (res?.ok && res.value?.model) {
|
|
519
|
+
setConfig(prev => ({ ...prev, supervisorModel: res.value.model }))
|
|
520
|
+
}
|
|
521
|
+
})
|
|
522
|
+
.catch(() => { /* supervisor domain not yet set or config service unavailable */ })
|
|
523
|
+
}
|
|
477
524
|
call(MAESTRO_ENDPOINTS.lanPinStatus, {})
|
|
478
525
|
.then(value => { setLanPinEnabled(value.enabled); if (value.enabled) setLanPin(value.pin ?? null) })
|
|
479
526
|
.catch(() => { /* host without the LAN PIN endpoints — keep the row hidden */ })
|
|
@@ -559,6 +606,16 @@ export function MaestroSettingsTab({ rpcCall }) {
|
|
|
559
606
|
const saveField = async (field, value) => {
|
|
560
607
|
setError(null)
|
|
561
608
|
setConfig(prev => ({ ...prev, [field]: value }))
|
|
609
|
+
// Supervisor model can be saved via generic config service when review not installed (independent install)
|
|
610
|
+
if (field === 'supervisorModel' && configRpcCall) {
|
|
611
|
+
try {
|
|
612
|
+
const res = await configRpcCall('set', { domain: 'supervisor', patch: { model: value } })
|
|
613
|
+
if (res?.ok) return
|
|
614
|
+
// Fall through to review RPC if generic set fails
|
|
615
|
+
} catch (e) {
|
|
616
|
+
// Fall through to review RPC
|
|
617
|
+
}
|
|
618
|
+
}
|
|
562
619
|
try {
|
|
563
620
|
await call(MAESTRO_ENDPOINTS.saveConfig, { [field]: value })
|
|
564
621
|
} catch (err) {
|
|
@@ -679,6 +736,19 @@ export function MaestroSettingsTab({ rpcCall }) {
|
|
|
679
736
|
}),
|
|
680
737
|
),
|
|
681
738
|
|
|
739
|
+
h('div', { style: sectionStyle },
|
|
740
|
+
h('h4', { style: headingStyle }, 'Supervisor LLM'),
|
|
741
|
+
h('p', { style: captionStyle }, 'Model used by the supervisor debug-agent to auto-fix DSH Web crashes. Empty = DSH default (or Review model if set). Uses the same provider catalog as Review.'),
|
|
742
|
+
h(ReviewModelSelector, {
|
|
743
|
+
value: config.supervisorModel ?? null,
|
|
744
|
+
catalog,
|
|
745
|
+
fallbackValue: catalog?.current ?? null,
|
|
746
|
+
fallbackLabel: 'Use DSH default',
|
|
747
|
+
onChange: v => saveField('supervisorModel', v),
|
|
748
|
+
label: 'Supervisor model',
|
|
749
|
+
}),
|
|
750
|
+
),
|
|
751
|
+
|
|
682
752
|
h('div', { style: sectionStyle },
|
|
683
753
|
h('h4', { style: headingStyle }, 'Projects'),
|
|
684
754
|
h(ProjectMappingsEditor, { mappings: config.projectMappings ?? [], onChange: mappings => saveField('projectMappings', mappings), catalog, globalReviewModel: config.reviewModel ?? null }),
|