@ljwei-stak/dsh-model-router 0.16.0 → 0.16.2
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/.dsh-plugin/client.js +314 -80
- package/.dsh-plugin/index.mjs +23 -17
- package/.dsh-plugin/shared/adaptive-feedback.mjs +120 -40
- package/.dsh-plugin/shared/dynamic-data-view.mjs +59 -4
- package/.dsh-plugin/shared/dynamic-data.mjs +161 -83
- package/.dsh-plugin/shared/latest-versions.mjs +3 -21
- package/.dsh-plugin/shared/official-tools-runtime.mjs +188 -41
- package/.dsh-plugin/shared/router-state.mjs +139 -38
- package/.dsh-plugin/shared/run-ledger.mjs +32 -11
- package/.dsh-plugin/shared/version-order.mjs +30 -0
- package/CHANGELOG.md +20 -0
- package/INSTALLATION_GUIDE.zh.md +12 -12
- package/README.md +9 -5
- package/README.zh.md +9 -5
- package/docs/ROUTING_ADAPTIVE_LEARNING.zh.md +2 -0
- package/docs/ROUTING_MATURITY.zh.md +76 -0
- package/package.json +3 -1
package/.dsh-plugin/client.js
CHANGED
|
@@ -1591,18 +1591,27 @@ function applyQualityBiases(routes, biases) {
|
|
|
1591
1591
|
var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
1592
1592
|
var clean3 = (value) => typeof value === "string" ? value.trim() : "";
|
|
1593
1593
|
var routeKey3 = (provider, model) => `${provider}\0${model}`;
|
|
1594
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1594
1595
|
function applyFeedbackProfile(routes, profile) {
|
|
1595
|
-
if (!Array.isArray(routes) ||
|
|
1596
|
+
if (!Array.isArray(routes) || !record(profile) || typeof profile.enabled !== "boolean") return routes;
|
|
1596
1597
|
return routes.map((route) => {
|
|
1597
|
-
if (!route
|
|
1598
|
+
if (!record(route)) return route;
|
|
1599
|
+
let base = route;
|
|
1600
|
+
if (Object.hasOwn(route, "preferenceAdjustments") || Object.hasOwn(route, "preferenceAdjustmentMeta")) {
|
|
1601
|
+
base = { ...route };
|
|
1602
|
+
delete base.preferenceAdjustments;
|
|
1603
|
+
delete base.preferenceAdjustmentMeta;
|
|
1604
|
+
}
|
|
1605
|
+
if (profile.enabled !== true || !record(profile.adjustments)) return base;
|
|
1598
1606
|
const key = routeKey3(clean3(route.provider), clean3(route.model));
|
|
1599
|
-
if (!Object.hasOwn(profile.adjustments, key)) return
|
|
1607
|
+
if (!Object.hasOwn(profile.adjustments, key)) return base;
|
|
1600
1608
|
const value = profile.adjustments[key];
|
|
1601
|
-
if (!
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1609
|
+
if (!record(value)) return base;
|
|
1610
|
+
const limit = finite2(profile.maxAdjustment) && profile.maxAdjustment >= 0 && profile.maxAdjustment <= 0.1 ? profile.maxAdjustment : 0.1;
|
|
1611
|
+
const adjustments = Object.fromEntries(Object.entries(value).filter(([, bias]) => finite2(bias) && Math.abs(bias) <= limit));
|
|
1612
|
+
if (!Object.keys(adjustments).length) return base;
|
|
1604
1613
|
return {
|
|
1605
|
-
...
|
|
1614
|
+
...base,
|
|
1606
1615
|
preferenceAdjustments: adjustments,
|
|
1607
1616
|
preferenceAdjustmentMeta: {
|
|
1608
1617
|
policyVersion: profile.policyVersion,
|
|
@@ -1613,7 +1622,11 @@ function applyFeedbackProfile(routes, profile) {
|
|
|
1613
1622
|
updatedAt: profile.updatedAt,
|
|
1614
1623
|
halfLifeDays: profile.halfLifeDays,
|
|
1615
1624
|
maxAdjustment: profile.maxAdjustment,
|
|
1616
|
-
window: profile.window
|
|
1625
|
+
window: profile.window,
|
|
1626
|
+
cellStats: Object.hasOwn(profile.cellStats ?? {}, key) ? profile.cellStats[key] : {},
|
|
1627
|
+
evaluatedAt: profile.evaluatedAt,
|
|
1628
|
+
decayRefreshMs: profile.decayRefreshMs,
|
|
1629
|
+
revisionSemantics: profile.revisionSemantics
|
|
1617
1630
|
}
|
|
1618
1631
|
};
|
|
1619
1632
|
});
|
|
@@ -1863,33 +1876,73 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
|
|
|
1863
1876
|
} }, "\u5220\u9664\u6B64\u6A21\u578B\u914D\u7F6E")), notice && /* @__PURE__ */ import_react.default.createElement("p", { className: notice.tone === "error" ? "mr-error" : "mr-profile-success", role: notice.tone === "error" ? "alert" : "status" }, notice.text), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption" }, "\u8D28\u91CF\u8BC4\u5206\u548C\u4EF7\u683C\u90FD\u662F\u7528\u6237\u63D0\u4F9B\u7684\u4F30\u503C\u3002\u672A\u586B\u5199\u5355\u4EF7\u65F6\u663E\u793A\u201C\u4EF7\u683C\u5F85\u914D\u7F6E\u201D\uFF1B\u9884\u7B97\u53EA\u5F71\u54CD\u672C\u5730\u89C4\u5212\uFF0C\u4E0D\u9650\u5236\u5B9E\u9645\u8D26\u5355\u3002CLI \u6A21\u578B\u540D\u987B\u4E0E\u5382\u5546\u5DE5\u5177\u6838\u5BF9\u3002\u6267\u884C\u65B9\u5F0F\u51B3\u5B9A\u8BE5\u6A21\u578B\u6536\u5230\u4EFB\u52A1\u65F6\u8D70\u5B98\u65B9\u65E0\u754C\u9762\u5DE5\u5177\u8FD8\u662F\u6A21\u578B\u76EE\u5F55 API\uFF1B\u5B98\u65B9\u5DE5\u5177\u5931\u8D25\u65F6\u4ECD\u4F1A\u56DE\u9000 API\u3002\u8BA1\u8D39\u65B9\u5F0F\u9ED8\u8BA4\u8BA2\u9605\u4F18\u5148\uFF1A\u5148\u7528 CLI \u8D26\u53F7\u767B\u5F55\u6216\u7F16\u7A0B\u5957\u9910 Key \u8DEF\u7EBF\uFF0C\u8BA2\u9605\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\u540C\u4E00\u6B65\u9AA4\u81EA\u52A8\u6539\u7528 API Key\uFF0C\u5E76\u8BB0\u5165\u8FD0\u884C\u5386\u53F2\u3002"))));
|
|
1864
1877
|
}
|
|
1865
1878
|
|
|
1866
|
-
// .dsh-plugin/
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
const
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1879
|
+
// .dsh-plugin/shared/version-order.mjs
|
|
1880
|
+
var VERSION = /^(\d{1,6})\.(\d{1,6})\.(\d{1,6})(?:-[0-9A-Za-z.-]{1,64})?$/;
|
|
1881
|
+
function compareReleaseVersions(left, right) {
|
|
1882
|
+
const parse = (value) => {
|
|
1883
|
+
const match = VERSION.exec(String(value ?? ""));
|
|
1884
|
+
return match ? { parts: match.slice(1, 4).map(Number), pre: String(value).includes("-") } : null;
|
|
1885
|
+
};
|
|
1886
|
+
const a = parse(left);
|
|
1887
|
+
const b2 = parse(right);
|
|
1888
|
+
if (!a || !b2) return null;
|
|
1889
|
+
for (let index = 0; index < 3; index += 1) {
|
|
1890
|
+
if (a.parts[index] !== b2.parts[index]) return a.parts[index] > b2.parts[index] ? 1 : -1;
|
|
1875
1891
|
}
|
|
1892
|
+
if (a.pre !== b2.pre) return a.pre ? -1 : 1;
|
|
1876
1893
|
return 0;
|
|
1877
1894
|
}
|
|
1895
|
+
|
|
1896
|
+
// .dsh-plugin/client/tool-install-state.mjs
|
|
1878
1897
|
function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVersion = null }) {
|
|
1879
1898
|
const running = job?.status === "running";
|
|
1880
1899
|
const installed = probe?.installed === true;
|
|
1881
|
-
const order = installed && latestVersion ?
|
|
1900
|
+
const order = installed && latestVersion ? compareReleaseVersions(probe.version, latestVersion) : null;
|
|
1882
1901
|
const ready = readiness?.ready === true;
|
|
1883
1902
|
const desktop = tool.manager === "signed-windows-installer";
|
|
1884
1903
|
const noRunner = desktop || tool.headlessAdapter === true;
|
|
1885
1904
|
const repair = installed && !noRunner && readiness?.ready === false;
|
|
1886
1905
|
const label = running ? "\u5B89\u88C5\u4E2D\u2026" : !installed ? job?.status === "failed" ? "\u91CD\u8BD5\u5B89\u88C5" : desktop ? "\u4E0B\u8F7D\u6700\u65B0\u5B89\u88C5\u5668" : "\u4E00\u952E\u5B89\u88C5\u6700\u65B0\u7248" : order === -1 ? `\u66F4\u65B0\u5230\u6700\u65B0\u7248 ${latestVersion}` : order === 1 ? "\u5DF2\u9AD8\u4E8E\u6700\u65B0\u6B63\u5F0F\u7248" : repair ? "\u4FEE\u590D\u5B98\u65B9\u6267\u884C\u5165\u53E3" : order === 0 ? "\u5DF2\u662F\u6700\u65B0\u7248\u672C" : "\u5B89\u88C5\u6700\u65B0\u7248";
|
|
1887
1906
|
const current = order === 0 && (ready || noRunner);
|
|
1907
|
+
const interactive = probeStatus === "ready" || probeStatus === "refreshing";
|
|
1888
1908
|
return {
|
|
1889
1909
|
label,
|
|
1890
|
-
disabled:
|
|
1910
|
+
disabled: !interactive || running || installed && (order === 1 || current)
|
|
1891
1911
|
};
|
|
1892
1912
|
}
|
|
1913
|
+
function installClickRefusal({ tool, submitting = false, running = false } = {}) {
|
|
1914
|
+
if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
|
|
1915
|
+
if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
|
|
1916
|
+
if (submitting || running) return "\u8BE5\u5DE5\u5177\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002";
|
|
1917
|
+
return "";
|
|
1918
|
+
}
|
|
1919
|
+
function payloadError(payload, fallback) {
|
|
1920
|
+
if (!payload || typeof payload !== "object") return fallback;
|
|
1921
|
+
if (typeof payload.error === "string" && payload.error.trim()) return payload.error.trim();
|
|
1922
|
+
const message = payload.error?.message;
|
|
1923
|
+
if (typeof message === "string" && message.trim()) return message.trim();
|
|
1924
|
+
return fallback;
|
|
1925
|
+
}
|
|
1926
|
+
function acceptedInstallJob(response) {
|
|
1927
|
+
const fallback = "\u5B89\u88C5\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002";
|
|
1928
|
+
if (!response || typeof response !== "object") return { job: null, error: fallback };
|
|
1929
|
+
let payload = response;
|
|
1930
|
+
if (payload.ok === false) return { job: null, error: payloadError(payload, fallback) };
|
|
1931
|
+
if (payload.ok === true && payload.value && typeof payload.value === "object") {
|
|
1932
|
+
payload = payload.value;
|
|
1933
|
+
if (payload.ok === false) return { job: null, error: payloadError(payload, fallback) };
|
|
1934
|
+
if (payload.ok === true && payload.value && typeof payload.value === "object") payload = payload.value;
|
|
1935
|
+
}
|
|
1936
|
+
if (payload.accepted === true && payload.job && typeof payload.job === "object") return { job: payload.job, error: "" };
|
|
1937
|
+
return { job: null, error: payloadError(payload, fallback) };
|
|
1938
|
+
}
|
|
1939
|
+
function shouldApplyInstallStatus(localJob, remoteJob) {
|
|
1940
|
+
if (!remoteJob || typeof remoteJob !== "object") return false;
|
|
1941
|
+
const localStarted = typeof localJob?.startedAt === "string" ? localJob.startedAt : "";
|
|
1942
|
+
const remoteStarted = typeof remoteJob.startedAt === "string" ? remoteJob.startedAt : "";
|
|
1943
|
+
if (!localStarted || !remoteStarted) return true;
|
|
1944
|
+
return remoteStarted >= localStarted;
|
|
1945
|
+
}
|
|
1893
1946
|
|
|
1894
1947
|
// .dsh-plugin/client/router-insights.jsx
|
|
1895
1948
|
var import_react2 = __toESM(require("react"), 1);
|
|
@@ -2176,8 +2229,10 @@ function feedbackRatingArguments(run, item, direction) {
|
|
|
2176
2229
|
var nonnegative2 = (value) => Number.isFinite(value) && value >= 0 ? value : 0;
|
|
2177
2230
|
function learningView(learning, settings = {}) {
|
|
2178
2231
|
return {
|
|
2179
|
-
available: Boolean(learning && typeof learning === "object"),
|
|
2180
|
-
|
|
2232
|
+
available: Boolean(learning && typeof learning === "object" && !Array.isArray(learning)),
|
|
2233
|
+
// Current settings govern the next plan; a failed refresh must not make an
|
|
2234
|
+
// older profile claim that a newly disabled policy is still enabled.
|
|
2235
|
+
enabled: adaptiveSettingValue(settings, "feedbackLearningEnabled") !== false,
|
|
2181
2236
|
feedbackCount: nonnegative2(learning?.feedbackCount),
|
|
2182
2237
|
ignoredCount: nonnegative2(learning?.ignoredCount),
|
|
2183
2238
|
effectiveWeight: nonnegative2(learning?.effectiveWeight),
|
|
@@ -2185,18 +2240,71 @@ function learningView(learning, settings = {}) {
|
|
|
2185
2240
|
resetAt: nonnegative2(adaptiveSettingValue(settings, "feedbackResetAt"))
|
|
2186
2241
|
};
|
|
2187
2242
|
}
|
|
2243
|
+
function learningEvidenceRows(learning, limit = 12) {
|
|
2244
|
+
const cells = learning?.cellStats;
|
|
2245
|
+
if (!cells || typeof cells !== "object" || Array.isArray(cells)) return { rows: [], total: 0 };
|
|
2246
|
+
const rows = [];
|
|
2247
|
+
for (const [key, domains] of Object.entries(cells)) {
|
|
2248
|
+
const identity = key.split("\0");
|
|
2249
|
+
if (identity.length !== 2 || identity.some((part) => !part.trim()) || !domains || typeof domains !== "object" || Array.isArray(domains)) continue;
|
|
2250
|
+
for (const [domain, cell] of Object.entries(domains)) {
|
|
2251
|
+
if (!domain.trim() || !cell || typeof cell !== "object" || Array.isArray(cell) || !Number.isFinite(cell.adjustment) || Math.abs(cell.adjustment) > 0.1 || ["feedbackCount", "positiveCount", "negativeCount", "effectiveWeight", "effectiveSampleSize"].some((name) => !Number.isFinite(cell[name]) || cell[name] < 0) || !Number.isFinite(cell.shrinkage) || cell.shrinkage < 0 || cell.shrinkage > 1) continue;
|
|
2252
|
+
rows.push({
|
|
2253
|
+
id: JSON.stringify([key, domain]),
|
|
2254
|
+
route: identity.map((part) => part.slice(0, 100)).join("/"),
|
|
2255
|
+
domain: domain.slice(0, 80),
|
|
2256
|
+
feedbackCount: nonnegative2(cell.feedbackCount),
|
|
2257
|
+
positiveCount: nonnegative2(cell.positiveCount),
|
|
2258
|
+
negativeCount: nonnegative2(cell.negativeCount),
|
|
2259
|
+
effectiveWeight: nonnegative2(cell.effectiveWeight),
|
|
2260
|
+
effectiveSampleSize: nonnegative2(cell.effectiveSampleSize),
|
|
2261
|
+
shrinkage: Number.isFinite(cell.shrinkage) && cell.shrinkage >= 0 && cell.shrinkage <= 1 ? cell.shrinkage : 0,
|
|
2262
|
+
adjustment: cell.adjustment
|
|
2263
|
+
});
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
rows.sort((left, right) => left.route === right.route ? left.domain.localeCompare(right.domain) : left.route.localeCompare(right.route));
|
|
2267
|
+
const count = Number.isInteger(limit) && limit > 0 ? Math.min(limit, 50) : 12;
|
|
2268
|
+
return { rows: rows.slice(0, count), total: rows.length };
|
|
2269
|
+
}
|
|
2270
|
+
var EXCLUSION_LABELS = Object.freeze({
|
|
2271
|
+
"unrated": "\u5C1A\u672A\u8BC4\u4EF7\uFF08\u4E0D\u662F\u4E0D\u6EE1\u610F\uFF09",
|
|
2272
|
+
"not-successful": "\u6CA1\u6709\u6210\u529F\u6267\u884C\u7ED3\u679C",
|
|
2273
|
+
"cli-model-unverified": "CLI \u5B9E\u9645\u6A21\u578B\u672A\u6838\u9A8C",
|
|
2274
|
+
"before-reset": "\u7ED3\u679C\u65E9\u4E8E\u5B66\u4E60\u8D77\u70B9",
|
|
2275
|
+
"superseded": "\u5DF2\u88AB\u540C\u4E00\u7ED3\u679C\u7684\u65B0\u8BB0\u5F55\u66FF\u4EE3",
|
|
2276
|
+
"missing-identity": "\u7F3A\u5C11\u8FD0\u884C\u6216\u6B65\u9AA4\u6807\u8BC6",
|
|
2277
|
+
"invalid-route": "\u8DEF\u7EBF\u6807\u8BC6\u65E0\u6548",
|
|
2278
|
+
"invalid-time": "\u7ED3\u679C\u6216\u8BC4\u4EF7\u65F6\u95F4\u65E0\u6548",
|
|
2279
|
+
"future-time": "\u65F6\u95F4\u665A\u4E8E\u5F53\u524D\u65F6\u523B"
|
|
2280
|
+
});
|
|
2281
|
+
function learningExclusionRows(learning) {
|
|
2282
|
+
return Object.entries(EXCLUSION_LABELS).flatMap(([reason, label]) => {
|
|
2283
|
+
const count = nonnegative2(learning?.exclusionReasons?.[reason]);
|
|
2284
|
+
return count > 0 ? [{ reason, label, count }] : [];
|
|
2285
|
+
});
|
|
2286
|
+
}
|
|
2188
2287
|
var STATUS_LABEL = Object.freeze({ disabled: "\u672A\u542F\u7528", missing: "\u5C1A\u65E0\u5FEB\u7167", fresh: "\u5FEB\u7167\u6709\u6548", stale: "\u5FEB\u7167\u8FC7\u671F", error: "\u66F4\u65B0\u5931\u8D25" });
|
|
2189
|
-
|
|
2190
|
-
|
|
2288
|
+
var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set(["refresh-failed", "snapshot-rollback-rejected", "storage-failed", "refresh-interrupted"]);
|
|
2289
|
+
var positiveTime = (value) => Number.isFinite(value) && value > 0 ? value : null;
|
|
2290
|
+
function dynamicSourceView(source, enabled = true) {
|
|
2291
|
+
const status = enabled === false ? "disabled" : Object.hasOwn(STATUS_LABEL, source?.status ?? "") ? source.status : "missing";
|
|
2191
2292
|
let publicSource = "";
|
|
2192
|
-
if (typeof source?.source === "string") publicSource = publicEndpointDraft("pricingSnapshotEndpoint", source.source);
|
|
2293
|
+
if (enabled !== false && typeof source?.source === "string") publicSource = publicEndpointDraft("pricingSnapshotEndpoint", source.source);
|
|
2193
2294
|
return {
|
|
2194
2295
|
status,
|
|
2195
2296
|
label: STATUS_LABEL[status],
|
|
2196
2297
|
source: publicSource,
|
|
2197
|
-
version: typeof source?.version === "string" ? source.version.slice(0, 160) : null,
|
|
2198
|
-
verifiedAt: Number.isFinite(source?.verifiedAt) && source.verifiedAt > 0 ? source.verifiedAt : null,
|
|
2199
|
-
count: nonnegative2(source?.modelCount ?? source?.rowCount)
|
|
2298
|
+
version: enabled !== false && typeof source?.version === "string" ? source.version.slice(0, 160) : null,
|
|
2299
|
+
verifiedAt: enabled !== false && Number.isFinite(source?.verifiedAt) && source.verifiedAt > 0 ? source.verifiedAt : null,
|
|
2300
|
+
count: enabled === false ? 0 : nonnegative2(source?.modelCount ?? source?.rowCount),
|
|
2301
|
+
refreshing: enabled !== false && source?.refreshing === true,
|
|
2302
|
+
pending: enabled !== false && source?.pending === true,
|
|
2303
|
+
lastAttemptAt: enabled === false ? null : positiveTime(source?.lastAttemptAt),
|
|
2304
|
+
lastSuccessAt: enabled === false ? null : positiveTime(source?.lastSuccessAt),
|
|
2305
|
+
errorCode: enabled !== false && PUBLIC_ERROR_CODES.has(source?.error) ? source.error : "",
|
|
2306
|
+
endpoint: enabled === false ? "" : publicEndpointDraft("pricingSnapshotEndpoint", source?.configuredEndpoint ?? source?.endpoint ?? ""),
|
|
2307
|
+
lastGoodEndpoint: enabled === false ? "" : publicEndpointDraft("pricingSnapshotEndpoint", source?.lastGoodEndpoint ?? "")
|
|
2200
2308
|
};
|
|
2201
2309
|
}
|
|
2202
2310
|
|
|
@@ -2234,21 +2342,36 @@ function Meter({ label, meter }) {
|
|
|
2234
2342
|
function useSettingsWriter(settingsScope) {
|
|
2235
2343
|
const [snapshot, setSnapshot] = import_react2.default.useState(() => settingsScope.getSnapshot());
|
|
2236
2344
|
const [notice, setNotice] = import_react2.default.useState("");
|
|
2345
|
+
const [busy, setBusy] = import_react2.default.useState(false);
|
|
2346
|
+
const pending = import_react2.default.useRef(false);
|
|
2347
|
+
const mounted = import_react2.default.useRef(true);
|
|
2348
|
+
import_react2.default.useEffect(() => {
|
|
2349
|
+
mounted.current = true;
|
|
2350
|
+
return () => {
|
|
2351
|
+
mounted.current = false;
|
|
2352
|
+
};
|
|
2353
|
+
}, []);
|
|
2237
2354
|
import_react2.default.useEffect(() => settingsScope.subscribe(() => setSnapshot(settingsScope.getSnapshot())), [settingsScope]);
|
|
2238
|
-
const writable = snapshot.status === "ready" && snapshot.writable === true;
|
|
2355
|
+
const writable = snapshot.status === "ready" && snapshot.writable === true && !busy;
|
|
2239
2356
|
const write = async (key, value) => {
|
|
2240
|
-
|
|
2357
|
+
const current = settingsScope.getSnapshot();
|
|
2358
|
+
if (pending.current || current.status !== "ready" || current.writable !== true) return false;
|
|
2359
|
+
pending.current = true;
|
|
2360
|
+
setBusy(true);
|
|
2241
2361
|
setNotice("");
|
|
2242
2362
|
try {
|
|
2243
|
-
const accepted = await settingsScope.mutate([{ op: "set", path: [key], value }],
|
|
2244
|
-
if (!accepted) setNotice("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u5DF2\u5728\u5176\u4ED6\u9875\u9762\u4FEE\u6539\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
2363
|
+
const accepted = await settingsScope.mutate([{ op: "set", path: [key], value }], current.revision);
|
|
2364
|
+
if (!accepted && mounted.current) setNotice("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u5DF2\u5728\u5176\u4ED6\u9875\u9762\u4FEE\u6539\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
2245
2365
|
return accepted;
|
|
2246
2366
|
} catch (error) {
|
|
2247
|
-
setNotice(text(error?.message) || "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
2367
|
+
if (mounted.current) setNotice(text(error?.message) || "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
2248
2368
|
return false;
|
|
2369
|
+
} finally {
|
|
2370
|
+
pending.current = false;
|
|
2371
|
+
if (mounted.current) setBusy(false);
|
|
2249
2372
|
}
|
|
2250
2373
|
};
|
|
2251
|
-
return { value: snapshot.value ?? {}, writable, write, notice };
|
|
2374
|
+
return { value: snapshot.value ?? {}, writable, busy, write, notice };
|
|
2252
2375
|
}
|
|
2253
2376
|
var ADAPTIVE_FIELD_LABEL = {
|
|
2254
2377
|
feedbackHalfLifeDays: "\u53CD\u9988\u534A\u8870\u671F\uFF08\u5929\uFF09",
|
|
@@ -2260,12 +2383,18 @@ function AdaptiveNumberControl({ field: field2, value, writable, onSave }) {
|
|
|
2260
2383
|
const [draft, setDraft] = import_react2.default.useState("");
|
|
2261
2384
|
const [notice, setNotice] = import_react2.default.useState("");
|
|
2262
2385
|
const save = async () => {
|
|
2386
|
+
let next;
|
|
2263
2387
|
try {
|
|
2264
|
-
|
|
2265
|
-
setNotice("");
|
|
2266
|
-
if (await onSave(field2.key, next)) setDraft("");
|
|
2388
|
+
next = parseAdaptiveNumber(field2.key, draft);
|
|
2267
2389
|
} catch {
|
|
2268
2390
|
setNotice(`\u8BF7\u8F93\u5165 ${field2.min} \u5230 ${field2.max} \u7684\u6570\u5B57\u3002`);
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
setNotice("");
|
|
2394
|
+
try {
|
|
2395
|
+
if (await onSave(field2.key, next)) setDraft((current) => current === draft ? "" : current);
|
|
2396
|
+
} catch {
|
|
2397
|
+
setNotice("\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
2269
2398
|
}
|
|
2270
2399
|
};
|
|
2271
2400
|
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: `mr-${field2.key}` }, ADAPTIVE_FIELD_LABEL[field2.key]), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
@@ -2291,12 +2420,18 @@ function PublicEndpointControl({ name, label, value, writable, onSave }) {
|
|
|
2291
2420
|
const [notice, setNotice] = import_react2.default.useState("");
|
|
2292
2421
|
const current = publicEndpointDraft(name, value);
|
|
2293
2422
|
const save = async () => {
|
|
2423
|
+
let next;
|
|
2294
2424
|
try {
|
|
2295
|
-
|
|
2296
|
-
setNotice("");
|
|
2297
|
-
if (await onSave(name, next)) setDraft(null);
|
|
2425
|
+
next = parsePublicEndpoint(name, draft ?? current);
|
|
2298
2426
|
} catch {
|
|
2299
2427
|
setNotice("\u8BF7\u8F93\u5165\u4E0D\u542B\u8BA4\u8BC1\u3001\u67E5\u8BE2\u53C2\u6570\u6216\u7247\u6BB5\u7684\u516C\u5F00 HTTPS \u5730\u5740\uFF1B\u4EF7\u683C\u5FEB\u7167\u53EF\u7559\u7A7A\u3002");
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
setNotice("");
|
|
2431
|
+
try {
|
|
2432
|
+
if (await onSave(name, next)) setDraft((currentDraft) => currentDraft === draft ? null : currentDraft);
|
|
2433
|
+
} catch {
|
|
2434
|
+
setNotice("\u5730\u5740\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
2300
2435
|
}
|
|
2301
2436
|
};
|
|
2302
2437
|
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: `mr-${name}` }, label), /* @__PURE__ */ import_react2.default.createElement(
|
|
@@ -2315,25 +2450,42 @@ function PublicEndpointControl({ name, label, value, writable, onSave }) {
|
|
|
2315
2450
|
void save();
|
|
2316
2451
|
} }, "\u4FDD\u5B58\u5730\u5740"), notice && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-error", role: "alert" }, notice));
|
|
2317
2452
|
}
|
|
2318
|
-
function PublicSourceStatus({ label, source }) {
|
|
2319
|
-
const view = dynamicSourceView(source);
|
|
2320
|
-
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, label, "\uFF1A", view.label), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, view.version ? `\u7248\u672C ${view.version} \xB7 ` : "", view.count, " \u6761\u8BB0\u5F55", view.verifiedAt ? ` \xB7 \u6700\u8FD1\u6821\u9A8C ${new Date(view.verifiedAt).toLocaleString()}` : ""), view.source && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u516C\u5F00\u6765\u6E90\uFF1A", view.source), view.status === "error" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u66F4\u65B0\u5931\u8D25\uFF1B\u662F\u5426\u53EF\u7528\u7531 Host \u6821\u9A8C\uFF0C\u4E0D\u5C06\u7F3A\u5931\u6570\u636E\u5F53\u4F5C\u96F6\u6210\u672C\u6216\u6EE1\u5206\u3002"));
|
|
2453
|
+
function PublicSourceStatus({ label, source, enabled }) {
|
|
2454
|
+
const view = dynamicSourceView(source, enabled);
|
|
2455
|
+
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, label, "\uFF1A", view.label), view.status !== "disabled" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, view.version ? `\u7248\u672C ${view.version} \xB7 ` : "", view.count, " \u6761\u8BB0\u5F55", view.verifiedAt ? ` \xB7 \u6700\u8FD1\u6821\u9A8C ${new Date(view.verifiedAt).toLocaleString()}` : ""), view.source && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u516C\u5F00\u6765\u6E90\uFF1A", view.source), (view.refreshing || view.pending) && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption", role: "status" }, "\u516C\u5F00\u6E90\u6B63\u5728\u5237\u65B0\uFF1B\u4E0A\u9762\u7684\u7248\u672C\u4ECD\u662F\u6700\u8FD1\u4E00\u6B21\u5DF2\u4FDD\u5B58\u5FEB\u7167\uFF0C\u4E0D\u662F\u672C\u6B21\u8BF7\u6C42\u5DF2\u6210\u529F\u3002"), view.lastAttemptAt && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u6700\u8FD1\u5C1D\u8BD5 ", new Date(view.lastAttemptAt).toLocaleString(), view.lastSuccessAt ? ` \xB7 \u6700\u8FD1\u6210\u529F ${new Date(view.lastSuccessAt).toLocaleString()}` : ""), view.status === "error" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u66F4\u65B0\u5931\u8D25\uFF1B\u662F\u5426\u53EF\u7528\u7531 Host \u6821\u9A8C\uFF0C\u4E0D\u5C06\u7F3A\u5931\u6570\u636E\u5F53\u4F5C\u96F6\u6210\u672C\u6216\u6EE1\u5206\u3002"), view.status === "stale" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u4E0A\u6B21\u6709\u6548\u5FEB\u7167\u5DF2\u8FC7\u671F\u6216\u672C\u6B21\u66F4\u65B0\u5931\u8D25\uFF1BHost \u53EF\u80FD\u6CBF\u7528\u65E7\u6570\u636E\uFF0C\u4E0D\u80FD\u5F53\u4F5C\u6700\u65B0\u4EF7\u683C\u6216\u80FD\u529B\u3002"), view.errorCode === "storage-failed" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u672C\u6B21\u72B6\u6001\u4FDD\u5B58\u5931\u8D25\uFF1B\u53EA\u80FD\u4F7F\u7528\u6B64\u524D\u5DF2\u4FDD\u5B58\u7684\u5F53\u524D\u6E90\u5FEB\u7167\uFF0C\u8BF7\u91CD\u8BD5\u5237\u65B0\u3002"), view.errorCode === "refresh-interrupted" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u4E0A\u6B21\u516C\u5F00\u6570\u636E\u5237\u65B0\u4E2D\u65AD\uFF1B\u8BF7\u5237\u65B0\u6458\u8981\u67E5\u770B Host \u7684\u540E\u7EED\u91CD\u8BD5\u72B6\u6001\u3002"), view.lastGoodEndpoint && view.endpoint && view.lastGoodEndpoint !== view.endpoint && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u6B64\u524D\u6765\u6E90\u7684\u6709\u6548\u5FEB\u7167\u4ECD\u4FDD\u7559\u5728\u672C\u5730\uFF0C\u4F46\u4E0D\u5E94\u7528\u5230\u5F53\u524D\u516C\u5F00\u6E90\u3002"), view.status === "disabled" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u5F53\u524D\u8BBE\u7F6E\u4E0D\u4F7F\u7528\u6B64\u516C\u5F00\u6E90\uFF1B\u4FDD\u7559\u7684\u5386\u53F2\u5FEB\u7167\u4E0D\u4EE3\u8868\u6B63\u5728\u4F7F\u7528\u3002"));
|
|
2456
|
+
}
|
|
2457
|
+
function LearningEvidence({ learning }) {
|
|
2458
|
+
const evidence = learningEvidenceRows(learning);
|
|
2459
|
+
const exclusions = learningExclusionRows(learning);
|
|
2460
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, evidence.total > 0 && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u5206\u6A21\u578B / \u4EFB\u52A1\u7C7B\u578B\u7684\u5DF2\u89C2\u5BDF\u53CD\u9988\uFF08", evidence.total, " \u7EC4\uFF09"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u53EA\u63CF\u8FF0\u5DF2\u9009\u62E9\u5E76\u83B7\u5F97\u8BC4\u4EF7\u7684\u7ED3\u679C\uFF0C\u4E0D\u4EE3\u8868\u6240\u6709\u6A21\u578B\u7684\u771F\u5B9E\u8D28\u91CF\u6216\u6536\u76CA\uFF1B\u6709\u6548\u6837\u672C\u91CF\u53CD\u6620\u6743\u91CD\u96C6\u4E2D\u7A0B\u5EA6\uFF0C\u4E0D\u662F\u8D28\u91CF\u7F6E\u4FE1\u5EA6\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-table-wrap" }, /* @__PURE__ */ import_react2.default.createElement("table", { className: "mr-table" }, /* @__PURE__ */ import_react2.default.createElement("thead", null, /* @__PURE__ */ import_react2.default.createElement("tr", null, /* @__PURE__ */ import_react2.default.createElement("th", null, "\u8DEF\u7EBF / \u4EFB\u52A1\u7C7B\u578B"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u6709\u7528 / \u4E0D\u597D"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u504F\u597D\u6548\u7528\u8C03\u6574"))), /* @__PURE__ */ import_react2.default.createElement("tbody", null, evidence.rows.map((row) => /* @__PURE__ */ import_react2.default.createElement("tr", { key: row.id }, /* @__PURE__ */ import_react2.default.createElement("td", null, row.route, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, row.domain)), /* @__PURE__ */ import_react2.default.createElement("td", null, row.positiveCount, " / ", row.negativeCount, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, "\u5DF2\u89C2\u5BDF ", row.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", row.effectiveWeight.toFixed(2), " \xB7 \u6709\u6548\u6837\u672C\u91CF ", row.effectiveSampleSize.toFixed(2))), /* @__PURE__ */ import_react2.default.createElement("td", null, row.adjustment > 0 ? "+" : "", row.adjustment.toFixed(4), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, "\u6536\u7F29\u7CFB\u6570 ", row.shrinkage.toFixed(2)))))))), evidence.total > evidence.rows.length && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u4EC5\u5C55\u793A\u524D ", evidence.rows.length, " \u7EC4\uFF1B\u4E0D\u662F\u6240\u6709\u6A21\u578B\u7684\u8986\u76D6\u7387\u3002")), exclusions.length > 0 && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u672A\u53C2\u4E0E\u5B66\u4E60\u7684\u539F\u56E0"), /* @__PURE__ */ import_react2.default.createElement("ul", { className: "mr-checklist" }, exclusions.map((row) => /* @__PURE__ */ import_react2.default.createElement("li", { key: row.reason }, row.label, "\uFF1A", row.count)))));
|
|
2321
2461
|
}
|
|
2322
|
-
function AdaptiveControls({ ledger, settings, onChanged }) {
|
|
2462
|
+
function AdaptiveControls({ ledger, settings, onChanged, refreshing }) {
|
|
2323
2463
|
const value = settings.value;
|
|
2324
2464
|
const learning = learningView(ledger?.learning, value);
|
|
2325
2465
|
const [resetBusy, setResetBusy] = import_react2.default.useState(false);
|
|
2466
|
+
const [refreshNotice, setRefreshNotice] = import_react2.default.useState("");
|
|
2467
|
+
const resetPending = import_react2.default.useRef(false);
|
|
2326
2468
|
const save = async (key, next) => {
|
|
2327
2469
|
const accepted = await settings.write(key, next);
|
|
2328
|
-
if (accepted)
|
|
2470
|
+
if (accepted) {
|
|
2471
|
+
setRefreshNotice("");
|
|
2472
|
+
try {
|
|
2473
|
+
await onChanged?.();
|
|
2474
|
+
} catch {
|
|
2475
|
+
setRefreshNotice("\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u6458\u8981\u5237\u65B0\u5931\u8D25\uFF1B\u8BF7\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u540E\u91CD\u65B0\u89C4\u5212\u3002");
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2329
2478
|
return accepted;
|
|
2330
2479
|
};
|
|
2331
2480
|
const reset = async () => {
|
|
2332
|
-
if (!
|
|
2333
|
-
|
|
2481
|
+
if (resetPending.current || !settings.writable) return;
|
|
2482
|
+
resetPending.current = true;
|
|
2334
2483
|
try {
|
|
2484
|
+
if (!window.confirm("\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60\u4F60\u7684\u504F\u597D\uFF1F\u6B64\u524D\u53CD\u9988\u5C06\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\uFF0C\u4F46\u6267\u884C\u8BB0\u5F55\u3001\u8D39\u7528\u5386\u53F2\u548C\u539F\u8BC4\u4EF7\u4E0D\u4F1A\u5220\u9664\u3002")) return;
|
|
2485
|
+
setResetBusy(true);
|
|
2335
2486
|
await save("feedbackResetAt", Date.now());
|
|
2336
2487
|
} finally {
|
|
2488
|
+
resetPending.current = false;
|
|
2337
2489
|
setResetBusy(false);
|
|
2338
2490
|
}
|
|
2339
2491
|
};
|
|
@@ -2356,7 +2508,7 @@ function AdaptiveControls({ ledger, settings, onChanged }) {
|
|
|
2356
2508
|
writable: settings.writable,
|
|
2357
2509
|
onSave: save
|
|
2358
2510
|
}
|
|
2359
|
-
))), learning.available ? /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, learning.enabled ? "\u5B66\u4E60\u5DF2\u542F\u7528" : "\u5B66\u4E60\u5DF2\u505C\u7528", " \xB7 \u6709\u6548\u53CD\u9988 ", learning.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", learning.effectiveWeight.toFixed(2), " \xB7 \u5FFD\u7565 ", learning.ignoredCount, learning.policyVersion ? ` \xB7 \u7B56\u7565 ${learning.policyVersion}` : "") : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B66\u4E60\u6458\u8981\u5C1A\u672A\u8BFB\u53D6\uFF1B\u4FDD\u5B58\u540E\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u67E5\u770B\u3002"), learning.resetAt > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5B66\u4E60\u8D77\u70B9\uFF1A", new Date(learning.resetAt).toLocaleString(), "\uFF0C\u6B64\u524D\u53CD\u9988\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\u3002"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || resetBusy, onClick: () => {
|
|
2511
|
+
))), settings.busy && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u5019\u2026"), refreshing && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u53CD\u9988\u4E0E\u516C\u5F00\u6570\u636E\u6458\u8981\u2026"), refreshNotice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, refreshNotice), learning.available ? /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, learning.enabled ? "\u5B66\u4E60\u5DF2\u542F\u7528" : "\u5B66\u4E60\u5DF2\u505C\u7528", " \xB7 \u6700\u8FD1\u4E00\u6B21\u8D26\u672C\u6458\u8981\uFF1A\u6709\u6548\u53CD\u9988 ", learning.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", learning.effectiveWeight.toFixed(2), " \xB7 \u5FFD\u7565 ", learning.ignoredCount, learning.policyVersion ? ` \xB7 \u7B56\u7565 ${learning.policyVersion}` : "") : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B66\u4E60\u6458\u8981\u5C1A\u672A\u8BFB\u53D6\uFF1B\u4FDD\u5B58\u540E\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u67E5\u770B\u3002"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u6458\u8981\u662F\u6700\u8FD1\u4E00\u6B21\u8BFB\u53D6\u7684\u5DF2\u89C2\u5BDF\u8BC1\u636E\u3002\u4FEE\u6539\u8BC4\u4EF7 / \u5B66\u4E60\u8BBE\u7F6E\u540E\u9700\u5237\u65B0\u6458\u8981\u5E76\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\uFF1B\u5237\u65B0\u6309\u68C0\u67E5\u95F4\u9694\u590D\u7528\u516C\u5F00\u5FEB\u7167\uFF0C\u4E0D\u4FDD\u8BC1\u6BCF\u6B21\u4E0B\u8F7D\u65B0\u6570\u636E\u3002"), /* @__PURE__ */ import_react2.default.createElement(LearningEvidence, { learning: ledger?.learning }), learning.resetAt > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5B66\u4E60\u8D77\u70B9\uFF1A", new Date(learning.resetAt).toLocaleString(), "\uFF0C\u6B64\u524D\u53CD\u9988\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\u3002"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || resetBusy, onClick: () => {
|
|
2360
2512
|
void reset();
|
|
2361
2513
|
} }, resetBusy ? "\u6B63\u5728\u8BBE\u7F6E\u2026" : "\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60"), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "mr-section-title" }, "\u52A8\u6001\u516C\u5171\u6570\u636E"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u9ED8\u8BA4\u5173\u95ED\u3002\u660E\u786E\u542F\u7528\u540E\uFF0C\u5728\u6253\u5F00 / \u5237\u65B0\u8D26\u672C\u53CA\u6267\u884C\u524D\u6309\u68C0\u67E5\u95F4\u9694\u8BFB\u53D6\u516C\u5F00 LiveBench \u548C\u53EF\u9009\u4EF7\u683C\u5FEB\u7167\uFF1B\u4EF7\u683C\u4E0E\u80FD\u529B\u5148\u9A8C\u4FDD\u7559\u7248\u672C\uFF0C\u4E0D\u4EE3\u8868\u771F\u5B9E\u4EFB\u52A1\u6536\u76CA\u3002\u53EA\u6709\u6253\u5F00\u516C\u5171\u6E90\u5F00\u5173\u624D\u4F1A\u8BFB\u53D6\u8FDC\u7A0B\u6570\u636E\uFF0C\u4E0D\u53D1\u9001\u4EFB\u52A1\u6216\u53CD\u9988\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
2362
2514
|
"input",
|
|
@@ -2376,9 +2528,9 @@ function AdaptiveControls({ ledger, settings, onChanged }) {
|
|
|
2376
2528
|
writable: settings.writable,
|
|
2377
2529
|
onSave: save
|
|
2378
2530
|
}
|
|
2379
|
-
), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "liveBenchEndpoint", label: "LiveBench \u516C\u5F00\u6E90", value: adaptiveSettingValue(value, "liveBenchEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "pricingSnapshotEndpoint", label: "\u4EF7\u683C\u5FEB\u7167\u516C\u5F00\u6E90\uFF08\u53EF\u9009\uFF09", value: adaptiveSettingValue(value, "pricingSnapshotEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "LiveBench", source: ledger?.dynamicData?.liveBench }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "\u4EF7\u683C", source: ledger?.dynamicData?.pricing })));
|
|
2531
|
+
), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "liveBenchEndpoint", label: "LiveBench \u516C\u5F00\u6E90", value: adaptiveSettingValue(value, "liveBenchEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "pricingSnapshotEndpoint", label: "\u4EF7\u683C\u5FEB\u7167\u516C\u5F00\u6E90\uFF08\u53EF\u9009\uFF09", value: adaptiveSettingValue(value, "pricingSnapshotEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "LiveBench", source: ledger?.dynamicData?.liveBench, enabled: adaptiveSettingValue(value, "dynamicDataEnabled") === true }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "\u4EF7\u683C", source: ledger?.dynamicData?.pricing, enabled: adaptiveSettingValue(value, "dynamicDataEnabled") === true && Boolean(adaptiveSettingValue(value, "pricingSnapshotEndpoint")) })));
|
|
2380
2532
|
}
|
|
2381
|
-
function CostControlCard({ ledger, settingsScope, onChanged, error }) {
|
|
2533
|
+
function CostControlCard({ ledger, settingsScope, onChanged, error, refreshing = false }) {
|
|
2382
2534
|
const settings = useSettingsWriter(settingsScope);
|
|
2383
2535
|
const [dailyDraft, setDailyDraft] = import_react2.default.useState("");
|
|
2384
2536
|
const [monthlyDraft, setMonthlyDraft] = import_react2.default.useState("");
|
|
@@ -2416,7 +2568,7 @@ function CostControlCard({ ledger, settingsScope, onChanged, error }) {
|
|
|
2416
2568
|
void set("allowManualReassign", event.target.checked);
|
|
2417
2569
|
} }), "\u5141\u8BB8\u624B\u52A8\u6539\u6D3E\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: value.confirmUnsandboxedCli !== false, disabled: !settings.writable, onChange: (event) => {
|
|
2418
2570
|
void set("confirmUnsandboxedCli", event.target.checked);
|
|
2419
|
-
} }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), /* @__PURE__ */ import_react2.default.createElement(AdaptiveControls, { ledger, settings, onChanged }), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
|
|
2571
|
+
} }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), /* @__PURE__ */ import_react2.default.createElement(AdaptiveControls, { ledger, settings, onChanged, refreshing }), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
|
|
2420
2572
|
}
|
|
2421
2573
|
function DagView({ packages, renderNode, label = "\u5B50\u4EFB\u52A1\u4F9D\u8D56\u56FE" }) {
|
|
2422
2574
|
const layers = dagLayers(packages);
|
|
@@ -2432,13 +2584,13 @@ function ChannelText({ item }) {
|
|
|
2432
2584
|
return /* @__PURE__ */ import_react2.default.createElement("span", { className: item.channel === "official-cli" ? "mr-pill mr-pill-channel-ok" : "mr-pill" }, item.channel === "official-cli" ? `\u5B98\u65B9 CLI \xB7 ${item.toolId ?? ""}` : "\u6A21\u578B\u76EE\u5F55 API");
|
|
2433
2585
|
}
|
|
2434
2586
|
function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
|
|
2435
|
-
if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun });
|
|
2436
2587
|
const [target, setTarget] = import_react2.default.useState("");
|
|
2588
|
+
if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun });
|
|
2437
2589
|
const cost = packageCost(item);
|
|
2438
2590
|
const rerun = rerunSupport(run);
|
|
2439
2591
|
const canRerun = rerun.supported && !item.ok && !busy;
|
|
2440
2592
|
const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
|
|
2441
|
-
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && item.ran && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
|
|
2593
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === 1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u6709\u7528\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u6709\u7528", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === -1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u4E0D\u597D\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u4E0D\u597D", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && item.ran && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
|
|
2442
2594
|
const [provider, model] = target.split("\0");
|
|
2443
2595
|
onRerun(run.id, item.id, { provider, model });
|
|
2444
2596
|
} }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
|
|
@@ -12003,7 +12155,7 @@ var xterm_default = `/**
|
|
|
12003
12155
|
`;
|
|
12004
12156
|
|
|
12005
12157
|
// .dsh-plugin/client/host-version.mjs
|
|
12006
|
-
var ROUTER_CLIENT_VERSION = true ? "0.16.
|
|
12158
|
+
var ROUTER_CLIENT_VERSION = true ? "0.16.2" : "";
|
|
12007
12159
|
var STALE_HOST_MESSAGE = "\u63D2\u4EF6\u540E\u53F0\u7248\u672C\u8F83\u65E7\uFF0C\u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F Harness\uFF08\u5305\u62EC\u6258\u76D8\u56FE\u6807\uFF09\u540E\u518D\u4F7F\u7528\u3002";
|
|
12008
12160
|
function isMissingRemoteMethod(message) {
|
|
12009
12161
|
const value = String(message ?? "");
|
|
@@ -12809,7 +12961,10 @@ function PlanResults({ plan, ledger, headingRef }) {
|
|
|
12809
12961
|
const purposeLabel = { analysis: "\u4EFB\u52A1\u5206\u6790", execution: "\u4EFB\u52A1\u5B9E\u65BD", verification: "\u72EC\u7ACB\u9A8C\u8BC1", synthesis: "\u7ED3\u679C\u6574\u5408" };
|
|
12810
12962
|
return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u8DEF\u7531\u5EFA\u8BAE" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title", ref: headingRef, tabIndex: -1 }, "\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u672C\u5730\u8BA1\u7B97\u5B8C\u6210\uFF0C\u672A\u5411\u6A21\u578B\u53D1\u9001\u4EFB\u52A1\u5185\u5BB9\u3002"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u63A8\u8350\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, selected ? `${selected.provider}/${selected.model}` : "\u6682\u65E0\u8DEF\u7EBF")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u4EFB\u52A1\u590D\u6742\u5EA6 \xB7 \u5206\u503C\uFF080\u20131\uFF09"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u590D\u6742" }[plan.complexity.band] || plan.complexity.band, " \xB7 ", plan.complexity.value)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u4F30\u7B97\u603B\u6210\u672C"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, money2(plan.estimatedCost))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[plan.preset]?.label ?? "\u5747\u8861"))), budget?.exceeded && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A", budget.message, " \u5B9E\u9645\u6267\u884C\u65F6\u5C06\u6309\u8BBE\u7F6E\u81EA\u52A8\u964D\u7EA7\u6216\u6682\u505C\u8BE2\u95EE\u3002"), budget?.limited && !budget.exceeded && budget.estimateKnown && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A\u672C\u6B21\u9884\u4F30 ", money2(plan.estimatedCost), "\uFF0C\u5269\u4F59\u989D\u5EA6 ", money2(budget.remainingUsd), "\u3002"), plan.loginRequired && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u63A8\u8350\u6A21\u578B\u7684\u5B98\u65B9 CLI \u672A\u767B\u5F55\uFF0C\u6267\u884C\u65F6\u76F4\u63A5\u8D70\u6A21\u578B\u76EE\u5F55 API\uFF1B\u53EF\u5728\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u5361\u7247\u70B9\u201C\u53BB\u767B\u5F55\u201D\u3002"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-control-label" }, "\u6267\u884C\u6E20\u9053"), /* @__PURE__ */ import_react5.default.createElement(ChannelBadge, { item: plan })), /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-plan-explanation" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u67E5\u770B\u89C4\u5212\u4F9D\u636E\u4E0E\u4F30\u7B97\u8BF4\u660E"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.reason), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.pricingNotice, " ", plan.qualityNotice, " ", plan.availabilityNotice, " ", plan.modalityNotice || "")), plan.optimization.budgetExceeded && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error" }, "\u6309\u5DF2\u63D0\u4F9B\u5355\u4EF7\u4F30\u7B97\uFF0C\u4EFB\u52A1\u53EF\u80FD\u8D85\u8FC7\u672C\u6B21\u9884\u7B97\u3002\u9884\u7B97\u53EA\u5F71\u54CD\u5EFA\u8BAE\uFF0C\u4E0D\u4F1A\u963B\u6B62\u5B9E\u9645\u6263\u8D39\u3002"), plan.mode === "team" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("h3", { className: "mr-section-title" }, "\u56E2\u961F\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u4E0B\u65B9\u6A21\u578B\u662F\u89C4\u5212\u5EFA\u8BAE\uFF1B\u6258\u7BA1\u6267\u884C\u4F1A\u6309\u5382\u5546 CLI \u7684\u6A21\u578B\u540D\u89C4\u5219\u9009\u7528\uFF0C\u672A\u6838\u9A8C\u6620\u5C04\u65F6\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B\u3002"), plan.team.workPackages.length > 1 && /* @__PURE__ */ import_react5.default.createElement(DagView, { packages: plan.team.workPackages, label: "\u5DE5\u4F5C\u5305\u4F9D\u8D56\u56FE", renderNode: (item) => /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel) }), plan.team.workPackages.length === 0 ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-empty" }, "\u5F53\u524D\u76EE\u5F55\u6CA1\u6709\u53EF\u5206\u914D\u7684\u6A21\u578B\u8DEF\u7EBF\u3002") : plan.team.workPackages.map((item, index) => /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-package mr-package-details", key: item.id }, /* @__PURE__ */ import_react5.default.createElement("summary", null, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-package-name" }, index + 1, ". ", item.name), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel)), item.objective && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u5177\u4F53\u76EE\u6807\uFF1A", item.objective), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, purposeLabel[item.purpose] ?? item.purpose, item.dependsOn.length > 0 ? ` \xB7 \u4F9D\u8D56\uFF1A${item.dependsOn.map((id2) => packageNames.get(id2) ?? id2).join("\u3001")}` : ""), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u96BE\u5EA6\uFF1A", { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u56F0\u96BE" }[item.difficulty] || item.difficulty || "\u5F85\u8BC4\u4F30", " \xB7 \u8D39\u7528\uFF1A", money2(item.estimatedCost)), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u9A8C\u6536\uFF1A", item.verificationChecklist.join("\uFF1B")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react5.default.createElement(ChannelBadge, { item }), item.loginRequired && /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-pill" }, "CLI \u672A\u767B\u5F55")), item.channelDetail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u6E20\u9053\u8BF4\u660E\uFF1A", item.channelDetail)))), plan.routingBypassed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u5DF2\u6307\u5B9A\u5355\u4E00\u6A21\u578B\uFF0C\u672A\u4E0E\u5176\u4ED6\u8DEF\u7EBF\u6BD4\u8F83\u3002\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_execute"), " \u5E76\u4F20\u5165\u8BE5 provider \u4E0E model \u5373\u53EF\u76F4\u63A5\u6267\u884C\uFF1B\u82E5\u8BE5\u6A21\u578B\u5141\u8BB8\u5B98\u65B9\u5DE5\u5177\uFF0C\u4F1A\u4F18\u5148\u4F7F\u7528\u5BF9\u5E94 CLI\u3002"), plan.mode === "team" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.team.handoff)));
|
|
12811
12963
|
}
|
|
12812
|
-
var remoteError = (response, fallback) =>
|
|
12964
|
+
var remoteError = (response, fallback) => remoteErrorText(
|
|
12965
|
+
text5(response?.error?.message) || text5(response?.value?.error) || (typeof response?.error === "string" ? response.error : ""),
|
|
12966
|
+
fallback
|
|
12967
|
+
);
|
|
12813
12968
|
function probeLabel(probe) {
|
|
12814
12969
|
if (!probe) return "\u5C1A\u672A\u68C0\u6D4B";
|
|
12815
12970
|
if (probe.installed) return `\u5DF2\u5B89\u88C5${probe.version ? ` \xB7 ${probe.version}` : ""}`;
|
|
@@ -12827,10 +12982,22 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12827
12982
|
const request = import_react5.default.useRef(0);
|
|
12828
12983
|
const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
12829
12984
|
const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
12985
|
+
const jobsRef = import_react5.default.useRef({});
|
|
12986
|
+
const rememberJobs = (updater) => {
|
|
12987
|
+
setJobs((previous) => {
|
|
12988
|
+
const next = typeof updater === "function" ? updater(previous) : updater;
|
|
12989
|
+
jobsRef.current = next;
|
|
12990
|
+
return next;
|
|
12991
|
+
});
|
|
12992
|
+
};
|
|
12830
12993
|
const refresh = async () => {
|
|
12831
12994
|
onRefreshHealth?.();
|
|
12832
12995
|
const current = ++request.current;
|
|
12833
|
-
setProbeState((previous) => ({
|
|
12996
|
+
setProbeState((previous) => ({
|
|
12997
|
+
...previous,
|
|
12998
|
+
status: previous.probes.length > 0 ? "refreshing" : "loading",
|
|
12999
|
+
error: ""
|
|
13000
|
+
}));
|
|
12834
13001
|
try {
|
|
12835
13002
|
if (typeof listOfficialTools !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
|
|
12836
13003
|
const response = await listOfficialTools();
|
|
@@ -12843,8 +13010,16 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12843
13010
|
onProbes({ probes, capabilities, readiness, hostVersion: typeof response.value?.hostVersion === "string" ? response.value.hostVersion : null });
|
|
12844
13011
|
} catch (error) {
|
|
12845
13012
|
if (!mounted.current || current !== request.current) return;
|
|
12846
|
-
|
|
12847
|
-
|
|
13013
|
+
const message = remoteErrorText(text5(error?.message), "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002");
|
|
13014
|
+
let kept = false;
|
|
13015
|
+
setProbeState((previous) => {
|
|
13016
|
+
if (previous.probes.length > 0) {
|
|
13017
|
+
kept = true;
|
|
13018
|
+
return { ...previous, status: "ready", error: message };
|
|
13019
|
+
}
|
|
13020
|
+
return { status: "error", probes: [], capabilities: [], readiness: [], error: message };
|
|
13021
|
+
});
|
|
13022
|
+
if (!kept) onProbes({ probes: [], capabilities: [], readiness: [] });
|
|
12848
13023
|
}
|
|
12849
13024
|
};
|
|
12850
13025
|
import_react5.default.useEffect(() => {
|
|
@@ -12859,7 +13034,16 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12859
13034
|
return null;
|
|
12860
13035
|
}
|
|
12861
13036
|
})).then((entries) => {
|
|
12862
|
-
if (mounted.current)
|
|
13037
|
+
if (!mounted.current) return;
|
|
13038
|
+
rememberJobs((previous) => {
|
|
13039
|
+
const next = { ...previous };
|
|
13040
|
+
for (const entry of entries) {
|
|
13041
|
+
if (!entry) continue;
|
|
13042
|
+
const [id2, job] = entry;
|
|
13043
|
+
if (shouldApplyInstallStatus(previous[id2], job)) next[id2] = job;
|
|
13044
|
+
}
|
|
13045
|
+
return next;
|
|
13046
|
+
});
|
|
12863
13047
|
});
|
|
12864
13048
|
}
|
|
12865
13049
|
return () => {
|
|
@@ -12879,12 +13063,20 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12879
13063
|
if (!listening || !mounted.current) return;
|
|
12880
13064
|
if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u83B7\u53D6\u5B89\u88C5\u8FDB\u5EA6\u3002"));
|
|
12881
13065
|
const job = response.value?.job;
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
13066
|
+
const local = jobsRef.current[id2];
|
|
13067
|
+
if (!job) {
|
|
13068
|
+
if (local?.status === "running") return;
|
|
13069
|
+
throw new Error("\u5B89\u88C5\u4EFB\u52A1\u72B6\u6001\u6682\u4E0D\u53EF\u7528\u3002");
|
|
13070
|
+
}
|
|
13071
|
+
if (!shouldApplyInstallStatus(local, job)) return;
|
|
13072
|
+
rememberJobs((previous) => shouldApplyInstallStatus(previous[id2], job) ? { ...previous, [id2]: job } : previous);
|
|
13073
|
+
setRowErrors((previous) => ({
|
|
13074
|
+
...previous,
|
|
13075
|
+
[id2]: job.status === "failed" ? text5(job.error) || "\u5B89\u88C5\u5931\u8D25\u3002" : ""
|
|
13076
|
+
}));
|
|
12885
13077
|
if (job.status !== "running") void refresh();
|
|
12886
13078
|
} catch (error) {
|
|
12887
|
-
if (listening && mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text5(error?.message)
|
|
13079
|
+
if (listening && mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: remoteErrorText(text5(error?.message), "\u5B89\u88C5\u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF0C\u5C06\u7EE7\u7EED\u91CD\u8BD5\u3002") }));
|
|
12888
13080
|
} finally {
|
|
12889
13081
|
polling.current.delete(id2);
|
|
12890
13082
|
}
|
|
@@ -12899,21 +13091,43 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12899
13091
|
}, [jobs, officialToolInstallStatus]);
|
|
12900
13092
|
const install = async (id2) => {
|
|
12901
13093
|
const tool = OFFICIAL_TOOLS.find((item) => item.id === id2);
|
|
12902
|
-
|
|
13094
|
+
const refusal = installClickRefusal({
|
|
13095
|
+
tool,
|
|
13096
|
+
submitting: submitting.current.has(id2),
|
|
13097
|
+
running: jobsRef.current[id2]?.status === "running"
|
|
13098
|
+
});
|
|
13099
|
+
if (refusal) {
|
|
13100
|
+
setRowErrors((previous) => ({ ...previous, [id2]: refusal }));
|
|
13101
|
+
return;
|
|
13102
|
+
}
|
|
12903
13103
|
submitting.current.add(id2);
|
|
13104
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12904
13105
|
setRowErrors((previous) => ({ ...previous, [id2]: "" }));
|
|
12905
|
-
|
|
13106
|
+
rememberJobs((previous) => ({
|
|
13107
|
+
...previous,
|
|
13108
|
+
[id2]: { tool: id2, status: "running", outputTail: [], startedAt, error: null }
|
|
13109
|
+
}));
|
|
12906
13110
|
try {
|
|
12907
13111
|
if (typeof installOfficialTool !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
|
|
12908
13112
|
const response = await installOfficialTool(id2);
|
|
12909
13113
|
if (!mounted.current) return;
|
|
12910
|
-
|
|
12911
|
-
|
|
13114
|
+
const accepted = acceptedInstallJob(response);
|
|
13115
|
+
if (!accepted.job) throw new Error(remoteErrorText(accepted.error, "\u5B89\u88C5\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002"));
|
|
13116
|
+
rememberJobs((previous) => shouldApplyInstallStatus(previous[id2], accepted.job) ? { ...previous, [id2]: accepted.job } : previous);
|
|
12912
13117
|
} catch (error) {
|
|
12913
|
-
if (mounted.current)
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
|
|
13118
|
+
if (!mounted.current) return;
|
|
13119
|
+
const message = remoteErrorText(text5(error?.message), "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002");
|
|
13120
|
+
rememberJobs((previous) => ({
|
|
13121
|
+
...previous,
|
|
13122
|
+
[id2]: {
|
|
13123
|
+
...previous[id2] ?? {},
|
|
13124
|
+
tool: id2,
|
|
13125
|
+
status: "failed",
|
|
13126
|
+
error: message,
|
|
13127
|
+
startedAt: previous[id2]?.startedAt || startedAt
|
|
13128
|
+
}
|
|
13129
|
+
}));
|
|
13130
|
+
setRowErrors((previous) => ({ ...previous, [id2]: message }));
|
|
12917
13131
|
} finally {
|
|
12918
13132
|
submitting.current.delete(id2);
|
|
12919
13133
|
}
|
|
@@ -12925,7 +13139,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12925
13139
|
const response = await cancelOfficialToolInstall(id2);
|
|
12926
13140
|
if (!mounted.current) return;
|
|
12927
13141
|
if (!response?.ok || !response.value?.accepted || !response.value?.job) throw new Error(remoteError(response, "\u53D6\u6D88\u8BF7\u6C42\u672A\u88AB\u63A5\u53D7\u3002"));
|
|
12928
|
-
|
|
13142
|
+
rememberJobs((previous) => ({ ...previous, [id2]: response.value.job }));
|
|
12929
13143
|
if (response.value.job.status !== "running") void refresh();
|
|
12930
13144
|
} catch (error) {
|
|
12931
13145
|
if (mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text5(error?.message) || "\u65E0\u6CD5\u53D6\u6D88\u5B89\u88C5\u3002" }));
|
|
@@ -12936,7 +13150,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12936
13150
|
const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
|
|
12937
13151
|
return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177 \xB7 \u4F53\u68C0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u7684\u5B89\u88C5\u3001\u7248\u672C\u548C\u767B\u5F55\u72B6\u6001\uFF0C\u5E76\u4ECE\u56FA\u5B9A\u6CE8\u518C\u8868\u4E00\u952E\u5B89\u88C5\u6216\u66F4\u65B0\u5230\u5404\u5382\u5546\u6700\u65B0\u7248\uFF08\u65B0\u7248\u672C\u672A\u7ECF\u63D2\u4EF6\u6D4B\u8BD5\uFF09\u3002\u672A\u767B\u5F55\u7684\u5DE5\u5177\u70B9\u201C\u53BB\u767B\u5F55\u201D\u67E5\u770B\u767B\u5F55\u547D\u4EE4\u3002ZCode \u4F1A\u6253\u5F00\u5B98\u65B9\u5B89\u88C5\u7A97\u53E3\u4F9B\u4F60\u9009\u62E9\u76EE\u5F55\uFF1B\u5B8C\u6210\u540E\u91CD\u65B0\u4F53\u68C0\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: probeState.status === "loading", onClick: () => {
|
|
12938
13152
|
void refresh();
|
|
12939
|
-
} }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, probeState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.
|
|
13153
|
+
} }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, probeState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.error && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, probeState.error), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tools", role: "list", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868" }, OFFICIAL_TOOLS.map((tool) => {
|
|
12940
13154
|
const command = installCommandLine(tool);
|
|
12941
13155
|
const probe = byId[tool.id];
|
|
12942
13156
|
const capability = capabilitiesById[tool.id];
|
|
@@ -12962,13 +13176,18 @@ var WORKSPACE_VIEWS = [
|
|
|
12962
13176
|
];
|
|
12963
13177
|
function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries }) {
|
|
12964
13178
|
const [health, setHealth] = import_react5.default.useState({ report: null, error: "", refreshing: false });
|
|
12965
|
-
const [ledger, setLedger] = import_react5.default.useState({ value: null, error: "" });
|
|
13179
|
+
const [ledger, setLedger] = import_react5.default.useState({ value: null, error: "", refreshing: false });
|
|
12966
13180
|
const [boundaries, setBoundaries] = import_react5.default.useState({ value: null, error: "" });
|
|
12967
13181
|
const [busy, setBusy] = import_react5.default.useState(false);
|
|
12968
13182
|
const mounted = import_react5.default.useRef(true);
|
|
12969
13183
|
const ledgerRequest = import_react5.default.useRef(0);
|
|
12970
|
-
import_react5.default.
|
|
12971
|
-
|
|
13184
|
+
const mutationBusy = import_react5.default.useRef(false);
|
|
13185
|
+
import_react5.default.useEffect(() => {
|
|
13186
|
+
mounted.current = true;
|
|
13187
|
+
return () => {
|
|
13188
|
+
mounted.current = false;
|
|
13189
|
+
ledgerRequest.current += 1;
|
|
13190
|
+
};
|
|
12972
13191
|
}, []);
|
|
12973
13192
|
const call = async (operation, fallback) => {
|
|
12974
13193
|
if (typeof operation !== "function") throw new Error("\u5DE5\u4F5C\u53F0\u670D\u52A1\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6\u540E\u91CD\u8BD5\u3002");
|
|
@@ -12985,13 +13204,18 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
|
|
|
12985
13204
|
};
|
|
12986
13205
|
const refreshLedger = async () => {
|
|
12987
13206
|
const request = ++ledgerRequest.current;
|
|
13207
|
+
if (mounted.current) setLedger((previous) => ({ ...previous, error: "", refreshing: true }));
|
|
12988
13208
|
try {
|
|
12989
13209
|
const value = await call(loadLedger, "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002");
|
|
12990
|
-
if (mounted.current && request === ledgerRequest.current) setLedger({ value, error: "" });
|
|
12991
|
-
if (request !== ledgerRequest.current) return null;
|
|
13210
|
+
if (mounted.current && request === ledgerRequest.current) setLedger({ value, error: "", refreshing: false });
|
|
13211
|
+
if (!mounted.current || request !== ledgerRequest.current) return null;
|
|
12992
13212
|
return value;
|
|
12993
13213
|
} catch (error) {
|
|
12994
|
-
if (mounted.current && request === ledgerRequest.current) setLedger((previous) => ({
|
|
13214
|
+
if (mounted.current && request === ledgerRequest.current) setLedger((previous) => ({
|
|
13215
|
+
...previous,
|
|
13216
|
+
refreshing: false,
|
|
13217
|
+
error: `${text5(error?.message) || "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002"}${previous.value ? " \u4E0B\u65B9\u4FDD\u7559\u6700\u8FD1\u4E00\u6B21\u6458\u8981\uFF0C\u5C1A\u672A\u91CD\u65B0\u6838\u9A8C\u3002" : ""}`
|
|
13218
|
+
}));
|
|
12995
13219
|
return null;
|
|
12996
13220
|
}
|
|
12997
13221
|
};
|
|
@@ -13012,6 +13236,8 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
|
|
|
13012
13236
|
}
|
|
13013
13237
|
};
|
|
13014
13238
|
const rate = async (runId, packageId, rating, expectedFinishedAt) => {
|
|
13239
|
+
if (mutationBusy.current) return;
|
|
13240
|
+
mutationBusy.current = true;
|
|
13015
13241
|
setBusy(true);
|
|
13016
13242
|
try {
|
|
13017
13243
|
await call(() => rateResult({ runId, packageId, rating, ...expectedFinishedAt === void 0 ? {} : { expectedFinishedAt } }), "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
@@ -13019,10 +13245,12 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
|
|
|
13019
13245
|
} catch (error) {
|
|
13020
13246
|
if (mounted.current) setLedger((previous) => ({ ...previous, error: text5(error?.message) || "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002" }));
|
|
13021
13247
|
} finally {
|
|
13248
|
+
mutationBusy.current = false;
|
|
13022
13249
|
if (mounted.current) setBusy(false);
|
|
13023
13250
|
}
|
|
13024
13251
|
};
|
|
13025
13252
|
const rerun = async (runId, packageId, override, choice = null) => {
|
|
13253
|
+
if (mutationBusy.current) return;
|
|
13026
13254
|
const run = ledger.value?.runs?.find((item2) => item2.id === runId);
|
|
13027
13255
|
const item = run?.packages?.find((entry) => entry.id === packageId);
|
|
13028
13256
|
const reasons = rerunConfirmations({ run, item, override, choice, ledger: ledger.value, health: health.report, toolFor: toolForProvider, headlessIds: HEADLESS_TOOLS });
|
|
@@ -13031,6 +13259,8 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
|
|
|
13031
13259
|
${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
|
|
13032
13260
|
\u5168\u90E8\u786E\u8BA4\u5E76\u7EE7\u7EED\u5417\uFF1F`)) return;
|
|
13033
13261
|
const codes = new Set(reasons.map((entry) => entry.code));
|
|
13262
|
+
if (mutationBusy.current) return;
|
|
13263
|
+
mutationBusy.current = true;
|
|
13034
13264
|
setBusy(true);
|
|
13035
13265
|
try {
|
|
13036
13266
|
const request = {
|
|
@@ -13051,6 +13281,7 @@ ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
|
|
|
13051
13281
|
} catch (error) {
|
|
13052
13282
|
if (mounted.current) setLedger((previous) => ({ ...previous, error: `${text5(error?.message) || "\u91CD\u8DD1\u5931\u8D25\u3002"} \u53EF\u4EE5\u4FEE\u6B63\u540E\u518D\u70B9\u201C\u91CD\u8DD1\u6B64\u6B65\u201D\uFF0C\u6216\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_rerun_step\u3002` }));
|
|
13053
13283
|
} finally {
|
|
13284
|
+
mutationBusy.current = false;
|
|
13054
13285
|
if (mounted.current) setBusy(false);
|
|
13055
13286
|
}
|
|
13056
13287
|
};
|
|
@@ -13187,6 +13418,8 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
13187
13418
|
const ledger = await workbench.refreshLedger();
|
|
13188
13419
|
if (request !== generationRequest.current || inputs !== generationInputs.current || !mounted.current) return;
|
|
13189
13420
|
if (!ledger) throw new Error("\u8BF7\u5148\u6062\u590D\u6267\u884C\u8BB0\u5F55\u8FDE\u63A5\uFF1B\u65E0\u6CD5\u6838\u5BF9\u6700\u65B0\u6570\u636E\u4E0E\u5B66\u4E60\u72B6\u6001\u3002");
|
|
13421
|
+
if (ledger.storageAvailable === false) throw new Error("\u6267\u884C\u8BB0\u5F55\u5B58\u50A8\u6682\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u6838\u5BF9\u8D39\u7528\u4E0E\u5B66\u4E60\u72B6\u6001\uFF1B\u8BF7\u6062\u590D\u8FDE\u63A5\u540E\u518D\u89C4\u5212\u3002");
|
|
13422
|
+
if (ledger.budget?.historyVerified === false) throw new Error("\u8D39\u7528\u5386\u53F2\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u4ECE\u5907\u4EFD\u6062\u590D\u5E76\u6838\u9A8C\u540E\u518D\u89C4\u5212\u3002");
|
|
13190
13423
|
if (signature2 !== routingSettingsSignature(settingsScope.getSnapshot().value ?? {})) throw new Error("\u89C4\u5212\u8BBE\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\u3002");
|
|
13191
13424
|
const next = createWorkspacePlan(task, catalogState.catalog, {
|
|
13192
13425
|
...ledger.routingData,
|
|
@@ -13294,11 +13527,12 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
13294
13527
|
CostControlCard,
|
|
13295
13528
|
{
|
|
13296
13529
|
ledger: workbench.ledger.value,
|
|
13297
|
-
error: workbench.ledger.error
|
|
13530
|
+
error: workbench.ledger.error || workbench.ledger.value?.storageNotice || "",
|
|
13531
|
+
refreshing: workbench.ledger.refreshing,
|
|
13298
13532
|
settingsScope,
|
|
13299
13533
|
onChanged: () => {
|
|
13300
13534
|
invalidatePlan();
|
|
13301
|
-
|
|
13535
|
+
return workbench.refreshLedger();
|
|
13302
13536
|
}
|
|
13303
13537
|
}
|
|
13304
13538
|
), /* @__PURE__ */ import_react5.default.createElement(
|