dsh-model-switch 0.4.19 → 0.4.21
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/CHANGELOG.md +212 -194
- package/IMPLEMENTATION_PLAN.md +40 -40
- package/LICENSE +21 -21
- package/PRODUCT.md +33 -33
- package/README.md +214 -200
- package/README.zh.md +212 -198
- package/cordis.patch.yml +515 -18
- package/lib/auto-review.js +120 -0
- package/lib/client.js +467 -22
- package/lib/compaction.js +205 -0
- package/lib/index.js +17 -2
- package/lib/types/auto-review.d.ts +68 -0
- package/lib/types/client/ModelSwitchSettings.d.ts +3 -1
- package/lib/types/client/derived-settings-scope.d.ts +4 -4
- package/lib/types/client/locales.d.ts +8 -0
- package/lib/types/client/picker/PlanReviewCard.d.ts +3 -0
- package/lib/types/client/picker/locales.d.ts +2 -0
- package/lib/types/client/picker/plan-preview.d.ts +49 -0
- package/lib/types/client/remote-settings-scope.d.ts +45 -45
- package/lib/types/client-contract.d.ts +18 -0
- package/lib/types/compaction.d.ts +56 -0
- package/lib/types/host-runtime.d.ts +12 -0
- package/lib/types/host-settings.d.ts +20 -0
- package/lib/types/picker/plan-goal.d.ts +29 -3
- package/package.json +360 -347
package/lib/client.js
CHANGED
|
@@ -33,6 +33,16 @@ window.__ModuleLoader__.load({
|
|
|
33
33
|
provider: "imageProvider",
|
|
34
34
|
model: "imageModel"
|
|
35
35
|
});
|
|
36
|
+
/** Auto-preset reviewer route; both unset means the reviewer follows the session model. */
|
|
37
|
+
const AUTO_REVIEW_SETTINGS_FIELDS = Object.freeze({
|
|
38
|
+
provider: "autoReviewProvider",
|
|
39
|
+
model: "autoReviewModel"
|
|
40
|
+
});
|
|
41
|
+
/** Compaction summarization route for `/compact` and automatic compaction; both unset means the official default (the conversation target). */
|
|
42
|
+
const COMPACTION_SETTINGS_FIELDS = Object.freeze({
|
|
43
|
+
provider: "compactProvider",
|
|
44
|
+
model: "compactModel"
|
|
45
|
+
});
|
|
36
46
|
function deriveSubagentSettings(settings) {
|
|
37
47
|
return {
|
|
38
48
|
mode: settings.subagentMode,
|
|
@@ -53,6 +63,22 @@ window.__ModuleLoader__.load({
|
|
|
53
63
|
...settings.imageModel === void 0 ? {} : { model: settings.imageModel }
|
|
54
64
|
};
|
|
55
65
|
}
|
|
66
|
+
function deriveAutoReviewSettings(settings) {
|
|
67
|
+
return {
|
|
68
|
+
...settings.autoReviewProvider === void 0 ? {} : { provider: settings.autoReviewProvider },
|
|
69
|
+
...settings.autoReviewModel === void 0 ? {} : { model: settings.autoReviewModel }
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function deriveCompactionSettings(settings) {
|
|
73
|
+
return {
|
|
74
|
+
...settings.compactProvider === void 0 ? {} : { provider: settings.compactProvider },
|
|
75
|
+
...settings.compactModel === void 0 ? {} : { model: settings.compactModel }
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Whether both fields of a model route form a complete pair; an incomplete pair stays off. */
|
|
79
|
+
function routePairConfigured(route) {
|
|
80
|
+
return route !== void 0 && (route.provider ?? "").trim() !== "" && (route.model ?? "").trim() !== "";
|
|
81
|
+
}
|
|
56
82
|
//#endregion
|
|
57
83
|
//#region src/client/derived-config-form.ts
|
|
58
84
|
function deriveConfigForm(source, project, fields) {
|
|
@@ -603,6 +629,19 @@ window.__ModuleLoader__.load({
|
|
|
603
629
|
return values.filter((value) => value !== void 0 && value !== "").join(" · ");
|
|
604
630
|
}
|
|
605
631
|
function RouteIcon({ kind }) {
|
|
632
|
+
if (kind === "compaction") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
633
|
+
width: "18",
|
|
634
|
+
height: "18",
|
|
635
|
+
viewBox: "0 0 18 18",
|
|
636
|
+
fill: "none",
|
|
637
|
+
"aria-hidden": "true",
|
|
638
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
639
|
+
d: "M5 3.5 9 7.5l4-4M5 14.5 9 10.5l4 4",
|
|
640
|
+
stroke: "currentColor",
|
|
641
|
+
strokeLinecap: "round",
|
|
642
|
+
strokeLinejoin: "round"
|
|
643
|
+
})
|
|
644
|
+
});
|
|
606
645
|
if (kind === "main") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
607
646
|
width: "18",
|
|
608
647
|
height: "18",
|
|
@@ -686,6 +725,23 @@ window.__ModuleLoader__.load({
|
|
|
686
725
|
})
|
|
687
726
|
]
|
|
688
727
|
});
|
|
728
|
+
if (kind === "autoReview") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
729
|
+
width: "18",
|
|
730
|
+
height: "18",
|
|
731
|
+
viewBox: "0 0 18 18",
|
|
732
|
+
fill: "none",
|
|
733
|
+
"aria-hidden": "true",
|
|
734
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
735
|
+
d: "M9 2.5 14.5 4.8v4.1c0 3.1-2.3 5.7-5.5 6.6-3.2-.9-5.5-3.5-5.5-6.6V4.8L9 2.5Z",
|
|
736
|
+
stroke: "currentColor",
|
|
737
|
+
strokeLinejoin: "round"
|
|
738
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
739
|
+
d: "m6.6 8.9 1.7 1.7 3.2-3.4",
|
|
740
|
+
stroke: "currentColor",
|
|
741
|
+
strokeLinecap: "round",
|
|
742
|
+
strokeLinejoin: "round"
|
|
743
|
+
})]
|
|
744
|
+
});
|
|
689
745
|
return null;
|
|
690
746
|
}
|
|
691
747
|
function RouteCard({ title, summary, hint, icon, open, onToggle, disabled = false, badge, badgeWarn = false, trailing, expandable = true, children }) {
|
|
@@ -857,11 +913,15 @@ window.__ModuleLoader__.load({
|
|
|
857
913
|
const { main, subagent, draft, groups } = controller;
|
|
858
914
|
const search = props.useSearchSettings((value) => value);
|
|
859
915
|
const image = props.useImageSettings((value) => value);
|
|
916
|
+
const autoReview = props.useAutoReviewSettings((value) => value);
|
|
917
|
+
const compaction = props.useCompactionSettings((value) => value);
|
|
860
918
|
const switchSettings = props.useSwitchSettings((value) => value);
|
|
861
919
|
const [open, setOpen] = (0, react.useState)();
|
|
862
920
|
const [subagentDraft, setSubagentDraft, resetSubagent] = useDraft(subagent);
|
|
863
921
|
const [searchDraft, setSearchDraft, resetSearch] = useDraft(search);
|
|
864
922
|
const [imageDraft, setImageDraft, resetImage] = useDraft(image);
|
|
923
|
+
const [autoReviewDraft, setAutoReviewDraft, resetAutoReview] = useDraft(autoReview);
|
|
924
|
+
const [compactionDraft, setCompactionDraft, resetCompaction] = useDraft(compaction);
|
|
865
925
|
const [busy, setBusy] = (0, react.useState)();
|
|
866
926
|
const [message, setMessage] = (0, react.useState)();
|
|
867
927
|
const [compactBusy, setCompactBusy] = (0, react.useState)(false);
|
|
@@ -956,11 +1016,17 @@ window.__ModuleLoader__.load({
|
|
|
956
1016
|
const searchChoices = capabilityChoices(searchGroups, searchDraft, void 0, "search");
|
|
957
1017
|
const searchAvailable = searchLive?.searchProviderAdapters.available ?? false;
|
|
958
1018
|
const imageChoices = capabilityChoices(groups, imageDraft, props.capabilities.imageProviderAdapters.providers ?? [], "image");
|
|
1019
|
+
const autoReviewChoices = deriveRouteChoices(groups, autoReviewDraft);
|
|
1020
|
+
const autoReviewOn = routePairConfigured(autoReview.value);
|
|
1021
|
+
const compactionChoices = deriveRouteChoices(groups, compactionDraft);
|
|
1022
|
+
const compactionOn = routePairConfigured(compaction.value);
|
|
959
1023
|
const synced = [
|
|
960
1024
|
main,
|
|
961
1025
|
subagent,
|
|
962
1026
|
search,
|
|
963
|
-
image
|
|
1027
|
+
image,
|
|
1028
|
+
autoReview,
|
|
1029
|
+
compaction
|
|
964
1030
|
].every((snapshot) => snapshot.status === "ready");
|
|
965
1031
|
const run = async (route, operation) => {
|
|
966
1032
|
if (busy !== void 0) return;
|
|
@@ -1019,12 +1085,103 @@ window.__ModuleLoader__.load({
|
|
|
1019
1085
|
if (current.value?.model !== next.model) await props.setCapability(route, "model", next.model);
|
|
1020
1086
|
});
|
|
1021
1087
|
};
|
|
1088
|
+
const saveAutoReview = () => {
|
|
1089
|
+
if (autoReviewDraft === void 0) return;
|
|
1090
|
+
run("autoReview", async () => {
|
|
1091
|
+
if (autoReview.value?.provider !== autoReviewDraft.provider) await props.setCapability("autoReview", "provider", autoReviewDraft.provider);
|
|
1092
|
+
if (autoReview.value?.model !== autoReviewDraft.model) await props.setCapability("autoReview", "model", autoReviewDraft.model);
|
|
1093
|
+
});
|
|
1094
|
+
};
|
|
1095
|
+
const saveCompaction = () => {
|
|
1096
|
+
if (compactionDraft === void 0) return;
|
|
1097
|
+
run("compaction", async () => {
|
|
1098
|
+
if (compaction.value?.provider !== compactionDraft.provider) await props.setCapability("compaction", "provider", compactionDraft.provider);
|
|
1099
|
+
if (compaction.value?.model !== compactionDraft.model) await props.setCapability("compaction", "model", compactionDraft.model);
|
|
1100
|
+
});
|
|
1101
|
+
};
|
|
1102
|
+
/**
|
|
1103
|
+
* The reviewer switch: Off unsets both stored fields (follow the session
|
|
1104
|
+
* model); On seeds the route from Main so the pin takes effect immediately
|
|
1105
|
+
* and stays editable below. A failed write reports, never flips silently.
|
|
1106
|
+
*/
|
|
1107
|
+
const persistAutoReviewEnabled = (enabled) => {
|
|
1108
|
+
if (busy === "autoReview" || !autoReview.writable || autoReview.value === void 0) return;
|
|
1109
|
+
if (!enabled) {
|
|
1110
|
+
setOpen((current) => current === "autoReview" ? void 0 : current);
|
|
1111
|
+
run("autoReview", async () => {
|
|
1112
|
+
if (autoReview.value?.provider !== void 0) await props.setCapability("autoReview", "provider", void 0);
|
|
1113
|
+
if (autoReview.value?.model !== void 0) await props.setCapability("autoReview", "model", void 0);
|
|
1114
|
+
});
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
const seed = draft;
|
|
1118
|
+
if (seed === void 0 || seed.provider.trim() === "" || seed.model.trim() === "") return;
|
|
1119
|
+
setBusy("autoReview");
|
|
1120
|
+
setMessage(void 0);
|
|
1121
|
+
(async () => {
|
|
1122
|
+
if (autoReview.value?.provider !== seed.provider) await props.setCapability("autoReview", "provider", seed.provider);
|
|
1123
|
+
if (autoReview.value?.model !== seed.model) await props.setCapability("autoReview", "model", seed.model);
|
|
1124
|
+
})().then(() => {
|
|
1125
|
+
setAutoReviewDraft({
|
|
1126
|
+
provider: seed.provider,
|
|
1127
|
+
model: seed.model
|
|
1128
|
+
});
|
|
1129
|
+
setBusy(void 0);
|
|
1130
|
+
setOpen("autoReview");
|
|
1131
|
+
}, (error) => {
|
|
1132
|
+
setBusy(void 0);
|
|
1133
|
+
setMessage({
|
|
1134
|
+
route: "autoReview",
|
|
1135
|
+
text: error instanceof Error ? error.message : props.t("requestFailed")
|
|
1136
|
+
});
|
|
1137
|
+
});
|
|
1138
|
+
};
|
|
1139
|
+
/**
|
|
1140
|
+
* The compaction switch: Off unsets both stored fields (official default =
|
|
1141
|
+
* the conversation target); On seeds the route from Main so the pin takes
|
|
1142
|
+
* effect immediately and stays editable below. A failed write reports,
|
|
1143
|
+
* never flips silently.
|
|
1144
|
+
*/
|
|
1145
|
+
const persistCompactionEnabled = (enabled) => {
|
|
1146
|
+
if (busy === "compaction" || !compaction.writable || compaction.value === void 0) return;
|
|
1147
|
+
if (!enabled) {
|
|
1148
|
+
setOpen((current) => current === "compaction" ? void 0 : current);
|
|
1149
|
+
run("compaction", async () => {
|
|
1150
|
+
if (compaction.value?.provider !== void 0) await props.setCapability("compaction", "provider", void 0);
|
|
1151
|
+
if (compaction.value?.model !== void 0) await props.setCapability("compaction", "model", void 0);
|
|
1152
|
+
});
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
const seed = draft;
|
|
1156
|
+
if (seed === void 0 || seed.provider.trim() === "" || seed.model.trim() === "") return;
|
|
1157
|
+
setBusy("compaction");
|
|
1158
|
+
setMessage(void 0);
|
|
1159
|
+
(async () => {
|
|
1160
|
+
if (compaction.value?.provider !== seed.provider) await props.setCapability("compaction", "provider", seed.provider);
|
|
1161
|
+
if (compaction.value?.model !== seed.model) await props.setCapability("compaction", "model", seed.model);
|
|
1162
|
+
})().then(() => {
|
|
1163
|
+
setCompactionDraft({
|
|
1164
|
+
provider: seed.provider,
|
|
1165
|
+
model: seed.model
|
|
1166
|
+
});
|
|
1167
|
+
setBusy(void 0);
|
|
1168
|
+
setOpen("compaction");
|
|
1169
|
+
}, (error) => {
|
|
1170
|
+
setBusy(void 0);
|
|
1171
|
+
setMessage({
|
|
1172
|
+
route: "compaction",
|
|
1173
|
+
text: error instanceof Error ? error.message : props.t("requestFailed")
|
|
1174
|
+
});
|
|
1175
|
+
});
|
|
1176
|
+
};
|
|
1022
1177
|
const mainSummary = draft === void 0 ? props.t("loading") : compact(routeName(groups, draft), mainEffectiveEffort);
|
|
1023
1178
|
const subagentRole = subagentDraft?.mode === "fixed" && subagentDraft.provider !== void 0 && subagentDraft.provider !== "" ? props.providerRoleOf?.(subagentDraft.provider) : void 0;
|
|
1024
1179
|
const subagentOn = subagentDraft?.mode === "fixed";
|
|
1025
1180
|
const subagentSummary = subagentDraft === void 0 ? props.t("loading") : subagentOn ? compact(routeName(groups, subagentRoute), isAgentRole(subagentRole) ? props.t("agentBadge") : void 0, defaultEffort === void 0 ? props.t("providerDefaultShort") : compact(props.t("providerDefaultShort"), defaultEffort)) : props.t("subagentOff");
|
|
1026
1181
|
const subagentDisabled = subagent.status !== "ready" || !subagent.writable || subagentDraft === void 0 || busy === "subagent" || !subagentOn || (subagentDraft.provider ?? "").trim() === "" || (subagentDraft.model ?? "").trim() === "";
|
|
1027
1182
|
const capabilityDisabled = (route, snapshot, next) => snapshot.status !== "ready" || !snapshot.writable || next === void 0 || busy === route || (next.provider ?? "").trim() === "" || (next.model ?? "").trim() === "";
|
|
1183
|
+
const autoReviewDisabled = autoReview.status !== "ready" || !autoReview.writable || autoReviewDraft === void 0 || busy === "autoReview" || !autoReviewOn || (autoReviewDraft.provider ?? "").trim() === "" || (autoReviewDraft.model ?? "").trim() === "";
|
|
1184
|
+
const compactionDisabled = compaction.status !== "ready" || !compaction.writable || compactionDraft === void 0 || busy === "compaction" || !compactionOn || (compactionDraft.provider ?? "").trim() === "" || (compactionDraft.model ?? "").trim() === "";
|
|
1028
1185
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
|
|
1029
1186
|
className: ModelSwitchSettings_module_css_default.section,
|
|
1030
1187
|
children: [
|
|
@@ -1394,6 +1551,134 @@ window.__ModuleLoader__.load({
|
|
|
1394
1551
|
disabled: true,
|
|
1395
1552
|
badge: props.t("unavailable"),
|
|
1396
1553
|
badgeWarn: true
|
|
1554
|
+
}),
|
|
1555
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteCard, {
|
|
1556
|
+
title: props.t("autoReview"),
|
|
1557
|
+
summary: autoReviewDraft === void 0 ? props.t("loading") : autoReviewOn ? routeName(groups, autoReviewDraft) : props.t("autoReviewFollow"),
|
|
1558
|
+
hint: props.t("autoReviewHelp"),
|
|
1559
|
+
icon: "autoReview",
|
|
1560
|
+
open: open === "autoReview" && autoReviewOn,
|
|
1561
|
+
onToggle: () => {
|
|
1562
|
+
if (autoReviewOn) toggle("autoReview");
|
|
1563
|
+
},
|
|
1564
|
+
expandable: autoReviewOn,
|
|
1565
|
+
trailing: autoReviewDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1566
|
+
checked: autoReviewOn,
|
|
1567
|
+
disabled: busy === "autoReview" || !autoReview.writable,
|
|
1568
|
+
label: props.t("autoReview"),
|
|
1569
|
+
onChange: persistAutoReviewEnabled
|
|
1570
|
+
}),
|
|
1571
|
+
children: autoReviewDraft === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1572
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
1573
|
+
children: props.t("loading")
|
|
1574
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1575
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1576
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
1577
|
+
children: props.t("autoReviewRouteHelp")
|
|
1578
|
+
}),
|
|
1579
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1580
|
+
className: ModelSwitchSettings_module_css_default.formGrid,
|
|
1581
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1582
|
+
label: props.t("provider"),
|
|
1583
|
+
value: autoReviewDraft.provider ?? "",
|
|
1584
|
+
disabled: busy === "autoReview" || !autoReview.writable,
|
|
1585
|
+
choices: autoReviewChoices.providers,
|
|
1586
|
+
onChange: (provider) => {
|
|
1587
|
+
const first = groups.find((group) => group.id === provider)?.models[0];
|
|
1588
|
+
setAutoReviewDraft({
|
|
1589
|
+
provider,
|
|
1590
|
+
...first === void 0 ? {} : { model: first.id }
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1594
|
+
label: props.t("model"),
|
|
1595
|
+
value: autoReviewDraft.model ?? "",
|
|
1596
|
+
disabled: busy === "autoReview" || !autoReview.writable,
|
|
1597
|
+
choices: autoReviewChoices.models,
|
|
1598
|
+
onChange: (model) => {
|
|
1599
|
+
setAutoReviewDraft({
|
|
1600
|
+
...autoReviewDraft,
|
|
1601
|
+
model
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
})]
|
|
1605
|
+
}),
|
|
1606
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Actions, {
|
|
1607
|
+
t: props.t,
|
|
1608
|
+
busy: busy === "autoReview",
|
|
1609
|
+
disabled: autoReviewDisabled,
|
|
1610
|
+
...message?.route === "autoReview" ? { message: message.text } : {},
|
|
1611
|
+
onCancel: () => {
|
|
1612
|
+
resetAutoReview();
|
|
1613
|
+
setMessage(void 0);
|
|
1614
|
+
},
|
|
1615
|
+
onSave: saveAutoReview
|
|
1616
|
+
})
|
|
1617
|
+
] })
|
|
1618
|
+
}),
|
|
1619
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteCard, {
|
|
1620
|
+
title: props.t("compaction"),
|
|
1621
|
+
summary: compactionDraft === void 0 ? props.t("loading") : compactionOn ? routeName(groups, compactionDraft) : props.t("compactionFollow"),
|
|
1622
|
+
hint: props.t("compactionHelp"),
|
|
1623
|
+
icon: "compaction",
|
|
1624
|
+
open: open === "compaction" && compactionOn,
|
|
1625
|
+
onToggle: () => {
|
|
1626
|
+
if (compactionOn) toggle("compaction");
|
|
1627
|
+
},
|
|
1628
|
+
expandable: compactionOn,
|
|
1629
|
+
trailing: compactionDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1630
|
+
checked: compactionOn,
|
|
1631
|
+
disabled: busy === "compaction" || !compaction.writable,
|
|
1632
|
+
label: props.t("compaction"),
|
|
1633
|
+
onChange: persistCompactionEnabled
|
|
1634
|
+
}),
|
|
1635
|
+
children: compactionDraft === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1636
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
1637
|
+
children: props.t("loading")
|
|
1638
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1639
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1640
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
1641
|
+
children: props.t("compactionRouteHelp")
|
|
1642
|
+
}),
|
|
1643
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1644
|
+
className: ModelSwitchSettings_module_css_default.formGrid,
|
|
1645
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1646
|
+
label: props.t("provider"),
|
|
1647
|
+
value: compactionDraft.provider ?? "",
|
|
1648
|
+
disabled: busy === "compaction" || !compaction.writable,
|
|
1649
|
+
choices: compactionChoices.providers,
|
|
1650
|
+
onChange: (provider) => {
|
|
1651
|
+
const first = groups.find((group) => group.id === provider)?.models[0];
|
|
1652
|
+
setCompactionDraft({
|
|
1653
|
+
provider,
|
|
1654
|
+
...first === void 0 ? {} : { model: first.id }
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1658
|
+
label: props.t("model"),
|
|
1659
|
+
value: compactionDraft.model ?? "",
|
|
1660
|
+
disabled: busy === "compaction" || !compaction.writable,
|
|
1661
|
+
choices: compactionChoices.models,
|
|
1662
|
+
onChange: (model) => {
|
|
1663
|
+
setCompactionDraft({
|
|
1664
|
+
...compactionDraft,
|
|
1665
|
+
model
|
|
1666
|
+
});
|
|
1667
|
+
}
|
|
1668
|
+
})]
|
|
1669
|
+
}),
|
|
1670
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Actions, {
|
|
1671
|
+
t: props.t,
|
|
1672
|
+
busy: busy === "compaction",
|
|
1673
|
+
disabled: compactionDisabled,
|
|
1674
|
+
...message?.route === "compaction" ? { message: message.text } : {},
|
|
1675
|
+
onCancel: () => {
|
|
1676
|
+
resetCompaction();
|
|
1677
|
+
setMessage(void 0);
|
|
1678
|
+
},
|
|
1679
|
+
onSave: saveCompaction
|
|
1680
|
+
})
|
|
1681
|
+
] })
|
|
1397
1682
|
})
|
|
1398
1683
|
]
|
|
1399
1684
|
})
|
|
@@ -1438,6 +1723,14 @@ window.__ModuleLoader__.load({
|
|
|
1438
1723
|
requestFailed: "保存失败",
|
|
1439
1724
|
catalogFailed: "无法加载模型目录。",
|
|
1440
1725
|
conflict: "设置已在其他位置更改,请检查最新值后重试。",
|
|
1726
|
+
autoReview: "自动审查模型",
|
|
1727
|
+
autoReviewFollow: "跟随会话模型",
|
|
1728
|
+
autoReviewHelp: "为官方 auto-review(Auto 权限预设的逐调用审查)指定审查模型;需启用官方 auto-review 能力包。关闭时审查跟随当前会话模型。",
|
|
1729
|
+
autoReviewRouteHelp: "审查请求固定使用这里的 Provider/模型,与会话模型无关;保存后对下一次审查立即生效。",
|
|
1730
|
+
compaction: "压缩模型",
|
|
1731
|
+
compactionFollow: "跟随会话模型",
|
|
1732
|
+
compactionHelp: "为官方压缩(/compact 与官方自动压缩)指定摘要模型;关闭(两个字段都留空)时使用官方默认,即当前会话的目标模型。",
|
|
1733
|
+
compactionRouteHelp: "摘要请求固定使用这里的 Provider/模型,与会话目标模型无关;保存后对下一次压缩立即生效。保存时若恰有压缩进行中,可能被打断并在下次重试。",
|
|
1441
1734
|
"reason.central-subagent-routing": "Alpha.4 没有全局子代理启动路由接口。",
|
|
1442
1735
|
"reason.packaged-preset-roots": "Alpha.4 不支持插件提供额外 preset root。",
|
|
1443
1736
|
"reason.tool-owner-suppression": "Alpha.4 没有工具所有者或来源抑制接口。",
|
|
@@ -1481,6 +1774,14 @@ window.__ModuleLoader__.load({
|
|
|
1481
1774
|
requestFailed: "Save failed",
|
|
1482
1775
|
catalogFailed: "Could not load the model catalog.",
|
|
1483
1776
|
conflict: "Settings changed elsewhere. Review the latest values and retry.",
|
|
1777
|
+
autoReview: "Auto review model",
|
|
1778
|
+
autoReviewFollow: "Follows the session model",
|
|
1779
|
+
autoReviewHelp: "Pin the reviewer model for the official auto-review gate (per-call review under the Auto permission preset). Requires the official auto-review bundle. When off, reviews follow the session model.",
|
|
1780
|
+
autoReviewRouteHelp: "Review requests use exactly this provider/model regardless of the session model; saved changes apply to the very next review.",
|
|
1781
|
+
compaction: "Compaction model",
|
|
1782
|
+
compactionFollow: "Follows the conversation model",
|
|
1783
|
+
compactionHelp: "Pick the summarization model for official compaction (/compact and official automatic compaction). When off (both fields empty), the official default applies: the conversation target model.",
|
|
1784
|
+
compactionRouteHelp: "Summarization requests use exactly this provider/model regardless of the conversation target; saved changes apply to the very next compaction. Saving while a compaction is running may interrupt it; it retries next time.",
|
|
1484
1785
|
"reason.central-subagent-routing": "Alpha.4 exposes no global Subagent start-routing seam.",
|
|
1485
1786
|
"reason.packaged-preset-roots": "Alpha.4 exposes no plugin-owned preset root.",
|
|
1486
1787
|
"reason.tool-owner-suppression": "Alpha.4 exposes no tool owner or provenance suppression seam.",
|
|
@@ -1505,6 +1806,7 @@ window.__ModuleLoader__.load({
|
|
|
1505
1806
|
id: question.id,
|
|
1506
1807
|
question: question.question,
|
|
1507
1808
|
plan: question.detail,
|
|
1809
|
+
...intent.callId === void 0 ? {} : { callId: intent.callId },
|
|
1508
1810
|
approve,
|
|
1509
1811
|
...decline === void 0 ? {} : { decline }
|
|
1510
1812
|
};
|
|
@@ -2785,7 +3087,80 @@ window.__ModuleLoader__.load({
|
|
|
2785
3087
|
});
|
|
2786
3088
|
}
|
|
2787
3089
|
//#endregion
|
|
2788
|
-
//#region
|
|
3090
|
+
//#region src/client/picker/plan-preview.ts
|
|
3091
|
+
/** Registration id ui-plan uses for its `conversation.plan-review.actions` entry. */
|
|
3092
|
+
const PLAN_REVIEW_OPEN_ID = "@deepseek-ai/dsh-client-ui-plan";
|
|
3093
|
+
/** Identities whose preview was already opened this process (official parity: ui-plan's store keeps them too). */
|
|
3094
|
+
const opened = /* @__PURE__ */ new Set();
|
|
3095
|
+
/**
|
|
3096
|
+
* Stable identity of one review's sidebar preview.
|
|
3097
|
+
* @param sessionId - session that owns the review.
|
|
3098
|
+
* @param review - narrowed plan review.
|
|
3099
|
+
* @param requestKey - pending-question request key.
|
|
3100
|
+
* @returns `session:call:<callId>` for a logged plan, else `session:review:<requestKey>`.
|
|
3101
|
+
*/
|
|
3102
|
+
function planPreviewIdentity(sessionId, review, requestKey) {
|
|
3103
|
+
const identity = review.callId === void 0 ? `review:${requestKey}` : `call:${review.callId}`;
|
|
3104
|
+
return `${String(sessionId)}:${identity}`;
|
|
3105
|
+
}
|
|
3106
|
+
function faceOf(slots, sessionId) {
|
|
3107
|
+
const entry = slots.entries("conversation.plan-review.actions").find((candidate) => candidate.options.id === PLAN_REVIEW_OPEN_ID && typeof candidate.inject === "function");
|
|
3108
|
+
if (entry === void 0 || entry.inject === void 0) return void 0;
|
|
3109
|
+
try {
|
|
3110
|
+
const face = entry.inject(sessionId);
|
|
3111
|
+
if (face === void 0 || typeof face.openReview !== "function") return void 0;
|
|
3112
|
+
if (face.hooks === void 0 || typeof face.hooks.sidebarMounted?.getSnapshot !== "function") return void 0;
|
|
3113
|
+
return face;
|
|
3114
|
+
} catch {
|
|
3115
|
+
return;
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Bind the preview navigation to one slot registry.
|
|
3120
|
+
* @param slots - the live registry ledger.
|
|
3121
|
+
* @returns an idempotent binding usable from the card's render and effects.
|
|
3122
|
+
*/
|
|
3123
|
+
function createPlanPreviewBinding(slots) {
|
|
3124
|
+
const open = (sessionId, review, requestKey) => {
|
|
3125
|
+
const face = faceOf(slots, sessionId);
|
|
3126
|
+
if (face === void 0) return false;
|
|
3127
|
+
opened.add(planPreviewIdentity(sessionId, review, requestKey));
|
|
3128
|
+
face.openReview(review, requestKey);
|
|
3129
|
+
return true;
|
|
3130
|
+
};
|
|
3131
|
+
return {
|
|
3132
|
+
available: () => slots.entries("conversation.plan-review.actions").some((candidate) => candidate.options.id === PLAN_REVIEW_OPEN_ID),
|
|
3133
|
+
open,
|
|
3134
|
+
autoOpen: (sessionId, review, requestKey) => {
|
|
3135
|
+
const identity = planPreviewIdentity(sessionId, review, requestKey);
|
|
3136
|
+
if (opened.has(identity)) return () => void 0;
|
|
3137
|
+
const face = faceOf(slots, sessionId);
|
|
3138
|
+
if (face === void 0) return () => void 0;
|
|
3139
|
+
const mounted = face.hooks.sidebarMounted;
|
|
3140
|
+
if (mounted.getSnapshot() !== void 0) {
|
|
3141
|
+
opened.add(identity);
|
|
3142
|
+
face.openReview(review, requestKey);
|
|
3143
|
+
return () => void 0;
|
|
3144
|
+
}
|
|
3145
|
+
let disposed = false;
|
|
3146
|
+
let openedHere = false;
|
|
3147
|
+
const unsubscribe = mounted.subscribe(() => {
|
|
3148
|
+
if (disposed || openedHere || opened.has(identity)) return;
|
|
3149
|
+
if (mounted.getSnapshot() === void 0) return;
|
|
3150
|
+
openedHere = true;
|
|
3151
|
+
opened.add(identity);
|
|
3152
|
+
unsubscribe();
|
|
3153
|
+
face.openReview(review, requestKey);
|
|
3154
|
+
});
|
|
3155
|
+
return () => {
|
|
3156
|
+
disposed = true;
|
|
3157
|
+
unsubscribe();
|
|
3158
|
+
};
|
|
3159
|
+
}
|
|
3160
|
+
};
|
|
3161
|
+
}
|
|
3162
|
+
//#endregion
|
|
3163
|
+
//#region node_modules/.pnpm/dsh-llm-providers-ui@https+++github.com+NOirBRight+dsh-llm-providers-ui+releases+downlo_f1dadb1b56406564fc1bb8f2d953b82d/node_modules/dsh-llm-providers-ui/lib/order.js
|
|
2789
3164
|
/** Display order for installed provider cards when the user has not saved one. */
|
|
2790
3165
|
const PROVIDER_ITEM_ORDER = [
|
|
2791
3166
|
"llm-cursor",
|
|
@@ -3073,7 +3448,28 @@ window.__ModuleLoader__.load({
|
|
|
3073
3448
|
};
|
|
3074
3449
|
}
|
|
3075
3450
|
/**
|
|
3076
|
-
*
|
|
3451
|
+
* Address the plan document exactly as the official opener does.
|
|
3452
|
+
*
|
|
3453
|
+
* A logged plan (`callId` present) resolves from `dsh-resource://plan/...`
|
|
3454
|
+
* for as long as the session log holds the call; before that the pending
|
|
3455
|
+
* review's own `dsh-resource://plan-review/...` address is the one that
|
|
3456
|
+
* opens its preview.
|
|
3457
|
+
*
|
|
3458
|
+
* @param sessionId - the session that owns the review.
|
|
3459
|
+
* @param ref - logged call identity plus the pending request key.
|
|
3460
|
+
* @returns The plan resource address.
|
|
3461
|
+
*/
|
|
3462
|
+
function planDocumentAddress(sessionId, ref) {
|
|
3463
|
+
const encode = encodeURIComponent;
|
|
3464
|
+
return ref.callId === void 0 ? `dsh-resource://plan-review/${encode(sessionId)}/${encode(ref.requestKey)}` : `dsh-resource://plan/${encode(sessionId)}/${encode(ref.callId)}`;
|
|
3465
|
+
}
|
|
3466
|
+
/**
|
|
3467
|
+
* Make this plan the session's armed goal, replacing any unfinished goal.
|
|
3468
|
+
*
|
|
3469
|
+
* The objective is a short instruction carrying the plan document's address,
|
|
3470
|
+
* not the plan's raw markdown: goal objectives are injected into every round,
|
|
3471
|
+
* and a full plan would be truncated by length limits mid-sentence. The round
|
|
3472
|
+
* driver reads the plan from the address instead.
|
|
3077
3473
|
*
|
|
3078
3474
|
* Ordering mirrors the card's own commit-then-answer rule: a refusal here keeps
|
|
3079
3475
|
* the Plan pending instead of approving work that no goal tracks. The replace
|
|
@@ -3082,17 +3478,18 @@ window.__ModuleLoader__.load({
|
|
|
3082
3478
|
*
|
|
3083
3479
|
* @param remote - the released goal remote, absent when no goal package is mounted.
|
|
3084
3480
|
* @param sessionId - the session that owns both the review and the goal.
|
|
3085
|
-
* @param plan - the plan markdown under review.
|
|
3481
|
+
* @param plan - the plan markdown under review (validated non-empty).
|
|
3482
|
+
* @param ref - the plan document identity used for its address.
|
|
3086
3483
|
* @returns Whether the goal now tracks this plan, or why it does not.
|
|
3087
3484
|
*/
|
|
3088
|
-
async function setPlanAsGoal(remote, sessionId, plan) {
|
|
3485
|
+
async function setPlanAsGoal(remote, sessionId, plan, ref) {
|
|
3089
3486
|
if (remote === void 0) return { kind: "unsupported" };
|
|
3090
|
-
|
|
3091
|
-
if (objective === "") return {
|
|
3487
|
+
if (plan.trim() === "") return {
|
|
3092
3488
|
kind: "failed",
|
|
3093
3489
|
code: "GOAL_INVALID_OBJECTIVE",
|
|
3094
3490
|
message: "goal objective must be a non-empty string"
|
|
3095
3491
|
};
|
|
3492
|
+
const objective = `持续推进当前plan直到完成(plan 文档:${planDocumentAddress(sessionId, ref)})`;
|
|
3096
3493
|
const created = await remote.create(sessionId, { objective });
|
|
3097
3494
|
if (created.ok) return { kind: "created" };
|
|
3098
3495
|
if (created.error.code !== "GOAL_ALREADY_EXISTS") return {
|
|
@@ -3139,7 +3536,7 @@ window.__ModuleLoader__.load({
|
|
|
3139
3536
|
};
|
|
3140
3537
|
//#endregion
|
|
3141
3538
|
//#region \0dsh-css:src/client/picker/PlanReviewCard.module.css.mjs
|
|
3142
|
-
const css = ".BylfoW_frame{padding:6px calc(var(--dsh-composer-side-clearance) + 16px) 10px;justify-content:center;display:flex}.BylfoW_card{width:100%;max-width:var(--dsh-chat-content-width);border:1px solid var(--dsw-alias-state-warn-secondary);background:var(--dsw-specific-input-major);max-height:min(60vh,520px);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;flex-direction:column;display:flex;overflow:visible}.BylfoW_card,.BylfoW_card *{box-sizing:border-box}.BylfoW_strip{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary);border-radius:20px 20px 0 0;flex-shrink:0;align-items:center;gap:8px;padding:10px 16px;font-size:13px;line-height:18px;display:flex}.BylfoW_dot{background:var(--dsw-alias-state-warn-primary);border-radius:50%;width:8px;height:8px}.BylfoW_stripTitle{flex:none;font-weight:600}.BylfoW_headerPicker{flex:0 auto;align-items:center;min-width:0;max-width:55%;margin-left:auto;display:flex}.BylfoW_headerPicker>*{min-width:0;max-width:100%}.BylfoW_body{overscroll-behavior:contain;flex:auto;min-height:0;padding:12px 16px 4px;font-size:14px;line-height:22px;overflow-y:auto}.BylfoW_footer{z-index:2;flex-direction:column;flex-shrink:0;gap:6px;padding:8px 16px 12px;display:flex;position:relative;overflow:visible}.BylfoW_feedback{min-height:0;color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}.BylfoW_feedback:empty{display:none}.BylfoW_feedbackRow{align-items:center;gap:8px;min-width:0;display:flex}.BylfoW_feedbackInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-input-minor);min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-xs-13);border-radius:8px;flex:auto;padding:0 10px}.BylfoW_feedbackInput::placeholder{color:var(--dsw-alias-label-tertiary)}.BylfoW_feedbackInput:disabled{opacity:.6}.BylfoW_bar{flex-wrap:nowrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;min-height:32px;display:flex}.BylfoW_picker{flex:16rem;min-width:0;max-width:16rem}.BylfoW_pickerError{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px;display:flex}.BylfoW_actions{flex-wrap:nowrap;flex:none;justify-content:flex-end;align-items:center;gap:8px;margin-left:auto;display:flex}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{white-space:nowrap;height:32px;min-height:32px;padding:0 10px}.BylfoW_discuss,.BylfoW_recover{color:var(--dsw-alias-label-secondary)}.BylfoW_discuss:hover:not(:disabled),.BylfoW_recover:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BylfoW_approve{padding:0 12px}@media (width<=720px){.BylfoW_frame{padding-right:max(10px, env(safe-area-inset-right));padding-bottom:max(10px, env(safe-area-inset-bottom));padding-left:max(10px, env(safe-area-inset-left))}.BylfoW_card{border-radius:16px}.BylfoW_strip,.BylfoW_body,.BylfoW_footer{padding-left:12px;padding-right:12px}.BylfoW_strip{flex-wrap:wrap;gap:6px}.BylfoW_headerPicker{flex:100%;max-width:100%;margin-left:0}.BylfoW_bar{justify-content:flex-end;gap:6px}.BylfoW_actions{flex:100%;justify-content:flex-end;gap:6px;min-width:0}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{overflow-wrap:anywhere;white-space:normal;flex:1 1 0;min-width:0;height:auto;padding:4px;line-height:14px}.BylfoW_feedbackInput{height:auto;min-height:32px}}";
|
|
3539
|
+
const css = ".BylfoW_frame{padding:6px calc(var(--dsh-composer-side-clearance) + 16px) 10px;justify-content:center;display:flex}.BylfoW_card{width:100%;max-width:var(--dsh-chat-content-width);border:1px solid var(--dsw-alias-state-warn-secondary);background:var(--dsw-specific-input-major);max-height:min(60vh,520px);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;flex-direction:column;display:flex;overflow:visible}.BylfoW_card,.BylfoW_card *{box-sizing:border-box}.BylfoW_strip{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary);border-radius:20px 20px 0 0;flex-shrink:0;align-items:center;gap:8px;padding:10px 16px;font-size:13px;line-height:18px;display:flex}.BylfoW_dot{background:var(--dsw-alias-state-warn-primary);border-radius:50%;width:8px;height:8px}.BylfoW_stripTitle{flex:none;font-weight:600}.BylfoW_previewLink{color:inherit;font:inherit;cursor:pointer;opacity:.85;background:0 0;border:0;flex:none;align-items:center;gap:4px;padding:0;display:inline-flex}.BylfoW_previewLink:hover{opacity:1;text-decoration:underline}.BylfoW_previewLink:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:3px}.BylfoW_headerPicker{flex:0 auto;align-items:center;min-width:0;max-width:55%;margin-left:auto;display:flex}.BylfoW_headerPicker>*{min-width:0;max-width:100%}.BylfoW_body{overscroll-behavior:contain;flex:auto;min-height:0;padding:12px 16px 4px;font-size:14px;line-height:22px;overflow-y:auto}.BylfoW_summary{min-width:0}.BylfoW_summaryTitle{text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:15px;font-weight:500;line-height:22px;overflow:hidden}.BylfoW_summaryText{-webkit-line-clamp:2;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;margin:8px 0 0;font-size:14px;line-height:24px;display:-webkit-box;overflow:hidden}.BylfoW_footer{z-index:2;flex-direction:column;flex-shrink:0;gap:6px;padding:8px 16px 12px;display:flex;position:relative;overflow:visible}.BylfoW_feedback{min-height:0;color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}.BylfoW_feedback:empty{display:none}.BylfoW_feedbackRow{align-items:center;gap:8px;min-width:0;display:flex}.BylfoW_feedbackInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-input-minor);min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-xs-13);border-radius:8px;flex:auto;padding:0 10px}.BylfoW_feedbackInput::placeholder{color:var(--dsw-alias-label-tertiary)}.BylfoW_feedbackInput:disabled{opacity:.6}.BylfoW_bar{flex-wrap:nowrap;justify-content:space-between;align-items:center;gap:12px;min-width:0;min-height:32px;display:flex}.BylfoW_picker{flex:16rem;min-width:0;max-width:16rem}.BylfoW_pickerError{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px;display:flex}.BylfoW_actions{flex-wrap:nowrap;flex:none;justify-content:flex-end;align-items:center;gap:8px;margin-left:auto;display:flex}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{white-space:nowrap;height:32px;min-height:32px;padding:0 10px}.BylfoW_discuss,.BylfoW_recover{color:var(--dsw-alias-label-secondary)}.BylfoW_discuss:hover:not(:disabled),.BylfoW_recover:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BylfoW_approve{padding:0 12px}@media (width<=720px){.BylfoW_frame{padding-right:max(10px, env(safe-area-inset-right));padding-bottom:max(10px, env(safe-area-inset-bottom));padding-left:max(10px, env(safe-area-inset-left))}.BylfoW_card{border-radius:16px}.BylfoW_strip,.BylfoW_body,.BylfoW_footer{padding-left:12px;padding-right:12px}.BylfoW_strip{flex-wrap:wrap;gap:6px}.BylfoW_headerPicker{flex:100%;max-width:100%;margin-left:0}.BylfoW_bar{justify-content:flex-end;gap:6px}.BylfoW_actions{flex:100%;justify-content:flex-end;gap:6px;min-width:0}.BylfoW_discuss,.BylfoW_keep,.BylfoW_goalRun,.BylfoW_approve,.BylfoW_recover{overflow-wrap:anywhere;white-space:normal;flex:1 1 0;min-width:0;height:auto;padding:4px;line-height:14px}.BylfoW_feedbackInput{height:auto;min-height:32px}}";
|
|
3143
3540
|
const tagId = "dsh-model-switch/PlanReviewCard.module.css";
|
|
3144
3541
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
3145
3542
|
const tag = document.createElement("style");
|
|
@@ -3166,9 +3563,13 @@ window.__ModuleLoader__.load({
|
|
|
3166
3563
|
"keep": "BylfoW_keep",
|
|
3167
3564
|
"picker": "BylfoW_picker",
|
|
3168
3565
|
"pickerError": "BylfoW_pickerError",
|
|
3566
|
+
"previewLink": "BylfoW_previewLink",
|
|
3169
3567
|
"recover": "BylfoW_recover",
|
|
3170
3568
|
"strip": "BylfoW_strip",
|
|
3171
|
-
"stripTitle": "BylfoW_stripTitle"
|
|
3569
|
+
"stripTitle": "BylfoW_stripTitle",
|
|
3570
|
+
"summary": "BylfoW_summary",
|
|
3571
|
+
"summaryText": "BylfoW_summaryText",
|
|
3572
|
+
"summaryTitle": "BylfoW_summaryTitle"
|
|
3172
3573
|
};
|
|
3173
3574
|
//#endregion
|
|
3174
3575
|
//#region src/client/picker/PlanReviewCard.tsx
|
|
@@ -3285,11 +3686,12 @@ window.__ModuleLoader__.load({
|
|
|
3285
3686
|
directory: pickerDirectoryViewOrdered(snapshot, props, order, props.catalogRoutes?.() ?? {}),
|
|
3286
3687
|
t: props.t,
|
|
3287
3688
|
goalRemote: props.goalRemote,
|
|
3689
|
+
planPreview: props.planPreview,
|
|
3288
3690
|
...props.resolveInteractionOperations === void 0 ? {} : { resolveInteractionOperations: props.resolveInteractionOperations },
|
|
3289
3691
|
...props.roleOf === void 0 ? {} : { roleOf: props.roleOf }
|
|
3290
3692
|
}, props.matched.key);
|
|
3291
3693
|
}
|
|
3292
|
-
function PlanReviewState({ matched, review, available, providerLock, agentLocked, lockFailed, settingsUnavailableReason, directory, t, goalRemote, resolveInteractionOperations, roleOf }) {
|
|
3694
|
+
function PlanReviewState({ matched, review, available, providerLock, agentLocked, lockFailed, settingsUnavailableReason, directory, t, goalRemote, planPreview, resolveInteractionOperations, roleOf }) {
|
|
3293
3695
|
const { snapshot, getDirectorySnapshot, load, select } = directory;
|
|
3294
3696
|
const [execution, setExecution] = (0, react.useState)(snapshot.current ?? void 0);
|
|
3295
3697
|
const [feedback, setFeedback] = (0, react.useState)("");
|
|
@@ -3305,6 +3707,26 @@ window.__ModuleLoader__.load({
|
|
|
3305
3707
|
if (execution === void 0 && snapshot.current !== null) setExecution(snapshot.current);
|
|
3306
3708
|
}, [execution, snapshot.current]);
|
|
3307
3709
|
/**
|
|
3710
|
+
* The takeover hides the official panel, so this card drives ui-plan's
|
|
3711
|
+
* registered opener: the full plan opens in the right sidebar as soon as a
|
|
3712
|
+
* Session is on screen (identity-deduped inside the binding).
|
|
3713
|
+
*/
|
|
3714
|
+
(0, react.useEffect)(() => planPreview.autoOpen(matched.sessionId, review, matched.key), [
|
|
3715
|
+
planPreview,
|
|
3716
|
+
matched.sessionId,
|
|
3717
|
+
matched.key,
|
|
3718
|
+
review
|
|
3719
|
+
]);
|
|
3720
|
+
/** Official two-part summary: first line as title, first paragraph as body. */
|
|
3721
|
+
const summary = (0, react.useMemo)(() => {
|
|
3722
|
+
const title = (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-line" });
|
|
3723
|
+
const description = (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-paragraph" });
|
|
3724
|
+
return {
|
|
3725
|
+
title,
|
|
3726
|
+
description: description === title ? "" : description
|
|
3727
|
+
};
|
|
3728
|
+
}, [review.plan]);
|
|
3729
|
+
/**
|
|
3308
3730
|
* Run one takeover action. `force` reaches past a terminal answer state: the
|
|
3309
3731
|
* withdrawal action must stay reachable, or a rejected answer would leave the
|
|
3310
3732
|
* card with no way back to the composer.
|
|
@@ -3357,7 +3779,9 @@ window.__ModuleLoader__.load({
|
|
|
3357
3779
|
};
|
|
3358
3780
|
const onApprove = () => {
|
|
3359
3781
|
if (execution === void 0 || !executionAllowed || !available || busy || blocked) return;
|
|
3360
|
-
settle(() =>
|
|
3782
|
+
settle(async () => {
|
|
3783
|
+
await approveWith(execution);
|
|
3784
|
+
});
|
|
3361
3785
|
};
|
|
3362
3786
|
const goal = goalRemote();
|
|
3363
3787
|
const goalReason = goal === void 0 ? t("plan.goalUnsupported") : void 0;
|
|
@@ -3370,7 +3794,10 @@ window.__ModuleLoader__.load({
|
|
|
3370
3794
|
const onRunAsGoal = () => {
|
|
3371
3795
|
if (execution === void 0 || !executionAllowed || !available || busy || blocked || goal === void 0) return;
|
|
3372
3796
|
settle(async () => {
|
|
3373
|
-
const handoff = await setPlanAsGoal(goal, matched.sessionId, review.plan
|
|
3797
|
+
const handoff = await setPlanAsGoal(goal, matched.sessionId, review.plan, {
|
|
3798
|
+
...review.callId === void 0 ? {} : { callId: review.callId },
|
|
3799
|
+
requestKey: matched.key
|
|
3800
|
+
});
|
|
3374
3801
|
if (handoff.kind === "unsupported") throw new Error(t("plan.goalUnsupported"));
|
|
3375
3802
|
if (handoff.kind === "failed") {
|
|
3376
3803
|
const message = handoff.code === void 0 ? handoff.message : `${handoff.code}: ${handoff.message}`;
|
|
@@ -3397,6 +3824,15 @@ window.__ModuleLoader__.load({
|
|
|
3397
3824
|
className: PlanReviewCard_module_css_default.stripTitle,
|
|
3398
3825
|
children: t("plan.header")
|
|
3399
3826
|
}),
|
|
3827
|
+
planPreview.available() && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3828
|
+
type: "button",
|
|
3829
|
+
className: PlanReviewCard_module_css_default.previewLink,
|
|
3830
|
+
"data-plan-preview-open": true,
|
|
3831
|
+
onClick: () => {
|
|
3832
|
+
planPreview.open(matched.sessionId, review, matched.key);
|
|
3833
|
+
},
|
|
3834
|
+
children: t("plan.openFull")
|
|
3835
|
+
}),
|
|
3400
3836
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3401
3837
|
className: PlanReviewCard_module_css_default.headerPicker,
|
|
3402
3838
|
"aria-label": t("plan.execution"),
|
|
@@ -3428,15 +3864,16 @@ window.__ModuleLoader__.load({
|
|
|
3428
3864
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3429
3865
|
className: PlanReviewCard_module_css_default.body,
|
|
3430
3866
|
"data-plan-review-scroll": true,
|
|
3431
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3867
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3868
|
+
className: PlanReviewCard_module_css_default.summary,
|
|
3869
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3870
|
+
className: PlanReviewCard_module_css_default.summaryTitle,
|
|
3871
|
+
"data-plan-review-summary": true,
|
|
3872
|
+
children: summary.title
|
|
3873
|
+
}), summary.description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3874
|
+
className: PlanReviewCard_module_css_default.summaryText,
|
|
3875
|
+
children: summary.description
|
|
3876
|
+
})]
|
|
3440
3877
|
})
|
|
3441
3878
|
}),
|
|
3442
3879
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3581,6 +4018,7 @@ window.__ModuleLoader__.load({
|
|
|
3581
4018
|
"choice.unavailable": "目录没有这个组合",
|
|
3582
4019
|
"plan.kicker": "Plan",
|
|
3583
4020
|
"plan.header": "计划待审",
|
|
4021
|
+
"plan.openFull": "查看完整计划",
|
|
3584
4022
|
"plan.execution": "执行模型",
|
|
3585
4023
|
"plan.approve": "确认执行",
|
|
3586
4024
|
"plan.keep": "拒绝",
|
|
@@ -3636,6 +4074,7 @@ window.__ModuleLoader__.load({
|
|
|
3636
4074
|
"choice.unavailable": "This combination is not in the catalog",
|
|
3637
4075
|
"plan.kicker": "Plan",
|
|
3638
4076
|
"plan.header": "Plan review",
|
|
4077
|
+
"plan.openFull": "View full plan",
|
|
3639
4078
|
"plan.execution": "Execution model",
|
|
3640
4079
|
"plan.approve": "Approve",
|
|
3641
4080
|
"plan.keep": "Keep planning",
|
|
@@ -3805,6 +4244,7 @@ window.__ModuleLoader__.load({
|
|
|
3805
4244
|
});
|
|
3806
4245
|
});
|
|
3807
4246
|
const resolveInteractionOperations = () => interactionOperationsFrom(scope);
|
|
4247
|
+
const planPreview = createPlanPreviewBinding(scope.slots);
|
|
3808
4248
|
const rpcOf = () => {
|
|
3809
4249
|
return scope.get("connection", false)?.rpc;
|
|
3810
4250
|
};
|
|
@@ -3831,6 +4271,7 @@ window.__ModuleLoader__.load({
|
|
|
3831
4271
|
subscribeMainDefaults: (listener) => mainDefaults.subscribe(listener),
|
|
3832
4272
|
getMainDefaultsSnapshot: () => mainDefaults.getSnapshot(),
|
|
3833
4273
|
goalRemote: () => goalRemoteFrom(scope),
|
|
4274
|
+
planPreview,
|
|
3834
4275
|
hooks: {
|
|
3835
4276
|
directory: directory.store,
|
|
3836
4277
|
providerOrder: orderStore
|
|
@@ -3972,6 +4413,8 @@ window.__ModuleLoader__.load({
|
|
|
3972
4413
|
const subagent = deriveConfigForm(owned, deriveSubagentSettings, SUBAGENT_SETTINGS_FIELDS);
|
|
3973
4414
|
const search = deriveConfigForm(owned, deriveSearchSettings, SEARCH_SETTINGS_FIELDS);
|
|
3974
4415
|
const image = deriveConfigForm(owned, deriveImageSettings, IMAGE_SETTINGS_FIELDS);
|
|
4416
|
+
const autoReview = deriveConfigForm(owned, deriveAutoReviewSettings, AUTO_REVIEW_SETTINGS_FIELDS);
|
|
4417
|
+
const compaction = deriveConfigForm(owned, deriveCompactionSettings, COMPACTION_SETTINGS_FIELDS);
|
|
3975
4418
|
const saveMain = async (next, expectedRevision) => {
|
|
3976
4419
|
if (!await mainForm.mutate([
|
|
3977
4420
|
{
|
|
@@ -4036,13 +4479,15 @@ window.__ModuleLoader__.load({
|
|
|
4036
4479
|
subagentSettings: subagent,
|
|
4037
4480
|
searchSettings: search,
|
|
4038
4481
|
imageSettings: image,
|
|
4482
|
+
autoReviewSettings: autoReview,
|
|
4483
|
+
compactionSettings: compaction,
|
|
4039
4484
|
switchSettings: owned
|
|
4040
4485
|
},
|
|
4041
4486
|
capabilities: RUNTIME_CAPABILITIES,
|
|
4042
4487
|
saveMain,
|
|
4043
4488
|
setSubagent: (field, value) => value === void 0 ? subagent.unset(field) : subagent.set(field, value),
|
|
4044
4489
|
setCapability: (route, field, value) => {
|
|
4045
|
-
const scope = route === "search" ? search : image;
|
|
4490
|
+
const scope = route === "search" ? search : route === "image" ? image : route === "compaction" ? compaction : autoReview;
|
|
4046
4491
|
return value === void 0 ? scope.unset(field) : scope.set(field, value);
|
|
4047
4492
|
},
|
|
4048
4493
|
setCompactOnSwitch: async (value) => {
|