dsh-context-compression-improved 0.5.1 → 0.5.3
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/.gitattributes +1 -0
- package/CHANGELOG.ja.md +144 -83
- package/CHANGELOG.ko.md +143 -82
- package/CHANGELOG.md +278 -212
- package/CHANGELOG.zh.md +131 -77
- package/docs/installation.md +103 -103
- package/docs/installation.zh.md +100 -100
- package/package.json +1 -1
- package/packages/selector/cordis.patch.yml +5 -6
- package/packages/selector/lib/advisor-state.js +4 -231
- package/packages/selector/lib/client.d.ts +0 -24
- package/packages/selector/lib/client.js +6 -501
- package/packages/selector/lib/index.d.ts +4 -10
- package/packages/selector/lib/index.js +16 -234
- package/packages/selector/lib/pruner.d.ts +13 -248
- package/packages/selector/lib/pruner.js +148 -552
- package/packages/selector/src/client/EstimatorControls.tsx +0 -101
- package/packages/selector/src/client/index.ts +0 -17
- package/packages/selector/src/client/locales.ts +0 -38
- package/packages/selector/src/client/preset-options.ts +3 -2
- package/packages/selector/src/client/settings-section.tsx +8 -17
- package/packages/selector/src/index.ts +24 -271
- package/packages/selector/src/profiles.ts +4 -27
- package/packages/selector/src/pruner/state.ts +2 -25
- package/packages/selector/src/pruner.ts +75 -403
- package/packages/selector/src/runtime/audit.ts +27 -21
- package/packages/selector/src/runtime/config.ts +6 -32
- package/packages/selector/src/runtime/tokenpilot/advisor-prompt.ts +188 -188
- package/packages/selector/src/runtime/tokenpilot/advisor-state.ts +149 -133
- package/packages/selector/src/runtime/tokenpilot/advisor.ts +419 -419
- package/packages/selector/src/runtime/tokenpilot/benefit.ts +200 -0
- package/packages/selector/src/runtime/types.ts +0 -17
- package/packages/selector/tests/advisor-report.host.spec.ts +223 -223
- package/packages/selector/tests/preset-options-write.client.spec.ts +7 -23
- package/packages/selector/tests/public/package-contract.client.spec.ts +20 -0
- package/packages/selector/tests/runtime/advice-never-withholds.host.spec.ts +232 -0
- package/packages/selector/tests/runtime/advisor-invariant.spec.ts +272 -272
- package/packages/selector/tests/runtime/advisor.spec.ts +226 -226
- package/packages/selector/tests/runtime/audit.spec.ts +35 -21
- package/packages/selector/tests/runtime/char-basis.spec.ts +30 -30
- package/packages/selector/tests/runtime/deprecated-preset-options.spec.ts +96 -0
- package/packages/selector/tests/runtime/tokenpilot/benefit.spec.ts +217 -0
- package/packages/selector/tests/runtime/tokenpilot/profile-baseline.spec.ts +4 -5
- package/packages/selector/tests/settings-seat.client.spec.ts +45 -14
- package/scripts/toolclass-corpus-replay.mjs +281 -281
- package/packages/selector/src/client/ReviewOverlay.tsx +0 -320
- package/packages/selector/src/client/review-scope.ts +0 -16
- package/packages/selector/src/runtime/tokenpilot/proposal.ts +0 -267
- package/packages/selector/src/runtime/tokenpilot/review-queue.ts +0 -231
- package/packages/selector/src/runtime/tokenpilot/review-registry.ts +0 -117
- package/packages/selector/src/runtime/tokenpilot/review-storage.ts +0 -122
- package/packages/selector/tests/review-overlay.client.spec.tsx +0 -118
- package/packages/selector/tests/review-routes-registry.host.spec.ts +0 -142
- package/packages/selector/tests/review-routes.host.spec.ts +0 -290
- package/packages/selector/tests/runtime/tokenpilot/proposal.spec.ts +0 -393
- package/packages/selector/tests/runtime/tokenpilot/pruner-review.spec.ts +0 -382
- package/packages/selector/tests/runtime/tokenpilot/review-queue.spec.ts +0 -168
|
@@ -95,8 +95,7 @@ window.__ModuleLoader__.load({
|
|
|
95
95
|
"dedupeToolResults",
|
|
96
96
|
"summaryLocator",
|
|
97
97
|
"prefixStabilizer",
|
|
98
|
-
"readState"
|
|
99
|
-
"reviewMode"
|
|
98
|
+
"readState"
|
|
100
99
|
]) {
|
|
101
100
|
const entry = value[key];
|
|
102
101
|
if (entry !== void 0 && typeof entry !== "boolean") return void 0;
|
|
@@ -116,12 +115,6 @@ window.__ModuleLoader__.load({
|
|
|
116
115
|
}
|
|
117
116
|
const estimatorTimeoutMs = value.estimatorTimeoutMs;
|
|
118
117
|
if (estimatorTimeoutMs !== void 0 && (typeof estimatorTimeoutMs !== "number" || !Number.isSafeInteger(estimatorTimeoutMs) || estimatorTimeoutMs < 100 || estimatorTimeoutMs > 6e4)) return;
|
|
119
|
-
const reviewTimeoutTurns = value.reviewTimeoutTurns;
|
|
120
|
-
if (reviewTimeoutTurns !== void 0 && (typeof reviewTimeoutTurns !== "number" || !Number.isSafeInteger(reviewTimeoutTurns) || reviewTimeoutTurns < 1)) return;
|
|
121
|
-
const cacheHitDiscountAlpha = value.cacheHitDiscountAlpha;
|
|
122
|
-
if (cacheHitDiscountAlpha !== void 0 && (typeof cacheHitDiscountAlpha !== "number" || !Number.isFinite(cacheHitDiscountAlpha) || cacheHitDiscountAlpha <= 0 || cacheHitDiscountAlpha >= 1)) return;
|
|
123
|
-
const reviewHighImpactTokens = value.reviewHighImpactTokens;
|
|
124
|
-
if (reviewHighImpactTokens !== void 0 && (typeof reviewHighImpactTokens !== "number" || !Number.isSafeInteger(reviewHighImpactTokens) || reviewHighImpactTokens < 0)) return;
|
|
125
118
|
const advisorTimeoutMs = value.advisorTimeoutMs;
|
|
126
119
|
if (advisorTimeoutMs !== void 0 && (typeof advisorTimeoutMs !== "number" || !Number.isSafeInteger(advisorTimeoutMs) || advisorTimeoutMs < 100 || advisorTimeoutMs > 6e4)) return;
|
|
127
120
|
const advisorRefreshTurns = value.advisorRefreshTurns;
|
|
@@ -143,10 +136,6 @@ window.__ModuleLoader__.load({
|
|
|
143
136
|
if (value.estimatorBaseUrl !== void 0) decoded.estimatorBaseUrl = value.estimatorBaseUrl;
|
|
144
137
|
if (value.estimatorApiKey !== void 0) decoded.estimatorApiKey = value.estimatorApiKey;
|
|
145
138
|
if (estimatorTimeoutMs !== void 0) decoded.estimatorTimeoutMs = estimatorTimeoutMs;
|
|
146
|
-
if (value.reviewMode !== void 0) decoded.reviewMode = value.reviewMode;
|
|
147
|
-
if (reviewTimeoutTurns !== void 0) decoded.reviewTimeoutTurns = reviewTimeoutTurns;
|
|
148
|
-
if (cacheHitDiscountAlpha !== void 0) decoded.cacheHitDiscountAlpha = cacheHitDiscountAlpha;
|
|
149
|
-
if (reviewHighImpactTokens !== void 0) decoded.reviewHighImpactTokens = reviewHighImpactTokens;
|
|
150
139
|
if (advisorMode !== void 0) decoded.advisorMode = advisorMode;
|
|
151
140
|
if (advisorTimeoutMs !== void 0) decoded.advisorTimeoutMs = advisorTimeoutMs;
|
|
152
141
|
if (advisorRefreshTurns !== void 0) decoded.advisorRefreshTurns = advisorRefreshTurns;
|
|
@@ -1034,123 +1023,6 @@ window.__ModuleLoader__.load({
|
|
|
1034
1023
|
]
|
|
1035
1024
|
});
|
|
1036
1025
|
}
|
|
1037
|
-
/**
|
|
1038
|
-
* TokenPilot-inspired review-mode card (beta). When enabled, edge/high-impact
|
|
1039
|
-
* reduction candidates queue for manual approval and execute in one merged
|
|
1040
|
-
* batch at the next turn boundary; the numeric fields tune the benefit model.
|
|
1041
|
-
* Numeric drafts commit on blur and only when they parse to a value the
|
|
1042
|
-
* runtime schema accepts, so an invalid keystroke never disables the panel.
|
|
1043
|
-
*/
|
|
1044
|
-
function ReviewModeControls({ options, disabled, save, settle, t }) {
|
|
1045
|
-
const [turnsDraft, setTurnsDraft] = (0, react.useState)(String(options.reviewTimeoutTurns ?? 6));
|
|
1046
|
-
const [alphaDraft, setAlphaDraft] = (0, react.useState)(String(options.cacheHitDiscountAlpha ?? .1));
|
|
1047
|
-
const [highImpactDraft, setHighImpactDraft] = (0, react.useState)(String(options.reviewHighImpactTokens ?? 4e3));
|
|
1048
|
-
const reviewMode = options.reviewMode ?? false;
|
|
1049
|
-
const commit = (patch) => {
|
|
1050
|
-
settle(() => save(patch));
|
|
1051
|
-
};
|
|
1052
|
-
const commitTurns = () => {
|
|
1053
|
-
const next = Number(turnsDraft);
|
|
1054
|
-
if (!Number.isSafeInteger(next) || next < 1 || next === (options.reviewTimeoutTurns ?? 6)) return;
|
|
1055
|
-
commit({ reviewTimeoutTurns: next });
|
|
1056
|
-
};
|
|
1057
|
-
const commitAlpha = () => {
|
|
1058
|
-
const next = Number(alphaDraft);
|
|
1059
|
-
if (!Number.isFinite(next) || next <= 0 || next >= 1 || next === (options.cacheHitDiscountAlpha ?? .1)) return;
|
|
1060
|
-
commit({ cacheHitDiscountAlpha: next });
|
|
1061
|
-
};
|
|
1062
|
-
const commitHighImpact = () => {
|
|
1063
|
-
const next = Number(highImpactDraft);
|
|
1064
|
-
if (!Number.isSafeInteger(next) || next < 0 || next === (options.reviewHighImpactTokens ?? 4e3)) return;
|
|
1065
|
-
commit({ reviewHighImpactTokens: next });
|
|
1066
|
-
};
|
|
1067
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1068
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.autoCompact,
|
|
1069
|
-
"aria-labelledby": "context-compression-review-title",
|
|
1070
|
-
children: [
|
|
1071
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1072
|
-
id: "context-compression-review-title",
|
|
1073
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.autoCompactTitle,
|
|
1074
|
-
children: t("review.title")
|
|
1075
|
-
}),
|
|
1076
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1077
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.customNote,
|
|
1078
|
-
children: t("review.description")
|
|
1079
|
-
}),
|
|
1080
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1081
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.field,
|
|
1082
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("review.enabled") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
1083
|
-
value: reviewMode ? "on" : "off",
|
|
1084
|
-
disabled,
|
|
1085
|
-
onChange: (event) => {
|
|
1086
|
-
settle(() => save({ reviewMode: event.currentTarget.value === "on" }));
|
|
1087
|
-
},
|
|
1088
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1089
|
-
value: "off",
|
|
1090
|
-
children: t("review.enabled.off")
|
|
1091
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1092
|
-
value: "on",
|
|
1093
|
-
children: t("review.enabled.on")
|
|
1094
|
-
})]
|
|
1095
|
-
})]
|
|
1096
|
-
}),
|
|
1097
|
-
reviewMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1098
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1099
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.field,
|
|
1100
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("review.timeoutTurns") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1101
|
-
type: "number",
|
|
1102
|
-
min: 1,
|
|
1103
|
-
step: 1,
|
|
1104
|
-
value: turnsDraft,
|
|
1105
|
-
disabled,
|
|
1106
|
-
onChange: (event) => {
|
|
1107
|
-
setTurnsDraft(event.currentTarget.value);
|
|
1108
|
-
},
|
|
1109
|
-
onBlur: commitTurns,
|
|
1110
|
-
onKeyDown: (event) => {
|
|
1111
|
-
if (event.key === "Enter") event.currentTarget.blur();
|
|
1112
|
-
}
|
|
1113
|
-
})]
|
|
1114
|
-
}),
|
|
1115
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1116
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.field,
|
|
1117
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("review.alpha") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1118
|
-
type: "number",
|
|
1119
|
-
min: .01,
|
|
1120
|
-
max: .99,
|
|
1121
|
-
step: .05,
|
|
1122
|
-
value: alphaDraft,
|
|
1123
|
-
disabled,
|
|
1124
|
-
onChange: (event) => {
|
|
1125
|
-
setAlphaDraft(event.currentTarget.value);
|
|
1126
|
-
},
|
|
1127
|
-
onBlur: commitAlpha,
|
|
1128
|
-
onKeyDown: (event) => {
|
|
1129
|
-
if (event.key === "Enter") event.currentTarget.blur();
|
|
1130
|
-
}
|
|
1131
|
-
})]
|
|
1132
|
-
}),
|
|
1133
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1134
|
-
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.field,
|
|
1135
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("review.highImpact") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1136
|
-
type: "number",
|
|
1137
|
-
min: 0,
|
|
1138
|
-
step: 500,
|
|
1139
|
-
value: highImpactDraft,
|
|
1140
|
-
disabled,
|
|
1141
|
-
onChange: (event) => {
|
|
1142
|
-
setHighImpactDraft(event.currentTarget.value);
|
|
1143
|
-
},
|
|
1144
|
-
onBlur: commitHighImpact,
|
|
1145
|
-
onKeyDown: (event) => {
|
|
1146
|
-
if (event.key === "Enter") event.currentTarget.blur();
|
|
1147
|
-
}
|
|
1148
|
-
})]
|
|
1149
|
-
})
|
|
1150
|
-
] }) : null
|
|
1151
|
-
]
|
|
1152
|
-
});
|
|
1153
|
-
}
|
|
1154
1026
|
//#endregion
|
|
1155
1027
|
//#region src/client/settings-section.tsx
|
|
1156
1028
|
/**
|
|
@@ -1254,19 +1126,13 @@ window.__ModuleLoader__.load({
|
|
|
1254
1126
|
current !== "tokenpilot-inspired" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EstimatorInactiveNotice, {
|
|
1255
1127
|
profile: t(`profile.${current}`),
|
|
1256
1128
|
t
|
|
1257
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1258
|
-
options: state.value?.presetOptions ?? {},
|
|
1259
|
-
disabled: busy || !state.writable || false,
|
|
1260
|
-
save: savePresetOptions,
|
|
1261
|
-
settle,
|
|
1262
|
-
t
|
|
1263
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewModeControls, {
|
|
1129
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EstimatorControls, {
|
|
1264
1130
|
options: state.value?.presetOptions ?? {},
|
|
1265
1131
|
disabled: busy || !state.writable || false,
|
|
1266
1132
|
save: savePresetOptions,
|
|
1267
1133
|
settle,
|
|
1268
1134
|
t
|
|
1269
|
-
})
|
|
1135
|
+
}),
|
|
1270
1136
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1271
1137
|
className: _dsh_context_compression_css_466eb745356d_CompressionProfileSelector_module_css_default.pricing,
|
|
1272
1138
|
children: t("pricing.disclosure")
|
|
@@ -1356,25 +1222,6 @@ window.__ModuleLoader__.load({
|
|
|
1356
1222
|
"estimator.apiKey.set": "已设置 · 输入新值覆盖",
|
|
1357
1223
|
"estimator.apiKey.clear": "清除",
|
|
1358
1224
|
"estimator.apiKey.overwrite": "已设置保密值,输入新值并失焦即可覆盖。",
|
|
1359
|
-
"review.title": "人工审查(beta)",
|
|
1360
|
-
"review.description": "开启后,边缘区间与高影响的压缩候选不再自动执行,而是进入待审队列并在你批准后的下一个回合边界批量执行;未处理的提案超过过期轮数后自动作废。仅随「TokenPilot 启发模式」提供,默认关闭。",
|
|
1361
|
-
"review.enabled": "审查模式",
|
|
1362
|
-
"review.enabled.on": "开(提案等待人工批准)",
|
|
1363
|
-
"review.enabled.off": "关(默认,全自动)",
|
|
1364
|
-
"review.timeoutTurns": "提案过期轮数",
|
|
1365
|
-
"review.alpha": "缓存命中折扣 α",
|
|
1366
|
-
"review.highImpact": "高影响门槛(tokens)",
|
|
1367
|
-
"review.badge": "待审",
|
|
1368
|
-
"review.summary.autoApplied": "自动应用",
|
|
1369
|
-
"review.summary.reviewApplied": "审查应用",
|
|
1370
|
-
"review.summary.expired": "已过期",
|
|
1371
|
-
"review.summary.voided": "已作废",
|
|
1372
|
-
"review.row.payback": "回本轮数",
|
|
1373
|
-
"review.row.expectedSaving": "预期节省",
|
|
1374
|
-
"review.row.estimated": "估计",
|
|
1375
|
-
"review.action.approve": "批准",
|
|
1376
|
-
"review.action.reject": "驳回",
|
|
1377
|
-
"review.action.ignore": "本会话忽略",
|
|
1378
1225
|
"detail.tokenpilot-inspired": "在平衡模式之上叠加去重指针、恢复豁免、摘要定位块、前缀稳定与读取状态语义;估计器需另行配置端点",
|
|
1379
1226
|
"profile.custom": "Custom/实验模式",
|
|
1380
1227
|
"profile.native": "原生对照",
|
|
@@ -1471,25 +1318,6 @@ window.__ModuleLoader__.load({
|
|
|
1471
1318
|
"estimator.apiKey.set": "Set · type a new value to overwrite",
|
|
1472
1319
|
"estimator.apiKey.clear": "Clear",
|
|
1473
1320
|
"estimator.apiKey.overwrite": "A secret is stored; type a new value and blur to overwrite it.",
|
|
1474
|
-
"review.title": "Review mode (beta)",
|
|
1475
|
-
"review.description": "When enabled, edge-band and high-impact reduction candidates no longer apply automatically: they queue for manual approval and execute in one merged batch at the next turn boundary after approval. Unhandled proposals expire after the configured number of turns. Ships with the TokenPilot-inspired profile only, off by default.",
|
|
1476
|
-
"review.enabled": "Review mode",
|
|
1477
|
-
"review.enabled.on": "On (proposals wait for manual approval)",
|
|
1478
|
-
"review.enabled.off": "Off (default, fully automatic)",
|
|
1479
|
-
"review.timeoutTurns": "Proposal expiry (turns)",
|
|
1480
|
-
"review.alpha": "Cache-hit discount α",
|
|
1481
|
-
"review.highImpact": "High-impact threshold (tokens)",
|
|
1482
|
-
"review.badge": "Review",
|
|
1483
|
-
"review.summary.autoApplied": "Auto-applied",
|
|
1484
|
-
"review.summary.reviewApplied": "Review-applied",
|
|
1485
|
-
"review.summary.expired": "Expired",
|
|
1486
|
-
"review.summary.voided": "Voided",
|
|
1487
|
-
"review.row.payback": "Payback",
|
|
1488
|
-
"review.row.expectedSaving": "Expected saving",
|
|
1489
|
-
"review.row.estimated": "estimated",
|
|
1490
|
-
"review.action.approve": "Approve",
|
|
1491
|
-
"review.action.reject": "Reject",
|
|
1492
|
-
"review.action.ignore": "Ignore",
|
|
1493
1321
|
"detail.tokenpilot-inspired": "Layered on Balanced: dedupe pointers, recovery exemption, summary locators, prefix stabilization, and read-state semantics; the estimator needs an endpoint configured separately",
|
|
1494
1322
|
"profile.custom": "Custom / Experimental",
|
|
1495
1323
|
"profile.native": "Native baseline",
|
|
@@ -1553,7 +1381,9 @@ window.__ModuleLoader__.load({
|
|
|
1553
1381
|
//#region src/client/preset-options.ts
|
|
1554
1382
|
/** The namespace key holding every tokenpilot-inspired sub-capability override. */
|
|
1555
1383
|
const PRESET_OPTIONS_KEY = "presetOptions";
|
|
1556
|
-
/** Every field a patch may address, in the schema's own order.
|
|
1384
|
+
/** Every field a patch may address, in the schema's own order. The retired
|
|
1385
|
+
* review-gate keys are deliberately absent: nothing writes them any more, and
|
|
1386
|
+
* a stored document that still carries them is tolerated by the decoders. */
|
|
1557
1387
|
const PRESET_OPTION_KEYS = [
|
|
1558
1388
|
"dedupeToolResults",
|
|
1559
1389
|
"summaryLocator",
|
|
@@ -1565,10 +1395,6 @@ window.__ModuleLoader__.load({
|
|
|
1565
1395
|
"estimatorBaseUrl",
|
|
1566
1396
|
"estimatorApiKey",
|
|
1567
1397
|
"estimatorTimeoutMs",
|
|
1568
|
-
"reviewMode",
|
|
1569
|
-
"reviewTimeoutTurns",
|
|
1570
|
-
"cacheHitDiscountAlpha",
|
|
1571
|
-
"reviewHighImpactTokens",
|
|
1572
1398
|
"advisorMode",
|
|
1573
1399
|
"advisorTimeoutMs",
|
|
1574
1400
|
"advisorRefreshTurns",
|
|
@@ -1628,314 +1454,6 @@ window.__ModuleLoader__.load({
|
|
|
1628
1454
|
});
|
|
1629
1455
|
}
|
|
1630
1456
|
//#endregion
|
|
1631
|
-
//#region src/client/ReviewOverlay.tsx
|
|
1632
|
-
/**
|
|
1633
|
-
* TokenPilot-inspired R4: the review floating window.
|
|
1634
|
-
*
|
|
1635
|
-
* Mounted on the host `shell.overlay` slot (dsh-tidychat precedent: the layer
|
|
1636
|
-
* is click-through by default and only the card opts back in), showing a
|
|
1637
|
-
* bottom-right badge while any session has pending proposals and a card with
|
|
1638
|
-
* the four-state summary row plus one row per proposal. Every 10s it polls the
|
|
1639
|
-
* review-queue route; when the queue is empty or review mode is off the
|
|
1640
|
-
* component renders null, so it never disturbs the session.
|
|
1641
|
-
*
|
|
1642
|
-
* Styles carry the `dsh-cc-review-` prefix and ride a one-shot style tag.
|
|
1643
|
-
*/
|
|
1644
|
-
const QUEUE_ROUTES = ["/api/dsh-context-compression-improved/review-queue", "/endpoint/dsh-context-compression-improved/review-queue"];
|
|
1645
|
-
const DECIDE_ROUTES = ["/api/dsh-context-compression-improved/review-decide", "/endpoint/dsh-context-compression-improved/review-decide"];
|
|
1646
|
-
const CSS = `
|
|
1647
|
-
.dsh-cc-review-badge {
|
|
1648
|
-
position: fixed;
|
|
1649
|
-
right: 20px;
|
|
1650
|
-
bottom: 20px;
|
|
1651
|
-
z-index: 70;
|
|
1652
|
-
pointer-events: auto;
|
|
1653
|
-
box-sizing: border-box;
|
|
1654
|
-
min-width: 34px;
|
|
1655
|
-
height: 34px;
|
|
1656
|
-
padding: 0 10px;
|
|
1657
|
-
border-radius: 17px;
|
|
1658
|
-
border: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.4));
|
|
1659
|
-
background: var(--dsw-alias-bg-layer-3, #fff);
|
|
1660
|
-
color: var(--dsw-alias-label-primary, #222);
|
|
1661
|
-
font-size: 13px;
|
|
1662
|
-
display: flex;
|
|
1663
|
-
align-items: center;
|
|
1664
|
-
justify-content: center;
|
|
1665
|
-
gap: 6px;
|
|
1666
|
-
cursor: pointer;
|
|
1667
|
-
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
|
|
1668
|
-
}
|
|
1669
|
-
.dsh-cc-review-card {
|
|
1670
|
-
position: fixed;
|
|
1671
|
-
right: 20px;
|
|
1672
|
-
bottom: 62px;
|
|
1673
|
-
z-index: 70;
|
|
1674
|
-
pointer-events: auto;
|
|
1675
|
-
box-sizing: border-box;
|
|
1676
|
-
width: min(420px, calc(100vw - 40px));
|
|
1677
|
-
max-height: min(60vh, 520px);
|
|
1678
|
-
overflow: auto;
|
|
1679
|
-
background: var(--dsw-alias-bg-layer-3, #fff);
|
|
1680
|
-
border: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.4));
|
|
1681
|
-
border-radius: 12px;
|
|
1682
|
-
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
|
|
1683
|
-
padding: 12px 14px;
|
|
1684
|
-
color: var(--dsw-alias-label-primary, #222);
|
|
1685
|
-
font-size: 13px;
|
|
1686
|
-
}
|
|
1687
|
-
.dsh-cc-review-title {
|
|
1688
|
-
font-weight: 600;
|
|
1689
|
-
margin: 0 0 6px;
|
|
1690
|
-
font-size: 13px;
|
|
1691
|
-
}
|
|
1692
|
-
.dsh-cc-review-summary {
|
|
1693
|
-
display: flex;
|
|
1694
|
-
flex-wrap: wrap;
|
|
1695
|
-
gap: 4px 12px;
|
|
1696
|
-
color: var(--dsw-alias-label-tertiary, #888);
|
|
1697
|
-
font-size: 12px;
|
|
1698
|
-
margin-bottom: 8px;
|
|
1699
|
-
}
|
|
1700
|
-
.dsh-cc-review-row {
|
|
1701
|
-
border-top: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.25));
|
|
1702
|
-
padding: 8px 0;
|
|
1703
|
-
}
|
|
1704
|
-
.dsh-cc-review-row-meta {
|
|
1705
|
-
color: var(--dsw-alias-label-tertiary, #888);
|
|
1706
|
-
font-size: 12px;
|
|
1707
|
-
margin-bottom: 4px;
|
|
1708
|
-
}
|
|
1709
|
-
.dsh-cc-review-actions {
|
|
1710
|
-
display: flex;
|
|
1711
|
-
gap: 8px;
|
|
1712
|
-
}
|
|
1713
|
-
.dsh-cc-review-btn {
|
|
1714
|
-
appearance: none;
|
|
1715
|
-
border: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.4));
|
|
1716
|
-
background: transparent;
|
|
1717
|
-
color: inherit;
|
|
1718
|
-
border-radius: 6px;
|
|
1719
|
-
padding: 3px 10px;
|
|
1720
|
-
font-size: 12px;
|
|
1721
|
-
cursor: pointer;
|
|
1722
|
-
}
|
|
1723
|
-
.dsh-cc-review-btn-primary {
|
|
1724
|
-
background: var(--dsw-alias-state-business-primary, #3b82f6);
|
|
1725
|
-
border-color: transparent;
|
|
1726
|
-
color: #fff;
|
|
1727
|
-
}
|
|
1728
|
-
`;
|
|
1729
|
-
function injectOnce() {
|
|
1730
|
-
const tag = document.createElement("style");
|
|
1731
|
-
tag.setAttribute("data-plugin-css", "dsh-context-compression-improved-review");
|
|
1732
|
-
tag.textContent = CSS;
|
|
1733
|
-
document.head.appendChild(tag);
|
|
1734
|
-
return () => {
|
|
1735
|
-
tag.remove();
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
async function fetchJson(route, init) {
|
|
1739
|
-
const response = await fetch(route, {
|
|
1740
|
-
headers: { "cache-control": "no-cache" },
|
|
1741
|
-
...init
|
|
1742
|
-
});
|
|
1743
|
-
if (!response.ok) return void 0;
|
|
1744
|
-
return response.json();
|
|
1745
|
-
}
|
|
1746
|
-
async function pollQueue() {
|
|
1747
|
-
for (const route of QUEUE_ROUTES) {
|
|
1748
|
-
const body = await fetchJson(route);
|
|
1749
|
-
if (body?.ok === true) return {
|
|
1750
|
-
pending: body.pending ?? [],
|
|
1751
|
-
summary: body.summary
|
|
1752
|
-
};
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
async function postDecide(proposal, decision) {
|
|
1756
|
-
for (const route of DECIDE_ROUTES) try {
|
|
1757
|
-
const response = await fetch(route, {
|
|
1758
|
-
method: "POST",
|
|
1759
|
-
headers: { "content-type": "application/json" },
|
|
1760
|
-
body: JSON.stringify({
|
|
1761
|
-
sessionId: proposal.sessionId,
|
|
1762
|
-
proposalId: proposal.id,
|
|
1763
|
-
decision
|
|
1764
|
-
})
|
|
1765
|
-
});
|
|
1766
|
-
if (response.status !== 404) return response.ok;
|
|
1767
|
-
} catch {}
|
|
1768
|
-
return false;
|
|
1769
|
-
}
|
|
1770
|
-
/**
|
|
1771
|
-
* Slot factory helper: the client entry is a .ts file and cannot carry JSX,
|
|
1772
|
-
* so the element construction lives here.
|
|
1773
|
-
*/
|
|
1774
|
-
function renderReviewOverlay(scope, t) {
|
|
1775
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewOverlay, {
|
|
1776
|
-
scope,
|
|
1777
|
-
t
|
|
1778
|
-
});
|
|
1779
|
-
}
|
|
1780
|
-
/**
|
|
1781
|
-
* The floating window itself: renders null (and stays silent) while review
|
|
1782
|
-
* mode is off or nothing is pending.
|
|
1783
|
-
*/
|
|
1784
|
-
function ReviewOverlay({ scope, t }) {
|
|
1785
|
-
const [reviewMode, setReviewMode] = (0, react.useState)(false);
|
|
1786
|
-
const [pending, setPending] = (0, react.useState)([]);
|
|
1787
|
-
const [summary, setSummary] = (0, react.useState)();
|
|
1788
|
-
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
1789
|
-
const [busy, setBusy] = (0, react.useState)(false);
|
|
1790
|
-
(0, react.useEffect)(injectOnce, []);
|
|
1791
|
-
(0, react.useEffect)(() => {
|
|
1792
|
-
const pull = () => {
|
|
1793
|
-
try {
|
|
1794
|
-
const snapshot = scope.getSnapshot();
|
|
1795
|
-
setReviewMode(snapshot.status === "ready" && snapshot.value?.presetOptions?.reviewMode === true);
|
|
1796
|
-
} catch {
|
|
1797
|
-
setReviewMode(false);
|
|
1798
|
-
}
|
|
1799
|
-
};
|
|
1800
|
-
pull();
|
|
1801
|
-
let unsubscribe;
|
|
1802
|
-
try {
|
|
1803
|
-
unsubscribe = scope.subscribe(pull);
|
|
1804
|
-
} catch {
|
|
1805
|
-
unsubscribe = () => {};
|
|
1806
|
-
}
|
|
1807
|
-
return unsubscribe;
|
|
1808
|
-
}, [scope]);
|
|
1809
|
-
(0, react.useEffect)(() => {
|
|
1810
|
-
if (!reviewMode) return;
|
|
1811
|
-
let alive = true;
|
|
1812
|
-
let timer;
|
|
1813
|
-
const tick = () => {
|
|
1814
|
-
pollQueue().then((result) => {
|
|
1815
|
-
if (!alive) return;
|
|
1816
|
-
setPending(result?.pending ?? []);
|
|
1817
|
-
setSummary(result?.summary);
|
|
1818
|
-
timer = setTimeout(tick, 1e4);
|
|
1819
|
-
});
|
|
1820
|
-
};
|
|
1821
|
-
tick();
|
|
1822
|
-
return () => {
|
|
1823
|
-
alive = false;
|
|
1824
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
1825
|
-
};
|
|
1826
|
-
}, [reviewMode]);
|
|
1827
|
-
if (!reviewMode || pending.length === 0) return null;
|
|
1828
|
-
const decide = (proposal, decision) => {
|
|
1829
|
-
setBusy(true);
|
|
1830
|
-
postDecide(proposal, decision).then(() => {
|
|
1831
|
-
return pollQueue().then((result) => {
|
|
1832
|
-
setPending(result?.pending ?? []);
|
|
1833
|
-
setSummary(result?.summary);
|
|
1834
|
-
setBusy(false);
|
|
1835
|
-
});
|
|
1836
|
-
}).catch(() => {
|
|
1837
|
-
setBusy(false);
|
|
1838
|
-
});
|
|
1839
|
-
};
|
|
1840
|
-
const seqRange = (proposal) => {
|
|
1841
|
-
const seqs = proposal.items.map((item) => item.seq);
|
|
1842
|
-
const min = Math.min(...seqs);
|
|
1843
|
-
const max = Math.max(...seqs);
|
|
1844
|
-
return min === max ? `#${String(min)}` : `#${String(min)}–#${String(max)}`;
|
|
1845
|
-
};
|
|
1846
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1847
|
-
className: "dsh-cc-review-card",
|
|
1848
|
-
children: [
|
|
1849
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1850
|
-
className: "dsh-cc-review-title",
|
|
1851
|
-
children: t("review.title")
|
|
1852
|
-
}),
|
|
1853
|
-
summary !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1854
|
-
className: "dsh-cc-review-summary",
|
|
1855
|
-
children: [
|
|
1856
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
1857
|
-
t("review.summary.autoApplied"),
|
|
1858
|
-
": ",
|
|
1859
|
-
String(summary.autoApplied)
|
|
1860
|
-
] }),
|
|
1861
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
1862
|
-
t("review.summary.reviewApplied"),
|
|
1863
|
-
": ",
|
|
1864
|
-
String(summary.reviewApplied)
|
|
1865
|
-
] }),
|
|
1866
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
1867
|
-
t("review.summary.expired"),
|
|
1868
|
-
": ",
|
|
1869
|
-
String(summary.expired)
|
|
1870
|
-
] }),
|
|
1871
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
1872
|
-
t("review.summary.voided"),
|
|
1873
|
-
": ",
|
|
1874
|
-
String(summary.voided)
|
|
1875
|
-
] })
|
|
1876
|
-
]
|
|
1877
|
-
}) : null,
|
|
1878
|
-
pending.map((proposal) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1879
|
-
className: "dsh-cc-review-row",
|
|
1880
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1881
|
-
className: "dsh-cc-review-row-meta",
|
|
1882
|
-
children: [
|
|
1883
|
-
proposal.kind,
|
|
1884
|
-
" · ",
|
|
1885
|
-
seqRange(proposal),
|
|
1886
|
-
" · R ≈ ",
|
|
1887
|
-
String(proposal.benefit.recoveredTokens),
|
|
1888
|
-
proposal.benefit.paybackTurns !== void 0 ? ` · ${t("review.row.payback")}: ${String(Math.round(proposal.benefit.paybackTurns * 100) / 100)}` : "",
|
|
1889
|
-
proposal.benefit.expectedSaving !== void 0 ? ` · ${t("review.row.expectedSaving")}: ${String(Math.round(proposal.benefit.expectedSaving))} (${t("review.row.estimated")})` : ""
|
|
1890
|
-
]
|
|
1891
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1892
|
-
className: "dsh-cc-review-actions",
|
|
1893
|
-
children: [
|
|
1894
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1895
|
-
type: "button",
|
|
1896
|
-
className: "dsh-cc-review-btn dsh-cc-review-btn-primary",
|
|
1897
|
-
disabled: busy,
|
|
1898
|
-
onClick: () => {
|
|
1899
|
-
decide(proposal, "approved");
|
|
1900
|
-
},
|
|
1901
|
-
children: t("review.action.approve")
|
|
1902
|
-
}),
|
|
1903
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1904
|
-
type: "button",
|
|
1905
|
-
className: "dsh-cc-review-btn",
|
|
1906
|
-
disabled: busy,
|
|
1907
|
-
onClick: () => {
|
|
1908
|
-
decide(proposal, "rejected");
|
|
1909
|
-
},
|
|
1910
|
-
children: t("review.action.reject")
|
|
1911
|
-
}),
|
|
1912
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1913
|
-
type: "button",
|
|
1914
|
-
className: "dsh-cc-review-btn",
|
|
1915
|
-
disabled: busy,
|
|
1916
|
-
onClick: () => {
|
|
1917
|
-
decide(proposal, "ignored");
|
|
1918
|
-
},
|
|
1919
|
-
children: t("review.action.ignore")
|
|
1920
|
-
})
|
|
1921
|
-
]
|
|
1922
|
-
})]
|
|
1923
|
-
}, proposal.id))
|
|
1924
|
-
]
|
|
1925
|
-
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1926
|
-
type: "button",
|
|
1927
|
-
className: "dsh-cc-review-badge",
|
|
1928
|
-
onClick: () => {
|
|
1929
|
-
setExpanded((value) => !value);
|
|
1930
|
-
},
|
|
1931
|
-
children: [
|
|
1932
|
-
t("review.badge"),
|
|
1933
|
-
" ",
|
|
1934
|
-
String(pending.length)
|
|
1935
|
-
]
|
|
1936
|
-
})] });
|
|
1937
|
-
}
|
|
1938
|
-
//#endregion
|
|
1939
1457
|
//#region src/client/index.ts
|
|
1940
1458
|
const inject = [
|
|
1941
1459
|
"slots",
|
|
@@ -1989,19 +1507,6 @@ window.__ModuleLoader__.load({
|
|
|
1989
1507
|
} catch (error) {
|
|
1990
1508
|
console.warn("[dsh-context-compression-improved] settings.section 注册失败(新宿主已收编):", error);
|
|
1991
1509
|
}
|
|
1992
|
-
try {
|
|
1993
|
-
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
1994
|
-
name: "shell.overlay",
|
|
1995
|
-
id: "context-compression-review"
|
|
1996
|
-
}, () => {
|
|
1997
|
-
return renderReviewOverlay(ctx.settingsScope.bind({
|
|
1998
|
-
namespace: NS,
|
|
1999
|
-
decode: decodeSettings
|
|
2000
|
-
}), ctx.locale.bind(NS));
|
|
2001
|
-
}));
|
|
2002
|
-
} catch (error) {
|
|
2003
|
-
console.warn("[dsh-context-compression-improved] shell.overlay 注册失败(宿主无浮层或已收编):", error);
|
|
2004
|
-
}
|
|
2005
1510
|
}
|
|
2006
1511
|
//#endregion
|
|
2007
1512
|
exports.apply = apply;
|
|
@@ -17,18 +17,12 @@ interface Config {
|
|
|
17
17
|
* covers both arrival orders.
|
|
18
18
|
*/
|
|
19
19
|
estimatorCatalogRoute?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Register the review pipeline's HTTP routes (pending-queue read + decide
|
|
22
|
-
* write) on this row. Same Bundle opt-in semantics as
|
|
23
|
-
* `estimatorCatalogRoute`; without the routes the floating window has no
|
|
24
|
-
* transport and simply never appears.
|
|
25
|
-
*/
|
|
26
|
-
reviewQueueRoute?: boolean;
|
|
27
20
|
/**
|
|
28
21
|
* Register the advisory advisor's read-only HTTP report route (decay
|
|
29
|
-
* figure, task summary, score distribution
|
|
30
|
-
* as `
|
|
31
|
-
* it on through the
|
|
22
|
+
* figure, task summary, score distribution, last benefit-model advice).
|
|
23
|
+
* Same Bundle opt-in semantics as `estimatorCatalogRoute`; the advisor
|
|
24
|
+
* itself stays off until the user turns it on through the
|
|
25
|
+
* `presetOptions.advisor*` settings keys.
|
|
32
26
|
*/
|
|
33
27
|
advisorReportRoute?: boolean;
|
|
34
28
|
}
|