@ljwei-stak/dsh-model-router 0.21.0 → 0.22.0
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 +889 -91
- package/.dsh-plugin/index.mjs +225 -25
- package/.dsh-plugin/shared/assignment-solver.mjs +235 -35
- package/.dsh-plugin/shared/harness-plan.mjs +16 -4
- package/.dsh-plugin/shared/manual-plan.mjs +143 -0
- package/.dsh-plugin/shared/official-team-runtime.mjs +8 -1
- package/.dsh-plugin/shared/official-tool-registry.mjs +5 -3
- package/.dsh-plugin/shared/official-tools-remote.mjs +10 -0
- package/.dsh-plugin/shared/official-tools-runtime.mjs +1 -0
- package/.dsh-plugin/shared/package-assignments.mjs +71 -0
- package/.dsh-plugin/shared/quality-gates.mjs +169 -0
- package/.dsh-plugin/shared/reasoning-execution.mjs +92 -0
- package/.dsh-plugin/shared/router-state.mjs +2 -1
- package/.dsh-plugin/shared/router.mjs +124 -12
- package/.dsh-plugin/shared/routing-evidence.mjs +720 -0
- package/.dsh-plugin/shared/run-ledger.mjs +85 -3
- package/.dsh-plugin/shared/task-executors.mjs +182 -27
- package/.dsh-plugin/shared/tool-install-preferences.mjs +11 -3
- package/CHANGELOG.md +21 -0
- package/README.i18n.yaml +2 -2
- package/README.md +13 -9
- package/README.zh.md +13 -9
- package/docs/INSTALLATION_GUIDE.zh.md +12 -12
- package/docs/MANUAL_TASK_ASSIGNMENT.zh.md +46 -0
- package/docs/ROUTING_ALGORITHM_OPTIMIZATION.zh.md +91 -0
- package/docs/WORKBENCH_USER_GUIDE.zh.md +5 -3
- package/docs/releases/0.22.0-validation.md +28 -0
- package/package.json +15 -4
package/.dsh-plugin/client.js
CHANGED
|
@@ -504,7 +504,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
504
504
|
installArgs: [],
|
|
505
505
|
uninstallArgs: [],
|
|
506
506
|
probeExecutables: ["hermes"],
|
|
507
|
-
probeNote: "\u652F\u6301\u5B98\u65B9\u6E90\u7801\u811A\u672C\u5B89\u88C5\uFF1B\
|
|
507
|
+
probeNote: "\u652F\u6301\u5B98\u65B9\u6E90\u7801\u811A\u672C\u5B89\u88C5\uFF1B\u81EA\u5B9A\u4E49\u6E90\u7801\u5B89\u88C5\u5230\u7EDF\u4E00\u6839/hermes-agent\uFF0C\u63D2\u4EF6\u4F7F\u7528\u8BE5\u6E90\u7801\u7684 .hermes/bin \u5165\u53E3\u3002\u914D\u7F6E\u3001\u767B\u5F55\u548C\u5386\u53F2\u4FDD\u7559\u539F\u4F4D\u7F6E\u3002\u684C\u9762/MSIX \u522B\u540D\u6682\u4E0D\u7528\u4E8E\u6B64\u5165\u53E3\u3002\u767B\u5F55\u4F7F\u7528 hermes auth\u3002",
|
|
508
508
|
providerHints: ["hermes", "nousresearch"],
|
|
509
509
|
scriptBinaryNames: Object.freeze(["hermes", "hermes.exe"]),
|
|
510
510
|
installMethods: Object.freeze([
|
|
@@ -512,8 +512,11 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
512
512
|
shell: "bash",
|
|
513
513
|
scriptUrl: "https://hermes-agent.nousresearch.com/install.sh",
|
|
514
514
|
platforms: ["linux", "darwin"],
|
|
515
|
-
supportsInstallDir:
|
|
515
|
+
supportsInstallDir: true,
|
|
516
516
|
sharedDefaultBin: true,
|
|
517
|
+
installDirSubdir: "hermes-agent",
|
|
518
|
+
installDirSuffix: ".hermes/bin",
|
|
519
|
+
installArg: ["--dir"],
|
|
517
520
|
extraArgs: ["--non-interactive"],
|
|
518
521
|
verify: Object.freeze({ mustInclude: ["https://github.com/NousResearch/hermes-agent.git", "hermes_cli/source_completion.py"] }),
|
|
519
522
|
uninstallUnsupportedReason: "\u8BF7\u5728\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF\u8FD0\u884C hermes uninstall \u5378\u8F7D\u6E90\u7801\u5B89\u88C5\uFF1B\u4FDD\u7559\u914D\u7F6E\u4E0E\u5386\u53F2\u65F6\u6309\u5411\u5BFC\u9009\u62E9\u3002\u684C\u9762/MSIX \u5B89\u88C5\u8BF7\u4F7F\u7528\u7CFB\u7EDF\u5E94\u7528\u7BA1\u7406\u3002"
|
|
@@ -522,7 +525,10 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
522
525
|
shell: "powershell",
|
|
523
526
|
scriptUrl: "https://hermes-agent.nousresearch.com/install.ps1",
|
|
524
527
|
platforms: ["win32"],
|
|
525
|
-
supportsInstallDir:
|
|
528
|
+
supportsInstallDir: true,
|
|
529
|
+
installDirSubdir: "hermes-agent",
|
|
530
|
+
installDirSuffix: ".hermes/bin",
|
|
531
|
+
installArg: ["-InstallDir"],
|
|
526
532
|
extraArgs: ["-NonInteractive"],
|
|
527
533
|
verify: Object.freeze({ mustInclude: ["https://github.com/NousResearch/hermes-agent.git", "hermes_cli/source_completion.py"] }),
|
|
528
534
|
uninstallUnsupportedReason: "\u8BF7\u5728\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF\u8FD0\u884C hermes uninstall \u5378\u8F7D\u6E90\u7801\u5B89\u88C5\uFF1B\u4FDD\u7559\u914D\u7F6E\u4E0E\u5386\u53F2\u65F6\u6309\u5411\u5BFC\u9009\u62E9\u3002\u684C\u9762/MSIX \u5B89\u88C5\u8BF7\u4F7F\u7528\u7CFB\u7EDF\u5E94\u7528\u7BA1\u7406\u3002"
|
|
@@ -1046,51 +1052,118 @@ function liveBenchRow(snapshot, model) {
|
|
|
1046
1052
|
// .dsh-plugin/shared/assignment-solver.mjs
|
|
1047
1053
|
var EPSILON = 1e-12;
|
|
1048
1054
|
var compareText = (a, b2) => a < b2 ? -1 : a > b2 ? 1 : 0;
|
|
1049
|
-
var
|
|
1055
|
+
var choiceSignature = (option) => {
|
|
1056
|
+
if (option.actionId === void 0 && option.effort === void 0 && option.reasoningEffort === void 0) return option.route;
|
|
1057
|
+
return JSON.stringify([option.actionId ?? option.route, option.effort ?? option.reasoningEffort ?? null]);
|
|
1058
|
+
};
|
|
1059
|
+
var signature = (state) => JSON.stringify(state.choices.map(choiceSignature));
|
|
1060
|
+
var compareQuality = (left, right) => left.relaxedCount - right.relaxedCount || left.qualityShortfall - right.qualityShortfall;
|
|
1050
1061
|
function compareStates(left, right, minimizeCost = false) {
|
|
1051
1062
|
return left.relaxedCount - right.relaxedCount || left.qualityShortfall - right.qualityShortfall || (minimizeCost ? left.cost - right.cost : right.score - left.score) || (minimizeCost ? right.score - left.score : left.cost - right.cost) || left.switches - right.switches || compareText(signature(left), signature(right));
|
|
1052
1063
|
}
|
|
1064
|
+
var dominates = (left, right) => {
|
|
1065
|
+
if (left.cost > right.cost) return false;
|
|
1066
|
+
const quality = compareQuality(left, right);
|
|
1067
|
+
if (quality < 0) return true;
|
|
1068
|
+
if (quality > 0) return false;
|
|
1069
|
+
if (left.score > right.score) return true;
|
|
1070
|
+
if (left.score < right.score) return false;
|
|
1071
|
+
if (left.cost < right.cost) return true;
|
|
1072
|
+
if (left.cost > right.cost) return false;
|
|
1073
|
+
if (left.switches !== right.switches) return left.switches < right.switches;
|
|
1074
|
+
return compareText(signature(left), signature(right)) < 0;
|
|
1075
|
+
};
|
|
1076
|
+
var dominanceOrder = (left, right) => left.cost - right.cost || compareQuality(left, right) || right.score - left.score || left.switches - right.switches || compareText(signature(left), signature(right));
|
|
1053
1077
|
function solveCandidateAssignments({ tasks = [], pools = [], budget = Infinity, beamWidth = 256, exactLimit = 4096, handoffPenalty = 0.015, minimizeCost = false } = {}) {
|
|
1054
1078
|
if (!tasks.length || tasks.length !== pools.length) return null;
|
|
1079
|
+
const taskCount = tasks.length;
|
|
1080
|
+
const taskIndexById = /* @__PURE__ */ new Map();
|
|
1055
1081
|
const preceding = /* @__PURE__ */ new Set();
|
|
1056
|
-
for (
|
|
1057
|
-
|
|
1082
|
+
for (let index = 0; index < taskCount; index++) {
|
|
1083
|
+
const task = tasks[index];
|
|
1084
|
+
if (!task || !task.id || preceding.has(task.id) || (task.dependsOn ?? []).some((id2) => !preceding.has(id2))) {
|
|
1058
1085
|
throw new RangeError("Assignment tasks must have unique ids and known dependencies in topological order");
|
|
1059
1086
|
}
|
|
1060
1087
|
preceding.add(task.id);
|
|
1088
|
+
taskIndexById.set(task.id, index);
|
|
1061
1089
|
}
|
|
1062
1090
|
const constrained = Number.isFinite(budget);
|
|
1063
|
-
const options = pools.map((pool) => (Array.isArray(pool) ? pool : []).filter((option) => Number.isFinite(option.cost) && option.cost >= 0 && Number.isFinite(option.score) && (!constrained || option.pricingKnown === true)));
|
|
1091
|
+
const options = pools.map((pool) => (Array.isArray(pool) ? pool : []).filter((option) => option && Number.isFinite(option.cost) && option.cost >= 0 && Number.isFinite(option.score) && (!constrained || option.pricingKnown === true)));
|
|
1064
1092
|
if (options.some((pool) => pool.length === 0)) return null;
|
|
1065
|
-
const
|
|
1093
|
+
const handoffRoutes = options.map((pool) => pool.map((option) => option.handoffRoute ?? option.route));
|
|
1094
|
+
const maximumScores = options.map((pool) => pool.reduce((best2, option) => Math.max(best2, option.score), -Infinity));
|
|
1095
|
+
const dependencyIndexes = tasks.map((task) => (task.dependsOn ?? []).map((id2) => taskIndexById.get(id2)));
|
|
1096
|
+
const lastUse = new Array(taskCount).fill(-1);
|
|
1097
|
+
for (let index = 0; index < taskCount; index++) {
|
|
1098
|
+
for (const depIndex of dependencyIndexes[index]) {
|
|
1099
|
+
if (index > lastUse[depIndex]) lastUse[depIndex] = index;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
const suffixMinimum = new Array(taskCount + 1).fill(0);
|
|
1103
|
+
const futureRelaxedLower = new Array(taskCount + 1).fill(0);
|
|
1104
|
+
const futureShortfallLower = new Array(taskCount + 1).fill(0);
|
|
1066
1105
|
let searchSpace = 1;
|
|
1067
1106
|
let searchSpaceCapped = false;
|
|
1068
|
-
for (let index =
|
|
1069
|
-
|
|
1107
|
+
for (let index = taskCount - 1; index >= 0; index--) {
|
|
1108
|
+
let minCost = Infinity;
|
|
1109
|
+
let minRelaxedFlag = 1;
|
|
1110
|
+
let minShortfallAtFlag = Infinity;
|
|
1111
|
+
for (const option of options[index]) {
|
|
1112
|
+
if (option.cost < minCost) minCost = option.cost;
|
|
1113
|
+
const shortfall = Math.max(0, Number(option.qualityShortfall) || 0);
|
|
1114
|
+
const relaxedFlag = shortfall > 0 ? 1 : 0;
|
|
1115
|
+
if (relaxedFlag < minRelaxedFlag || relaxedFlag === minRelaxedFlag && shortfall < minShortfallAtFlag) {
|
|
1116
|
+
minRelaxedFlag = relaxedFlag;
|
|
1117
|
+
minShortfallAtFlag = shortfall;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
suffixMinimum[index] = suffixMinimum[index + 1] + minCost;
|
|
1121
|
+
futureRelaxedLower[index] = futureRelaxedLower[index + 1] + minRelaxedFlag;
|
|
1122
|
+
futureShortfallLower[index] = futureShortfallLower[index + 1] + minShortfallAtFlag;
|
|
1070
1123
|
const product = searchSpace * options[index].length;
|
|
1071
1124
|
if (product > Number.MAX_SAFE_INTEGER) searchSpaceCapped = true;
|
|
1072
1125
|
searchSpace = Math.min(Number.MAX_SAFE_INTEGER, product);
|
|
1073
1126
|
}
|
|
1074
1127
|
if (constrained && suffixMinimum[0] > budget + EPSILON) return null;
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1077
|
-
const
|
|
1128
|
+
const parsedExactLimit = Number(exactLimit);
|
|
1129
|
+
const exactThreshold = Number.isFinite(parsedExactLimit) ? Math.max(1, parsedExactLimit) : exactLimit === Infinity ? Number.MAX_SAFE_INTEGER : 4096;
|
|
1130
|
+
const parsedBeamWidth = Number(beamWidth);
|
|
1131
|
+
const width = Number.isFinite(parsedBeamWidth) ? Math.max(1, Math.floor(parsedBeamWidth) || 256) : 256;
|
|
1132
|
+
const exact = !searchSpaceCapped && searchSpace <= exactThreshold;
|
|
1133
|
+
const search = {
|
|
1134
|
+
method: exact ? "exact" : "beam",
|
|
1135
|
+
exact,
|
|
1136
|
+
strategy: exact ? "exact-enumeration" : "boundary-frontier-lookahead",
|
|
1137
|
+
searchSpace,
|
|
1138
|
+
searchSpaceCapped,
|
|
1139
|
+
expandedStates: 0,
|
|
1140
|
+
beamPruned: 0,
|
|
1141
|
+
dominancePruned: 0,
|
|
1142
|
+
peakFrontier: 0,
|
|
1143
|
+
retainedStates: 0,
|
|
1144
|
+
beamWidth: width,
|
|
1145
|
+
approximate: !exact,
|
|
1146
|
+
optimalityScope: "retained input candidate Cartesian space",
|
|
1147
|
+
boundCertified: exact
|
|
1148
|
+
};
|
|
1149
|
+
const unassignedReward = handoffPenalty < 0 ? -handoffPenalty : 0;
|
|
1078
1150
|
let states = [{ choices: [], routesByTask: /* @__PURE__ */ new Map(), score: 0, cost: 0, switches: 0, relaxedCount: 0, qualityShortfall: 0 }];
|
|
1079
|
-
for (let index = 0; index <
|
|
1080
|
-
const task = tasks[index];
|
|
1151
|
+
for (let index = 0; index < taskCount; index++) {
|
|
1081
1152
|
const expanded = [];
|
|
1082
1153
|
for (const state of states) {
|
|
1083
|
-
for (
|
|
1154
|
+
for (let optionIndex = 0; optionIndex < options[index].length; optionIndex++) {
|
|
1155
|
+
const option = options[index][optionIndex];
|
|
1084
1156
|
const cost = state.cost + option.cost;
|
|
1085
1157
|
if (constrained && cost + suffixMinimum[index + 1] > budget + EPSILON) continue;
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1158
|
+
let switches = 0;
|
|
1159
|
+
for (const depIndex of dependencyIndexes[index]) {
|
|
1160
|
+
const route = state.routesByTask.get(tasks[depIndex].id);
|
|
1161
|
+
if (route !== void 0 && route !== handoffRoutes[index][optionIndex]) switches++;
|
|
1162
|
+
}
|
|
1090
1163
|
const penalty = switches * handoffPenalty;
|
|
1091
1164
|
const shortfall = Math.max(0, Number(option.qualityShortfall) || 0);
|
|
1092
1165
|
const routesByTask2 = new Map(state.routesByTask);
|
|
1093
|
-
routesByTask2.set(
|
|
1166
|
+
routesByTask2.set(tasks[index].id, handoffRoutes[index][optionIndex]);
|
|
1094
1167
|
expanded.push({
|
|
1095
1168
|
choices: [...state.choices, { ...option, handoffPenalty: penalty }],
|
|
1096
1169
|
routesByTask: routesByTask2,
|
|
@@ -1104,22 +1177,404 @@ function solveCandidateAssignments({ tasks = [], pools = [], budget = Infinity,
|
|
|
1104
1177
|
}
|
|
1105
1178
|
}
|
|
1106
1179
|
if (!expanded.length) return null;
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
states = expanded
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1180
|
+
if (exact) {
|
|
1181
|
+
expanded.sort((left, right) => compareStates(left, right, minimizeCost));
|
|
1182
|
+
states = expanded;
|
|
1183
|
+
} else {
|
|
1184
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1185
|
+
for (const state of expanded) {
|
|
1186
|
+
const boundary = [];
|
|
1187
|
+
for (let prev = 0; prev <= index; prev++) {
|
|
1188
|
+
if (lastUse[prev] > index) boundary.push([tasks[prev].id, state.routesByTask.get(tasks[prev].id)]);
|
|
1189
|
+
}
|
|
1190
|
+
const key = JSON.stringify(boundary);
|
|
1191
|
+
const group = groups.get(key);
|
|
1192
|
+
if (group) group.push(state);
|
|
1193
|
+
else groups.set(key, [state]);
|
|
1194
|
+
}
|
|
1195
|
+
const compressed = [];
|
|
1196
|
+
for (const group of groups.values()) {
|
|
1197
|
+
group.sort(dominanceOrder);
|
|
1198
|
+
const retained = [];
|
|
1199
|
+
for (const candidate of group) {
|
|
1200
|
+
let dominated = false;
|
|
1201
|
+
for (const keeper of retained) {
|
|
1202
|
+
if (dominates(keeper, candidate)) {
|
|
1203
|
+
dominated = true;
|
|
1204
|
+
break;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
if (dominated) search.dominancePruned++;
|
|
1208
|
+
else retained.push(candidate);
|
|
1209
|
+
}
|
|
1210
|
+
for (const state of retained) compressed.push(state);
|
|
1211
|
+
}
|
|
1212
|
+
const scoreUpperCache = /* @__PURE__ */ new Map();
|
|
1213
|
+
const optimisticScore = (state) => {
|
|
1214
|
+
if (scoreUpperCache.has(state)) return scoreUpperCache.get(state);
|
|
1215
|
+
let total = state.score;
|
|
1216
|
+
for (let future = index + 1; future < taskCount; future++) {
|
|
1217
|
+
const deps = dependencyIndexes[future];
|
|
1218
|
+
let unassignedDeps = 0;
|
|
1219
|
+
let assignedCount = 0;
|
|
1220
|
+
const assignedRoutes = /* @__PURE__ */ new Map();
|
|
1221
|
+
for (const depIndex of deps) {
|
|
1222
|
+
if (depIndex > index) unassignedDeps++;
|
|
1223
|
+
else {
|
|
1224
|
+
const route = state.routesByTask.get(tasks[depIndex].id);
|
|
1225
|
+
if (route !== void 0) {
|
|
1226
|
+
assignedCount++;
|
|
1227
|
+
assignedRoutes.set(route, (assignedRoutes.get(route) ?? 0) + 1);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
if (!assignedCount || handoffPenalty === 0) {
|
|
1232
|
+
total += maximumScores[future] + unassignedReward * unassignedDeps;
|
|
1233
|
+
continue;
|
|
1234
|
+
}
|
|
1235
|
+
let best2 = -Infinity;
|
|
1236
|
+
for (let optionIndex = 0; optionIndex < options[future].length; optionIndex++) {
|
|
1237
|
+
const option = options[future][optionIndex];
|
|
1238
|
+
const matches = assignedRoutes.get(handoffRoutes[future][optionIndex]) ?? 0;
|
|
1239
|
+
let value = option.score - handoffPenalty * (assignedCount - matches);
|
|
1240
|
+
if (unassignedDeps && unassignedReward) value += unassignedReward * unassignedDeps;
|
|
1241
|
+
if (value > best2) best2 = value;
|
|
1242
|
+
}
|
|
1243
|
+
total += best2;
|
|
1244
|
+
}
|
|
1245
|
+
scoreUpperCache.set(state, total);
|
|
1246
|
+
return total;
|
|
1247
|
+
};
|
|
1248
|
+
compressed.sort((left, right) => {
|
|
1249
|
+
const leftRelaxed = left.relaxedCount + futureRelaxedLower[index + 1];
|
|
1250
|
+
const rightRelaxed = right.relaxedCount + futureRelaxedLower[index + 1];
|
|
1251
|
+
if (leftRelaxed !== rightRelaxed) return leftRelaxed - rightRelaxed;
|
|
1252
|
+
const leftShortfall = left.qualityShortfall + futureShortfallLower[index + 1];
|
|
1253
|
+
const rightShortfall = right.qualityShortfall + futureShortfallLower[index + 1];
|
|
1254
|
+
if (leftShortfall !== rightShortfall) return leftShortfall - rightShortfall;
|
|
1255
|
+
const leftScore = optimisticScore(left);
|
|
1256
|
+
const rightScore = optimisticScore(right);
|
|
1257
|
+
const leftCost = left.cost + suffixMinimum[index + 1];
|
|
1258
|
+
const rightCost = right.cost + suffixMinimum[index + 1];
|
|
1259
|
+
if (minimizeCost) {
|
|
1260
|
+
if (leftCost !== rightCost) return leftCost - rightCost;
|
|
1261
|
+
if (leftScore !== rightScore) return rightScore - leftScore;
|
|
1262
|
+
} else {
|
|
1263
|
+
if (leftScore !== rightScore) return rightScore - leftScore;
|
|
1264
|
+
if (leftCost !== rightCost) return leftCost - rightCost;
|
|
1265
|
+
}
|
|
1266
|
+
return compareStates(left, right, minimizeCost);
|
|
1267
|
+
});
|
|
1268
|
+
if (compressed.length > width) {
|
|
1269
|
+
states = compressed.slice(0, width);
|
|
1270
|
+
search.beamPruned += compressed.length - states.length;
|
|
1271
|
+
if (constrained && index < taskCount - 1) {
|
|
1272
|
+
let cheapest = compressed[0];
|
|
1273
|
+
for (const state of compressed) if (compareStates(state, cheapest, true) < 0) cheapest = state;
|
|
1274
|
+
if (!states.includes(cheapest)) states[width - 1] = cheapest;
|
|
1275
|
+
}
|
|
1276
|
+
} else states = compressed;
|
|
1277
|
+
}
|
|
1278
|
+
if (states.length > search.peakFrontier) search.peakFrontier = states.length;
|
|
1116
1279
|
}
|
|
1117
1280
|
states.sort((left, right) => compareStates(left, right, minimizeCost));
|
|
1281
|
+
search.retainedStates = states.length;
|
|
1118
1282
|
const best = states[0];
|
|
1119
1283
|
const { routesByTask, ...result } = best;
|
|
1120
1284
|
return { ...result, minimumCostLowerBound: suffixMinimum[0], search };
|
|
1121
1285
|
}
|
|
1122
1286
|
|
|
1287
|
+
// .dsh-plugin/shared/routing-evidence.mjs
|
|
1288
|
+
var SCHEMA_VERSION = 1;
|
|
1289
|
+
var FEATURE_DIMS = 4096;
|
|
1290
|
+
var TOKEN_CAP = 512;
|
|
1291
|
+
var MAX_TEXT_CHARS = 2e4;
|
|
1292
|
+
var MAX_STRING = 200;
|
|
1293
|
+
var MAX_EFFORT = 64;
|
|
1294
|
+
var MAX_QUALITY_SAMPLES = 1e4;
|
|
1295
|
+
var MAX_INPUT_TOKENS = 5e6;
|
|
1296
|
+
var MAX_OUTPUT_TOKENS = 2e6;
|
|
1297
|
+
var MAX_INPUT_CHARS = 5e6;
|
|
1298
|
+
var MAX_DURATION_MS = 864e5;
|
|
1299
|
+
var SIM_THRESHOLD = 0.2;
|
|
1300
|
+
var MAX_NEIGHBORS = 32;
|
|
1301
|
+
var SHRINK_PRIOR = 2;
|
|
1302
|
+
var NORM_TOLERANCE = 0.05;
|
|
1303
|
+
function isObj(o2) {
|
|
1304
|
+
return o2 !== null && typeof o2 === "object" && !Array.isArray(o2);
|
|
1305
|
+
}
|
|
1306
|
+
function boundedString(s15, max = MAX_STRING) {
|
|
1307
|
+
return typeof s15 === "string" && s15.length <= max && !/[\u0000-\u001f\u007f]/.test(s15);
|
|
1308
|
+
}
|
|
1309
|
+
function nonEmpty(s15) {
|
|
1310
|
+
return boundedString(s15) && s15.trim().length > 0;
|
|
1311
|
+
}
|
|
1312
|
+
function effortOk(s15) {
|
|
1313
|
+
return boundedString(s15, MAX_EFFORT);
|
|
1314
|
+
}
|
|
1315
|
+
function finite(n) {
|
|
1316
|
+
return typeof n === "number" && Number.isFinite(n);
|
|
1317
|
+
}
|
|
1318
|
+
function normalizeChannel(c) {
|
|
1319
|
+
if (!nonEmpty(c)) return null;
|
|
1320
|
+
return c === "api" ? "harness-llm" : c;
|
|
1321
|
+
}
|
|
1322
|
+
function isWordCode(c) {
|
|
1323
|
+
return c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95;
|
|
1324
|
+
}
|
|
1325
|
+
function isCjkCode(c) {
|
|
1326
|
+
return c >= 13312 && c <= 19903 || c >= 19968 && c <= 40959 || c >= 63744 && c <= 64255;
|
|
1327
|
+
}
|
|
1328
|
+
function hashIndex(tok) {
|
|
1329
|
+
let h2 = 2166136261 >>> 0;
|
|
1330
|
+
for (let i = 0; i < tok.length; i++) {
|
|
1331
|
+
h2 ^= tok.charCodeAt(i);
|
|
1332
|
+
h2 = Math.imul(h2, 16777619) >>> 0;
|
|
1333
|
+
}
|
|
1334
|
+
return h2 % FEATURE_DIMS;
|
|
1335
|
+
}
|
|
1336
|
+
function buildFeatures(text7) {
|
|
1337
|
+
const s15 = text7.length > MAX_TEXT_CHARS ? text7.slice(0, MAX_TEXT_CHARS) : text7;
|
|
1338
|
+
const idxCounts = /* @__PURE__ */ new Map();
|
|
1339
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1340
|
+
const addToken = (tok) => {
|
|
1341
|
+
if (!seen.has(tok)) {
|
|
1342
|
+
if (seen.size >= TOKEN_CAP) return;
|
|
1343
|
+
seen.add(tok);
|
|
1344
|
+
}
|
|
1345
|
+
const h2 = hashIndex(tok);
|
|
1346
|
+
idxCounts.set(h2, (idxCounts.get(h2) || 0) + 1);
|
|
1347
|
+
};
|
|
1348
|
+
let word = "";
|
|
1349
|
+
let cjk = "";
|
|
1350
|
+
const flushWord = () => {
|
|
1351
|
+
if (word) {
|
|
1352
|
+
addToken(word.toLowerCase());
|
|
1353
|
+
word = "";
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
const flushCjk = () => {
|
|
1357
|
+
if (cjk) {
|
|
1358
|
+
if (cjk.length === 1) addToken(cjk);
|
|
1359
|
+
else for (let i = 0; i + 1 < cjk.length; i++) addToken(cjk.slice(i, i + 2));
|
|
1360
|
+
cjk = "";
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
for (let i = 0; i < s15.length; i++) {
|
|
1364
|
+
const c = s15.charCodeAt(i);
|
|
1365
|
+
if (isWordCode(c)) {
|
|
1366
|
+
flushCjk();
|
|
1367
|
+
word += s15[i];
|
|
1368
|
+
} else if (isCjkCode(c)) {
|
|
1369
|
+
flushWord();
|
|
1370
|
+
cjk += s15[i];
|
|
1371
|
+
} else {
|
|
1372
|
+
flushWord();
|
|
1373
|
+
flushCjk();
|
|
1374
|
+
}
|
|
1375
|
+
if (idxCounts.size >= FEATURE_DIMS) break;
|
|
1376
|
+
}
|
|
1377
|
+
flushWord();
|
|
1378
|
+
flushCjk();
|
|
1379
|
+
let sum = 0;
|
|
1380
|
+
for (const c of idxCounts.values()) sum += c * c;
|
|
1381
|
+
if (sum <= 0) return [];
|
|
1382
|
+
const norm = Math.sqrt(sum);
|
|
1383
|
+
const feats = [];
|
|
1384
|
+
for (const [idx, c] of idxCounts) feats.push([idx, c / norm]);
|
|
1385
|
+
feats.sort((a, b2) => a[0] - b2[0]);
|
|
1386
|
+
return feats;
|
|
1387
|
+
}
|
|
1388
|
+
function cosine(a, b2) {
|
|
1389
|
+
let na2 = 0;
|
|
1390
|
+
let nb = 0;
|
|
1391
|
+
for (let i = 0; i < a.length; i++) na2 += a[i][1] * a[i][1];
|
|
1392
|
+
for (let j2 = 0; j2 < b2.length; j2++) nb += b2[j2][1] * b2[j2][1];
|
|
1393
|
+
const denom = Math.sqrt(na2) * Math.sqrt(nb);
|
|
1394
|
+
if (denom === 0) return 0;
|
|
1395
|
+
let dot = 0;
|
|
1396
|
+
let x = 0;
|
|
1397
|
+
let y = 0;
|
|
1398
|
+
while (x < a.length && y < b2.length) {
|
|
1399
|
+
const ai2 = a[x][0];
|
|
1400
|
+
const bi2 = b2[y][0];
|
|
1401
|
+
if (ai2 === bi2) {
|
|
1402
|
+
dot += a[x][1] * b2[y][1];
|
|
1403
|
+
x++;
|
|
1404
|
+
y++;
|
|
1405
|
+
} else if (ai2 < bi2) x++;
|
|
1406
|
+
else y++;
|
|
1407
|
+
}
|
|
1408
|
+
return dot / denom;
|
|
1409
|
+
}
|
|
1410
|
+
function validateFeatures(features) {
|
|
1411
|
+
if (!Array.isArray(features) || features.length === 0 || features.length > FEATURE_DIMS) return false;
|
|
1412
|
+
let sum = 0;
|
|
1413
|
+
let prev = -1;
|
|
1414
|
+
for (const pair of features) {
|
|
1415
|
+
if (!Array.isArray(pair) || pair.length !== 2) return false;
|
|
1416
|
+
const idx = pair[0];
|
|
1417
|
+
const w = pair[1];
|
|
1418
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= FEATURE_DIMS) return false;
|
|
1419
|
+
if (typeof w !== "number" || !Number.isFinite(w) || w <= 0) return false;
|
|
1420
|
+
if (idx <= prev) return false;
|
|
1421
|
+
prev = idx;
|
|
1422
|
+
sum += w * w;
|
|
1423
|
+
}
|
|
1424
|
+
const norm = Math.sqrt(sum);
|
|
1425
|
+
if (!(norm > 0)) return false;
|
|
1426
|
+
return Math.abs(norm - 1) <= NORM_TOLERANCE;
|
|
1427
|
+
}
|
|
1428
|
+
function validateGroup(g) {
|
|
1429
|
+
if (!isObj(g)) return false;
|
|
1430
|
+
const id2 = g.identity;
|
|
1431
|
+
if (!isObj(id2)) return false;
|
|
1432
|
+
if (!nonEmpty(id2.provider) || !nonEmpty(id2.model)) return false;
|
|
1433
|
+
if (!effortOk(id2.reasoningEffort)) return false;
|
|
1434
|
+
if (!nonEmpty(id2.channel) || normalizeChannel(id2.channel) !== id2.channel) return false;
|
|
1435
|
+
if (!nonEmpty(id2.type)) return false;
|
|
1436
|
+
if (!boundedString(id2.purpose)) return false;
|
|
1437
|
+
if (!Number.isInteger(g.sampleCount) || g.sampleCount < 1 || g.sampleCount > MAX_QUALITY_SAMPLES) return false;
|
|
1438
|
+
for (const k of ["inputTokenRatio", "outputTokens"]) {
|
|
1439
|
+
if (typeof g[k] !== "number" || !Number.isFinite(g[k]) || g[k] < 0) return false;
|
|
1440
|
+
}
|
|
1441
|
+
for (const k of ["durationMs", "promptCharRatio"]) {
|
|
1442
|
+
const v2 = g[k];
|
|
1443
|
+
if (v2 !== null && (typeof v2 !== "number" || !Number.isFinite(v2) || v2 < 0)) return false;
|
|
1444
|
+
}
|
|
1445
|
+
const p90 = g.p90;
|
|
1446
|
+
if (!isObj(p90)) return false;
|
|
1447
|
+
for (const k of ["inputTokenRatio", "outputTokens"]) {
|
|
1448
|
+
if (typeof p90[k] !== "number" || !Number.isFinite(p90[k]) || p90[k] < 0) return false;
|
|
1449
|
+
}
|
|
1450
|
+
for (const k of ["durationMs", "promptCharRatio"]) {
|
|
1451
|
+
const v2 = p90[k];
|
|
1452
|
+
if (v2 !== null && (typeof v2 !== "number" || !Number.isFinite(v2) || v2 < 0)) return false;
|
|
1453
|
+
}
|
|
1454
|
+
for (const k of ["inputTokenRatio", "outputTokens", "durationMs", "promptCharRatio"]) {
|
|
1455
|
+
if (g[k] === null !== (p90[k] === null)) return false;
|
|
1456
|
+
if (g[k] !== null && p90[k] < g[k]) return false;
|
|
1457
|
+
}
|
|
1458
|
+
if (g.inputTokenRatio > MAX_INPUT_TOKENS || p90.inputTokenRatio > MAX_INPUT_TOKENS || g.outputTokens > MAX_OUTPUT_TOKENS || p90.outputTokens > MAX_OUTPUT_TOKENS || g.durationMs !== null && p90.durationMs > MAX_DURATION_MS || g.promptCharRatio !== null && p90.promptCharRatio > MAX_INPUT_CHARS) return false;
|
|
1459
|
+
return true;
|
|
1460
|
+
}
|
|
1461
|
+
function predictResources(evidence, {
|
|
1462
|
+
provider,
|
|
1463
|
+
model,
|
|
1464
|
+
reasoningEffort = "",
|
|
1465
|
+
channel = "harness-llm",
|
|
1466
|
+
type = "general",
|
|
1467
|
+
purpose = "",
|
|
1468
|
+
inputChars
|
|
1469
|
+
} = {}) {
|
|
1470
|
+
if (!isObj(evidence) || evidence.schemaVersion !== SCHEMA_VERSION || !Array.isArray(evidence.resourceGroups)) return null;
|
|
1471
|
+
if (!nonEmpty(provider) || !nonEmpty(model)) return null;
|
|
1472
|
+
if (!effortOk(reasoningEffort)) return null;
|
|
1473
|
+
const ch = normalizeChannel(channel);
|
|
1474
|
+
if (!ch) return null;
|
|
1475
|
+
const ty = nonEmpty(type) ? type : "general";
|
|
1476
|
+
const pu = typeof purpose === "string" ? purpose : "";
|
|
1477
|
+
const minSamples = evidence.minSamples;
|
|
1478
|
+
if (!Number.isInteger(minSamples) || minSamples < 1 || minSamples > 1e3) return null;
|
|
1479
|
+
void inputChars;
|
|
1480
|
+
for (const g of evidence.resourceGroups) {
|
|
1481
|
+
if (!validateGroup(g)) continue;
|
|
1482
|
+
const id2 = g.identity;
|
|
1483
|
+
if (id2.provider === provider && id2.model === model && id2.reasoningEffort === reasoningEffort && id2.channel === ch && id2.type === ty && id2.purpose === pu) {
|
|
1484
|
+
if (!Number.isInteger(g.sampleCount) || g.sampleCount < minSamples) return null;
|
|
1485
|
+
return {
|
|
1486
|
+
inputTokenRatio: g.inputTokenRatio,
|
|
1487
|
+
outputTokens: g.outputTokens,
|
|
1488
|
+
durationMs: g.durationMs,
|
|
1489
|
+
promptCharRatio: g.promptCharRatio,
|
|
1490
|
+
p90: {
|
|
1491
|
+
inputTokenRatio: g.p90.inputTokenRatio,
|
|
1492
|
+
outputTokens: g.p90.outputTokens,
|
|
1493
|
+
durationMs: g.p90.durationMs,
|
|
1494
|
+
promptCharRatio: g.p90.promptCharRatio
|
|
1495
|
+
},
|
|
1496
|
+
sampleCount: g.sampleCount,
|
|
1497
|
+
source: "recorded-resource-evidence"
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
return null;
|
|
1502
|
+
}
|
|
1503
|
+
function predictQuality(evidence, {
|
|
1504
|
+
text: text7,
|
|
1505
|
+
type = "general",
|
|
1506
|
+
provider,
|
|
1507
|
+
model,
|
|
1508
|
+
reasoningEffort = "",
|
|
1509
|
+
channel = "harness-llm"
|
|
1510
|
+
} = {}) {
|
|
1511
|
+
if (!isObj(evidence) || evidence.schemaVersion !== SCHEMA_VERSION || !Array.isArray(evidence.qualitySamples)) return null;
|
|
1512
|
+
if (typeof text7 !== "string" || text7.length === 0) return null;
|
|
1513
|
+
if (!nonEmpty(provider) || !nonEmpty(model)) return null;
|
|
1514
|
+
if (!effortOk(reasoningEffort)) return null;
|
|
1515
|
+
const ch = normalizeChannel(channel);
|
|
1516
|
+
if (!ch) return null;
|
|
1517
|
+
const ty = nonEmpty(type) ? type : "general";
|
|
1518
|
+
const minSamples = evidence.minSamples;
|
|
1519
|
+
if (!Number.isInteger(minSamples) || minSamples < 1 || minSamples > 1e3) return null;
|
|
1520
|
+
const qfeat = buildFeatures(text7);
|
|
1521
|
+
if (qfeat.length === 0) return null;
|
|
1522
|
+
const matched = [];
|
|
1523
|
+
let sumAll = 0;
|
|
1524
|
+
let nAll = 0;
|
|
1525
|
+
for (const s15 of evidence.qualitySamples) {
|
|
1526
|
+
if (!isObj(s15) || !finite(s15.quality) || s15.quality < 0 || s15.quality > 1 || !validateFeatures(s15.features) || s15.split !== "train") continue;
|
|
1527
|
+
if (s15.provider !== provider || s15.model !== model || s15.reasoningEffort !== reasoningEffort || s15.channel !== ch || s15.type !== ty) continue;
|
|
1528
|
+
sumAll += s15.quality;
|
|
1529
|
+
nAll++;
|
|
1530
|
+
const sim = cosine(qfeat, s15.features);
|
|
1531
|
+
if (sim >= SIM_THRESHOLD) matched.push({ s: s15, sim });
|
|
1532
|
+
}
|
|
1533
|
+
if (matched.length === 0) return null;
|
|
1534
|
+
matched.sort((a, b2) => b2.sim - a.sim);
|
|
1535
|
+
const seenGroup = /* @__PURE__ */ new Set();
|
|
1536
|
+
const neighbors = [];
|
|
1537
|
+
for (const m of matched) {
|
|
1538
|
+
if (seenGroup.has(m.s.groupId)) continue;
|
|
1539
|
+
seenGroup.add(m.s.groupId);
|
|
1540
|
+
neighbors.push(m);
|
|
1541
|
+
if (neighbors.length >= MAX_NEIGHBORS) break;
|
|
1542
|
+
}
|
|
1543
|
+
if (neighbors.length < minSamples) return null;
|
|
1544
|
+
const routeTypeMean = nAll > 0 ? sumAll / nAll : neighbors.reduce((a, b2) => a + b2.s.quality, 0) / neighbors.length;
|
|
1545
|
+
let wsum = 0;
|
|
1546
|
+
let wq = 0;
|
|
1547
|
+
for (const n of neighbors) {
|
|
1548
|
+
wsum += n.sim;
|
|
1549
|
+
wq += n.sim * n.s.quality;
|
|
1550
|
+
}
|
|
1551
|
+
if (!(wsum > 0)) return null;
|
|
1552
|
+
const quality = (wq + SHRINK_PRIOR * routeTypeMean) / (wsum + SHRINK_PRIOR);
|
|
1553
|
+
const meanSim = wsum / neighbors.length;
|
|
1554
|
+
const wmean = wq / wsum;
|
|
1555
|
+
let varSum = 0;
|
|
1556
|
+
for (const n of neighbors) {
|
|
1557
|
+
const d = n.s.quality - wmean;
|
|
1558
|
+
varSum += n.sim * d * d;
|
|
1559
|
+
}
|
|
1560
|
+
const spread = Math.sqrt(varSum / wsum);
|
|
1561
|
+
const clamped = Math.min(1, Math.max(0, quality));
|
|
1562
|
+
return {
|
|
1563
|
+
quality: clamped,
|
|
1564
|
+
sampleCount: neighbors.length,
|
|
1565
|
+
similarity: Math.min(1, Math.max(0, meanSim)),
|
|
1566
|
+
source: "recorded-query-evidence",
|
|
1567
|
+
uncertainty: {
|
|
1568
|
+
kind: "empirical-neighbor-spread",
|
|
1569
|
+
neighborCount: neighbors.length,
|
|
1570
|
+
similarityThreshold: SIM_THRESHOLD,
|
|
1571
|
+
spread,
|
|
1572
|
+
calibrated: false,
|
|
1573
|
+
note: "Empirical neighbor spread; not a calibrated probability."
|
|
1574
|
+
}
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1123
1578
|
// .dsh-plugin/shared/router.mjs
|
|
1124
1579
|
var OBJECTIVE_WEIGHTS = Object.freeze({
|
|
1125
1580
|
simple: Object.freeze({ quality: 0.28, cost: 0.45, latency: 0.14, specialty: 0.04, reasoning: 0.07, risk: 0.02 }),
|
|
@@ -1178,7 +1633,7 @@ var OPENCODE_CATALOG_PROVIDERS = Object.freeze([
|
|
|
1178
1633
|
]);
|
|
1179
1634
|
function classifyTask(text7) {
|
|
1180
1635
|
const value = String(text7 ?? "");
|
|
1181
|
-
if (value.length < 80 && /翻译|解释|translate|explain/i.test(value)) return "general";
|
|
1636
|
+
if (value.length < 80 && /翻译|解释|translate|explain/i.test(value) && !detectTaskTypes(value).some((type) => ["vision", "math", "code", "research"].includes(type))) return "general";
|
|
1182
1637
|
return detectTaskTypes(value)[0] ?? "general";
|
|
1183
1638
|
}
|
|
1184
1639
|
var TASK_TYPE_RULES = Object.freeze([
|
|
@@ -1229,10 +1684,12 @@ function specialtyMatch(model, taskType, liveScores = {}) {
|
|
|
1229
1684
|
return 0.38;
|
|
1230
1685
|
}
|
|
1231
1686
|
function qualityForTask(row, taskType) {
|
|
1687
|
+
if (row?.queryEvidence?.type === taskType) return row.queryEvidence.quality;
|
|
1232
1688
|
const base = asScore(row?.liveScores?.[taskType]) ?? asScore(row?.liveOverall) ?? row?.metadata?.quality ?? row?.baseQuality ?? row?.quality ?? 0;
|
|
1233
1689
|
return row?.qualityBias ? clamp(base + row.qualityBias) : base;
|
|
1234
1690
|
}
|
|
1235
1691
|
function qualitySourceForTask(row, taskType) {
|
|
1692
|
+
if (row?.queryEvidence?.type === taskType) return "recorded-query-evidence";
|
|
1236
1693
|
return asScore(row?.liveScores?.[taskType]) !== void 0 || asScore(row?.liveOverall) !== void 0 ? "livebench" : row?.fallbackQualitySource ?? row?.qualitySource ?? "unknown";
|
|
1237
1694
|
}
|
|
1238
1695
|
function specialtyForTask(row, taskType) {
|
|
@@ -1388,9 +1845,9 @@ function explicitRequirements(text7) {
|
|
|
1388
1845
|
const marker = /^(?:[-*•]\s+|\d{1,2}[.)、](?!\d)\s*|[一二三四五六七八九十]{1,3}[、.)]\s*)(.+)$/u;
|
|
1389
1846
|
const marked = lines.map((line) => marker.exec(line)?.[1]).filter(Boolean).map(requirementText).filter(looksLikeRequirement);
|
|
1390
1847
|
if (marked.length >= 2) return marked;
|
|
1391
|
-
const
|
|
1392
|
-
if (
|
|
1393
|
-
return
|
|
1848
|
+
const plain2 = lines.filter((line) => !/^#{1,6}\s|^```|[::]$/u.test(line));
|
|
1849
|
+
if (plain2.length >= 2 && plain2.every(looksLikeRequirement)) {
|
|
1850
|
+
return plain2.map(requirementText).filter((item) => item.length >= 3);
|
|
1394
1851
|
}
|
|
1395
1852
|
const clauses = value.split(/[;;,,]/u).map(requirementText).filter(Boolean);
|
|
1396
1853
|
if (clauses.length >= 2 && clauses.every(looksLikeRequirement)) {
|
|
@@ -1533,7 +1990,7 @@ function compareText2(left, right) {
|
|
|
1533
1990
|
return a < b2 ? -1 : a > b2 ? 1 : 0;
|
|
1534
1991
|
}
|
|
1535
1992
|
function compareRowsStable(left, right) {
|
|
1536
|
-
return compareText2(routeKey(left.provider, left.model), routeKey(right.provider, right.model));
|
|
1993
|
+
return compareText2(routeKey(left.provider, left.model), routeKey(right.provider, right.model)) || compareText2(String(left.actionId ?? ""), String(right.actionId ?? ""));
|
|
1537
1994
|
}
|
|
1538
1995
|
function reasoningEffortRank(effort) {
|
|
1539
1996
|
const normalized2 = String(effort ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
|
|
@@ -1559,6 +2016,13 @@ function selectReasoningEffort(efforts, preferred = "medium") {
|
|
|
1559
2016
|
}
|
|
1560
2017
|
function reasoningDecision(row, task) {
|
|
1561
2018
|
const preferred = String(task.preferredReasoningEffort ?? "medium");
|
|
2019
|
+
if (row.reasoningExecution === "unsupported-cli" || row.reasoningExecution === "default") return {
|
|
2020
|
+
reasoningEffort: void 0,
|
|
2021
|
+
reasoningFit: 0.55,
|
|
2022
|
+
preferredReasoningEffort: preferred,
|
|
2023
|
+
multiplier: REASONING_EFFORT_MULTIPLIERS.medium,
|
|
2024
|
+
reasoningExecutionNotice: row.reasoningExecution === "default" ? "\u6307\u5B9A\u6A21\u578B\u4F7F\u7528\u9002\u914D\u5668\u9ED8\u8BA4\u63A8\u7406\u6863\u4F4D\u3002" : "CLI \u63A8\u7406\u6863\u4F4D\u5C1A\u65E0\u7ECF\u9A8C\u8BC1\u7684\u6620\u5C04\uFF0C\u6309\u5382\u5546\u9ED8\u8BA4\u6863\u4F4D\u6267\u884C\u3002"
|
|
2025
|
+
};
|
|
1562
2026
|
const efforts = Array.isArray(row.reasoningEfforts) ? row.reasoningEfforts : [];
|
|
1563
2027
|
if (efforts.length === 0) {
|
|
1564
2028
|
const knownUnsupported = row.reasoningKnown === true;
|
|
@@ -1571,7 +2035,7 @@ function reasoningDecision(row, task) {
|
|
|
1571
2035
|
};
|
|
1572
2036
|
}
|
|
1573
2037
|
const preferredRank = reasoningEffortRank(preferred);
|
|
1574
|
-
const chosen = selectReasoningEffort(efforts, preferred);
|
|
2038
|
+
const chosen = Object.hasOwn(row, "actionEffort") ? row.actionEffort : selectReasoningEffort(efforts, preferred);
|
|
1575
2039
|
const distance = Math.abs(reasoningEffortRank(chosen) - preferredRank);
|
|
1576
2040
|
return {
|
|
1577
2041
|
reasoningEffort: chosen,
|
|
@@ -1589,16 +2053,88 @@ function candidateUtility(row, task, weights, cacheReadRatio = 0, cacheWriteRati
|
|
|
1589
2053
|
const reasoning = reasoningDecision(row, task);
|
|
1590
2054
|
const reference = taskCost({ pricing: COST_REFERENCE_PRICING, reasoningKnown: true, reasoningEfforts: [] }, task, text7, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1591
2055
|
const cost = row.pricing === null ? 0 : 1 / (1 + taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio) / Math.max(reference, 1e-12));
|
|
1592
|
-
const
|
|
2056
|
+
const resources = resourceTokenBudget(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio);
|
|
2057
|
+
const latencyUtility = Number.isFinite(resources.estimatedLatencyMs) ? 1 / (1 + resources.estimatedLatencyMs / 1e4) : 1 - clamp(row.latency * reasoning.multiplier.latency);
|
|
2058
|
+
const score = weights.quality * quality + weights.cost * cost + weights.latency * latencyUtility + weights.specialty * specialtyForTask(row, task.type) + (weights.reasoning ?? 0) * reasoning.reasoningFit - weights.risk * row.risk - qualityGap * (task.criticality ?? 0.75) + preferenceAdjustment;
|
|
1593
2059
|
return { score, floor, qualityGap, preferenceAdjustment, ...reasoning };
|
|
1594
2060
|
}
|
|
1595
2061
|
function taskCost(row, task, text7, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
1596
2062
|
if (row?.pricing === null) return 0;
|
|
1597
|
-
const
|
|
1598
|
-
const tokens = taskTokenBudget(text7, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity, cacheReadRatio, cacheWriteRatio);
|
|
2063
|
+
const tokens = resourceTokenBudget(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1599
2064
|
return row === null ? 0 : ((tokens.inputTokens - tokens.cacheReadTokens - tokens.cacheWriteTokens) * row.pricing.input + tokens.cacheReadTokens * row.pricing.cacheRead + tokens.cacheWriteTokens * row.pricing.cacheWrite + tokens.outputTokens * row.pricing.output) / 1e6;
|
|
1600
2065
|
}
|
|
1601
|
-
function
|
|
2066
|
+
function resourceTokenBudget(row, task, text7, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
2067
|
+
const effort = row ? reasoningDecision(row, task).reasoningEffort : void 0;
|
|
2068
|
+
const fallback = taskTokenBudget(text7, { ...task, reasoningEffort: effort }, complexity, cacheReadRatio, cacheWriteRatio);
|
|
2069
|
+
if (!row?.routingEvidence) return { ...fallback, estimateSource: "heuristic", resourceSampleCount: 0 };
|
|
2070
|
+
const key = JSON.stringify([task.type, task.purpose, effort ?? "", String(text7).length, cacheReadRatio, cacheWriteRatio]);
|
|
2071
|
+
if (row.resourceCache.has(key)) return row.resourceCache.get(key);
|
|
2072
|
+
const observed = predictResources(row.routingEvidence, {
|
|
2073
|
+
provider: row.provider,
|
|
2074
|
+
model: row.model,
|
|
2075
|
+
reasoningEffort: effort ?? "",
|
|
2076
|
+
channel: row.executionChannel ?? "harness-llm",
|
|
2077
|
+
type: task.type,
|
|
2078
|
+
purpose: task.purpose,
|
|
2079
|
+
inputChars: String(text7).length
|
|
2080
|
+
});
|
|
2081
|
+
let result = { ...fallback, estimateSource: "heuristic", resourceSampleCount: 0 };
|
|
2082
|
+
if (observed) {
|
|
2083
|
+
const promptRatio = observed.p90?.promptCharRatio ?? observed.promptCharRatio;
|
|
2084
|
+
const chars = Number.isFinite(promptRatio) ? String(text7).length * promptRatio : fallback.inputTokens * 3.7;
|
|
2085
|
+
const inputTokens = Math.ceil(chars * observed.p90.inputTokenRatio);
|
|
2086
|
+
const outputTokens = Math.ceil(observed.p90.outputTokens);
|
|
2087
|
+
if (Number.isSafeInteger(inputTokens) && inputTokens >= 0 && Number.isSafeInteger(outputTokens) && outputTokens >= 0) {
|
|
2088
|
+
const ratios = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
|
|
2089
|
+
const cacheReadTokens = Math.min(inputTokens, Math.round(inputTokens * ratios.read));
|
|
2090
|
+
const cacheWriteTokens = Math.min(inputTokens - cacheReadTokens, Math.round(inputTokens * ratios.write));
|
|
2091
|
+
result = {
|
|
2092
|
+
inputTokens,
|
|
2093
|
+
outputTokens,
|
|
2094
|
+
cacheReadTokens,
|
|
2095
|
+
cacheWriteTokens,
|
|
2096
|
+
estimateSource: observed.source,
|
|
2097
|
+
resourceSampleCount: observed.sampleCount,
|
|
2098
|
+
estimatedLatencyMs: observed.p90.durationMs,
|
|
2099
|
+
empiricalQuantile: 0.9
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
row.resourceCache.set(key, result);
|
|
2104
|
+
return result;
|
|
2105
|
+
}
|
|
2106
|
+
function taskActions(row, task) {
|
|
2107
|
+
const text7 = task.objective || row.routingText;
|
|
2108
|
+
const key = JSON.stringify([task.type, task.purpose, task.preferredReasoningEffort, text7]);
|
|
2109
|
+
if (row.actionCache.has(key)) return row.actionCache.get(key);
|
|
2110
|
+
const nearest = reasoningDecision(row, task).reasoningEffort;
|
|
2111
|
+
const qualityAt = (effort) => {
|
|
2112
|
+
const qualityKey = JSON.stringify([task.type, effort ?? "", text7]);
|
|
2113
|
+
if (!row.qualityCache.has(qualityKey)) row.qualityCache.set(qualityKey, predictQuality(row.routingEvidence, {
|
|
2114
|
+
text: text7,
|
|
2115
|
+
type: task.type,
|
|
2116
|
+
provider: row.provider,
|
|
2117
|
+
model: row.model,
|
|
2118
|
+
reasoningEffort: effort ?? "",
|
|
2119
|
+
channel: row.executionChannel ?? "harness-llm"
|
|
2120
|
+
}));
|
|
2121
|
+
return row.qualityCache.get(qualityKey);
|
|
2122
|
+
};
|
|
2123
|
+
let alternatives = [];
|
|
2124
|
+
if (row.reasoningExecution === "api") alternatives = (row.reasoningEfforts ?? []).map((effort) => ({ effort, quality: qualityAt(effort) })).filter((item) => item.quality);
|
|
2125
|
+
const joint = alternatives.length >= 2;
|
|
2126
|
+
const actions = joint ? alternatives : [{ effort: nearest, quality: qualityAt(nearest) }];
|
|
2127
|
+
const variants = actions.map(({ effort, quality }) => ({
|
|
2128
|
+
...row,
|
|
2129
|
+
actionEffort: effort,
|
|
2130
|
+
actionId: JSON.stringify([row.provider, row.model, effort ?? null]),
|
|
2131
|
+
jointEffort: joint,
|
|
2132
|
+
queryEvidence: quality ? { ...quality, type: task.type } : null
|
|
2133
|
+
}));
|
|
2134
|
+
row.actionCache.set(key, variants);
|
|
2135
|
+
return variants;
|
|
2136
|
+
}
|
|
2137
|
+
function dominates2(left, right, task, text7, complexity, cacheReadRatio, cacheWriteRatio) {
|
|
1602
2138
|
if (left.pricing === null || right.pricing === null) return false;
|
|
1603
2139
|
const leftReasoning = reasoningDecision(left, task);
|
|
1604
2140
|
const rightReasoning = reasoningDecision(right, task);
|
|
@@ -1623,7 +2159,8 @@ function dominates(left, right, task, text7, complexity, cacheReadRatio, cacheWr
|
|
|
1623
2159
|
return noWorse && strictlyBetter;
|
|
1624
2160
|
}
|
|
1625
2161
|
function eligibleRowsForTask(rows, task) {
|
|
1626
|
-
|
|
2162
|
+
const eligible = task.type === "vision" ? rows.filter((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image")) : rows;
|
|
2163
|
+
return eligible.flatMap((row) => taskActions(row, task));
|
|
1627
2164
|
}
|
|
1628
2165
|
function candidatePool(rows, task, weights, text7, complexity, cacheReadRatio, cacheWriteRatio, dependencySensitive = false) {
|
|
1629
2166
|
const eligibleRows = eligibleRowsForTask(rows, task);
|
|
@@ -1636,7 +2173,7 @@ function candidatePool(rows, task, weights, text7, complexity, cacheReadRatio, c
|
|
|
1636
2173
|
decision: candidateUtility(row, task, taskWeights, cacheReadRatio, cacheWriteRatio, text7, complexity),
|
|
1637
2174
|
cost: taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio)
|
|
1638
2175
|
}));
|
|
1639
|
-
const frontier = dependencySensitive ? scored : scored.filter((item) => !scored.some((other) => other !== item && other.decision.score >= item.decision.score &&
|
|
2176
|
+
const frontier = dependencySensitive ? scored : scored.filter((item) => !scored.some((other) => other !== item && other.decision.score >= item.decision.score && dominates2(other.row, item.row, task, text7, complexity, cacheReadRatio, cacheWriteRatio)));
|
|
1640
2177
|
const essential = [
|
|
1641
2178
|
scored.filter((item) => item.row.pricing !== null).sort((left, right) => left.cost - right.cost || compareRowsStable(left.row, right.row))[0],
|
|
1642
2179
|
scored.slice().sort((left, right) => right.decision.score - left.decision.score || compareRowsStable(left.row, right.row))[0],
|
|
@@ -1661,6 +2198,8 @@ function solveAssignments({ rows, tasks, weights, text: text7, complexity, budge
|
|
|
1661
2198
|
route: routeKey(option.row.provider, option.row.model),
|
|
1662
2199
|
score: option.decision.score,
|
|
1663
2200
|
cost: option.cost,
|
|
2201
|
+
actionId: option.row.actionId,
|
|
2202
|
+
handoffRoute: routeKey(option.row.provider, option.row.model),
|
|
1664
2203
|
qualityShortfall: Math.max(0, option.decision.floor - qualityForTask(option.row, tasks[index].type)),
|
|
1665
2204
|
pricingKnown: option.row.pricing !== null,
|
|
1666
2205
|
payload: option
|
|
@@ -1670,7 +2209,7 @@ function solveAssignments({ rows, tasks, weights, text: text7, complexity, budge
|
|
|
1670
2209
|
...result,
|
|
1671
2210
|
assignments: result.choices.map((choice, index) => ({
|
|
1672
2211
|
task: tasks[index],
|
|
1673
|
-
row: choice.payload.row,
|
|
2212
|
+
row: { ...choice.payload.row, estimatedCost: choice.payload.row.pricing === null ? null : choice.cost },
|
|
1674
2213
|
decision: { ...choice.payload.decision, relaxed: choice.qualityShortfall > 0 },
|
|
1675
2214
|
estimatedCost: choice.cost,
|
|
1676
2215
|
handoffPenalty: choice.handoffPenalty
|
|
@@ -1680,7 +2219,7 @@ function solveAssignments({ rows, tasks, weights, text: text7, complexity, budge
|
|
|
1680
2219
|
minimumFeasibleCost: result.minimumCostLowerBound
|
|
1681
2220
|
};
|
|
1682
2221
|
}
|
|
1683
|
-
function buildPlan({ text: text7 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", dataVersions = null, learning = null, budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0, preset = DEFAULT_ROUTING_PRESET } = {}) {
|
|
2222
|
+
function buildPlan({ text: text7 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", dataVersions = null, learning = null, routingEvidence = null, budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0, preset = DEFAULT_ROUTING_PRESET } = {}) {
|
|
1684
2223
|
const presetId = normalizeRoutingPreset(preset);
|
|
1685
2224
|
const firstLine = String(text7 ?? "").split(/\r?\n/u)[0].trim();
|
|
1686
2225
|
const transformOnly = /^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(firstLine) && !/(?:执行|完成|实施|分配)/u.test(firstLine);
|
|
@@ -1696,6 +2235,8 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1696
2235
|
return {
|
|
1697
2236
|
provider: String(entry.provider ?? ""),
|
|
1698
2237
|
model: String(entry.model ?? ""),
|
|
2238
|
+
executionChannel: ["harness-llm", "official-cli"].includes(entry.executionChannel) ? entry.executionChannel : void 0,
|
|
2239
|
+
reasoningExecution: ["api", "unsupported-cli", "default"].includes(entry.reasoningExecution) ? entry.reasoningExecution : void 0,
|
|
1699
2240
|
benchmarkModel: typeof entry.benchmarkModel === "string" ? entry.benchmarkModel : void 0,
|
|
1700
2241
|
reasoningEfforts: [...new Set(reasoningEfforts)],
|
|
1701
2242
|
defaultReasoningEffort: entry.defaultReasoningEffort === void 0 ? void 0 : String(entry.defaultReasoningEffort),
|
|
@@ -1758,6 +2299,13 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1758
2299
|
reasoningEfforts: route.reasoningEfforts,
|
|
1759
2300
|
defaultReasoningEffort: route.defaultReasoningEffort,
|
|
1760
2301
|
reasoningKnown: route.reasoningKnown,
|
|
2302
|
+
reasoningExecution: route.reasoningExecution,
|
|
2303
|
+
executionChannel: route.executionChannel,
|
|
2304
|
+
routingEvidence,
|
|
2305
|
+
routingText: text7,
|
|
2306
|
+
actionCache: /* @__PURE__ */ new Map(),
|
|
2307
|
+
qualityCache: /* @__PURE__ */ new Map(),
|
|
2308
|
+
resourceCache: /* @__PURE__ */ new Map(),
|
|
1761
2309
|
inputModalities: route.inputModalities,
|
|
1762
2310
|
pricing: pricingRow,
|
|
1763
2311
|
score: 0,
|
|
@@ -1834,13 +2382,14 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1834
2382
|
recommendedReasoningEffort: decision?.reasoningEffort,
|
|
1835
2383
|
preferredReasoningEffort: decision?.preferredReasoningEffort ?? task.preferredReasoningEffort,
|
|
1836
2384
|
reasoningFit: Number(Number(decision?.reasoningFit ?? 0).toFixed(3)),
|
|
2385
|
+
...decision?.reasoningExecutionNotice ? { reasoningExecutionNotice: decision.reasoningExecutionNotice } : {},
|
|
1837
2386
|
purpose: task.purpose,
|
|
1838
2387
|
criticality: task.criticality,
|
|
1839
2388
|
qualityFloor: Number(task.qualityFloor.toFixed(3)),
|
|
1840
2389
|
dependsOn: [...task.dependsOn ?? []]
|
|
1841
2390
|
}));
|
|
1842
2391
|
const costBreakdown = assignments.map(({ task, row, decision, estimatedCost, handoffPenalty }, index) => {
|
|
1843
|
-
const tokens =
|
|
2392
|
+
const tokens = resourceTokenBudget(row, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1844
2393
|
const taskEstimate = estimatedCost ?? taskCost(row, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1845
2394
|
return {
|
|
1846
2395
|
stage: index + 1,
|
|
@@ -1856,6 +2405,11 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1856
2405
|
cacheReadTokens: tokens.cacheReadTokens,
|
|
1857
2406
|
cacheWriteTokens: tokens.cacheWriteTokens,
|
|
1858
2407
|
outputTokens: tokens.outputTokens,
|
|
2408
|
+
estimateSource: tokens.estimateSource,
|
|
2409
|
+
resourceSampleCount: tokens.resourceSampleCount,
|
|
2410
|
+
...Number.isFinite(tokens.estimatedLatencyMs) ? { estimatedLatencyMs: tokens.estimatedLatencyMs } : {},
|
|
2411
|
+
...tokens.empiricalQuantile ? { empiricalQuantile: tokens.empiricalQuantile } : {},
|
|
2412
|
+
...row?.queryEvidence ? { queryEvidenceCount: row.queryEvidence.sampleCount, querySimilarity: row.queryEvidence.similarity } : {},
|
|
1859
2413
|
estimatedCost: row?.pricing === null || row === null ? null : Number(taskEstimate.toFixed(6)),
|
|
1860
2414
|
quality: qualitySourceForTask(row, task.type) === "unknown" || row === null ? null : Number(qualityForTask(row, task.type).toFixed(3)),
|
|
1861
2415
|
qualitySource: qualitySourceForTask(row, task.type),
|
|
@@ -1870,7 +2424,8 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1870
2424
|
return { task, strongest };
|
|
1871
2425
|
});
|
|
1872
2426
|
const baselineCost = baselineRows.every((item) => item.strongest?.pricing !== null && item.strongest !== null) ? baselineRows.reduce((sum, { task, strongest }) => sum + taskCost(strongest, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio), 0) : null;
|
|
1873
|
-
const
|
|
2427
|
+
const knownQualitySources = ["livebench", "route", "user", "recorded-query-evidence"];
|
|
2428
|
+
const qualityEvidenceComplete = assignments.length > 0 && assignments.every(({ row, task }) => knownQualitySources.includes(qualitySourceForTask(row, task.type))) && baselineRows.every(({ strongest, task }) => knownQualitySources.includes(qualitySourceForTask(strongest, task.type)));
|
|
1874
2429
|
const budgetExceeded = Number(budgetUsd) > 0 && totalEstimate !== null ? totalEstimate > Number(budgetUsd) : null;
|
|
1875
2430
|
const savings = baselineCost === null || totalEstimate === null || !qualityEvidenceComplete ? null : baselineCost <= 0 ? 0 : clamp((baselineCost - totalEstimate) / baselineCost);
|
|
1876
2431
|
const paretoPruned = (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.pruned, 0);
|
|
@@ -1885,7 +2440,13 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1885
2440
|
taskType,
|
|
1886
2441
|
taskTypes: [...new Set(taskNodes.map((task) => task.type).filter((type) => type !== "reasoning"))],
|
|
1887
2442
|
objectiveWeights: weights,
|
|
1888
|
-
candidates: rows
|
|
2443
|
+
candidates: eligibleRowsForTask(rows, taskNodes[0]).map((row) => ({
|
|
2444
|
+
...row,
|
|
2445
|
+
score: candidateUtility(row, taskNodes[0], weights, cacheReadRatio, cacheWriteRatio, text7, complexity.band).score,
|
|
2446
|
+
quality: qualityForTask(row, taskNodes[0].type),
|
|
2447
|
+
qualitySource: qualitySourceForTask(row, taskNodes[0].type),
|
|
2448
|
+
estimatedCost: row.pricing === null ? null : taskCost(row, taskNodes[0], text7, complexity.band, cacheReadRatio, cacheWriteRatio)
|
|
2449
|
+
})).sort((left, right) => right.score - left.score || compareRowsStable(left, right)).slice(0, 8).map((row) => {
|
|
1889
2450
|
const decision = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band], preferredReasoningEffort: complexity.band === "simple" ? "low" : "medium" }, weights, cacheReadRatio, cacheWriteRatio, text7, complexity.band);
|
|
1890
2451
|
return { provider: row.provider, model: row.model, score: Number(row.score.toFixed(3)), preferenceAdjustment: decision.preferenceAdjustment, quality: row.qualitySource === "unknown" ? null : Number(row.quality.toFixed(3)), qualitySource: row.qualitySource, specialty: Number(row.specialty.toFixed(3)), reasoningEffort: decision.reasoningEffort, preferredReasoningEffort: decision.preferredReasoningEffort, reasoningFit: Number(decision.reasoningFit.toFixed(3)), reasoningKnown: row.reasoningKnown, reasoningEfforts: row.reasoningEfforts, estimatedCost: row.estimatedCost === null ? null : Number(row.estimatedCost.toFixed(6)), inputPrice: row.pricing?.input ?? null, outputPrice: row.pricing?.output ?? null, pricingSource: row.pricingSource, pricingVersion: row.pricingVersion, pricingAsOf: row.snapshotAsOf };
|
|
1891
2452
|
}),
|
|
@@ -1897,6 +2458,11 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1897
2458
|
costBreakdown,
|
|
1898
2459
|
optimization: {
|
|
1899
2460
|
dataVersions,
|
|
2461
|
+
evidenceRevision: routingEvidence?.revision ?? null,
|
|
2462
|
+
qualityEvidenceCount: assignments.filter(({ row }) => row.queryEvidence).length,
|
|
2463
|
+
resourceEvidenceCount: costBreakdown.filter((item) => item.estimateSource === "recorded-resource-evidence").length,
|
|
2464
|
+
jointEffortCandidates: (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.options.filter((item) => item.row.jointEffort).length, 0),
|
|
2465
|
+
uncertaintySemantics: "empirical-prediction-not-calibrated-probability-or-joint-budget-guarantee",
|
|
1900
2466
|
personalization: learning ? {
|
|
1901
2467
|
policyVersion: learning.policyVersion,
|
|
1902
2468
|
revision: learning.revision,
|
|
@@ -2009,12 +2575,14 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2009
2575
|
liveBenchError = "",
|
|
2010
2576
|
dataVersions = null,
|
|
2011
2577
|
learning = null,
|
|
2578
|
+
routingEvidence = null,
|
|
2012
2579
|
cacheReadRatio = 0,
|
|
2013
2580
|
cacheWriteRatio = 0,
|
|
2014
2581
|
directProvider = "",
|
|
2015
2582
|
directModel = "",
|
|
2016
2583
|
preset = "balanced",
|
|
2017
|
-
loggedOutToolIds = []
|
|
2584
|
+
loggedOutToolIds = [],
|
|
2585
|
+
forceOfficialCli = false
|
|
2018
2586
|
} = {}) {
|
|
2019
2587
|
const taskText = clean2(task);
|
|
2020
2588
|
if (!taskText) throw new Error("task must contain text");
|
|
@@ -2036,13 +2604,28 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2036
2604
|
const channelOf = (provider, model) => {
|
|
2037
2605
|
const route = routes.find((item) => item.provider === provider && item.model === model);
|
|
2038
2606
|
const key = `${String(provider ?? "")}\0${String(model ?? "")}\0${route?.execution ?? ""}`;
|
|
2039
|
-
if (!channelCache.has(key))
|
|
2607
|
+
if (!channelCache.has(key)) {
|
|
2608
|
+
const tool = forceOfficialCli ? toolForProvider(provider) : null;
|
|
2609
|
+
channelCache.set(key, tool ? {
|
|
2610
|
+
kind: "official-cli",
|
|
2611
|
+
tool: tool.id,
|
|
2612
|
+
label: tool.label,
|
|
2613
|
+
detail: "\u5B98\u65B9 CLI \u56E2\u961F\u8BA1\u5212\u4EC5\u901A\u8FC7\u5DF2\u6838\u9A8C\u7684\u5B98\u65B9 CLI \u6267\u884C\uFF1B\u4F7F\u7528\u5382\u5546\u9ED8\u8BA4\u63A8\u7406\u6863\u4F4D\u3002"
|
|
2614
|
+
} : channelForProvider(provider, installedIds, runnableToolIds, route, loggedOutToolIds));
|
|
2615
|
+
}
|
|
2040
2616
|
return channelCache.get(key);
|
|
2041
2617
|
};
|
|
2042
2618
|
const needsImage = detectTaskTypes(taskText).includes("vision");
|
|
2043
2619
|
const plan = buildPlan({
|
|
2044
2620
|
text: taskText,
|
|
2045
|
-
available: routes
|
|
2621
|
+
available: routes.map((route) => {
|
|
2622
|
+
const channel = channelOf(route.provider, route.model);
|
|
2623
|
+
return {
|
|
2624
|
+
...route,
|
|
2625
|
+
executionChannel: channel.kind,
|
|
2626
|
+
reasoningExecution: directRoute ? "default" : channel.kind === "harness-llm" ? "api" : "unsupported-cli"
|
|
2627
|
+
};
|
|
2628
|
+
}),
|
|
2046
2629
|
mode: directRoute ? "single" : selectedMode,
|
|
2047
2630
|
budgetUsd: Math.max(0, Number.isFinite(budgetUsd) ? budgetUsd : 0),
|
|
2048
2631
|
pricing,
|
|
@@ -2050,6 +2633,7 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2050
2633
|
liveBenchError,
|
|
2051
2634
|
dataVersions,
|
|
2052
2635
|
learning,
|
|
2636
|
+
routingEvidence,
|
|
2053
2637
|
cacheReadRatio,
|
|
2054
2638
|
cacheWriteRatio,
|
|
2055
2639
|
preset
|
|
@@ -2087,6 +2671,7 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2087
2671
|
recommendedModel: item.recommended,
|
|
2088
2672
|
estimatedCost: plan.costBreakdown[index]?.estimatedCost ?? null,
|
|
2089
2673
|
...item.recommendedReasoningEffort ? { recommendedReasoningEffort: item.recommendedReasoningEffort } : {},
|
|
2674
|
+
...item.reasoningExecutionNotice ? { reasoningExecutionNotice: item.reasoningExecutionNotice } : {},
|
|
2090
2675
|
...annotate(channelOf(item.recommendedProvider, item.recommended)),
|
|
2091
2676
|
verificationChecklist: item.purpose === "synthesis" ? ["\u6838\u5BF9\u5404\u5DE5\u4F5C\u5305\u4EA4\u4ED8\u7269\u4E0E\u4F9D\u8D56", "\u8BB0\u5F55\u51B2\u7A81\u3001\u672A\u89E3\u51B3\u4E8B\u9879\u548C\u6700\u7EC8\u9A8C\u6536\u7ED3\u679C"] : item.type === "code" ? ["\u8BF4\u660E\u6539\u52A8\u6587\u4EF6\u4E0E\u63A5\u53E3", "\u8FD0\u884C\u4E0E\u6539\u52A8\u76F8\u5173\u7684\u9A8C\u8BC1\u5E76\u8BB0\u5F55\u7ED3\u679C", "\u5217\u51FA\u5C1A\u672A\u5B8C\u6210\u7684\u8FB9\u754C\u60C5\u51B5"] : item.type === "research" ? ["\u5217\u51FA\u6765\u6E90\u3001\u65E5\u671F\u548C\u53EF\u6838\u5BF9\u7684\u7ED3\u8BBA", "\u6807\u51FA\u63A8\u65AD\u4E0E\u4E0D\u786E\u5B9A\u4E8B\u9879"] : ["\u5217\u51FA\u4EA4\u4ED8\u5185\u5BB9\u548C\u9A8C\u6536\u4F9D\u636E", "\u6807\u51FA\u672A\u5B8C\u6210\u4E8B\u9879"]
|
|
2092
2677
|
}))
|
|
@@ -2094,13 +2679,68 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2094
2679
|
};
|
|
2095
2680
|
}
|
|
2096
2681
|
|
|
2682
|
+
// .dsh-plugin/shared/package-assignments.mjs
|
|
2683
|
+
var plain = (value) => value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
2684
|
+
var safeText = (value, limit) => typeof value === "string" && value.trim().length > 0 && value.trim().length <= limit && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
2685
|
+
var safeKey = (key) => typeof key === "string" && key === key.trim() && safeText(key, 128) && !["__proto__", "constructor", "prototype"].includes(key);
|
|
2686
|
+
function parsePackageAssignments(value) {
|
|
2687
|
+
if (value === void 0) return void 0;
|
|
2688
|
+
if (!plain(value)) throw new TypeError("packageAssignments must be an object");
|
|
2689
|
+
const keys = Reflect.ownKeys(value);
|
|
2690
|
+
if (!keys.length || keys.length > 32 || keys.some((key) => !safeKey(key))) {
|
|
2691
|
+
throw new TypeError("packageAssignments requires 1..32 safe package ids");
|
|
2692
|
+
}
|
|
2693
|
+
const result = {};
|
|
2694
|
+
for (const id2 of keys) {
|
|
2695
|
+
const target = value[id2];
|
|
2696
|
+
if (!plain(target)) throw new TypeError(`Invalid package assignment: ${id2}`);
|
|
2697
|
+
const allowed = target.kind === "api" ? ["kind", "provider", "model"] : target.kind === "tool" ? ["kind", "toolId"] : null;
|
|
2698
|
+
if (!allowed || Reflect.ownKeys(target).some((key) => !allowed.includes(key))) {
|
|
2699
|
+
throw new TypeError(`Unsupported package assignment fields: ${id2}`);
|
|
2700
|
+
}
|
|
2701
|
+
if (target.kind === "api") {
|
|
2702
|
+
if (!safeText(target.provider, 160) || !safeText(target.model, 240)) {
|
|
2703
|
+
throw new TypeError(`API assignment requires provider and model: ${id2}`);
|
|
2704
|
+
}
|
|
2705
|
+
result[id2] = { kind: "api", provider: target.provider.trim(), model: target.model.trim() };
|
|
2706
|
+
} else {
|
|
2707
|
+
if (!safeText(target.toolId, 64) || !getOfficialTool(target.toolId.trim())) {
|
|
2708
|
+
throw new TypeError(`Unknown official tool assignment: ${id2}`);
|
|
2709
|
+
}
|
|
2710
|
+
result[id2] = { kind: "tool", toolId: target.toolId.trim() };
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
return result;
|
|
2714
|
+
}
|
|
2715
|
+
function packagePlanKey(plan, task = "") {
|
|
2716
|
+
const packages = plan?.team?.workPackages;
|
|
2717
|
+
if (plan?.routingBypassed || plan?.mode === "direct" || !Array.isArray(packages) || !packages.length) return null;
|
|
2718
|
+
const fields = packages.map((item) => [
|
|
2719
|
+
item?.id ?? "",
|
|
2720
|
+
item?.name ?? "",
|
|
2721
|
+
item?.objective ?? "",
|
|
2722
|
+
item?.type ?? "",
|
|
2723
|
+
item?.purpose ?? "",
|
|
2724
|
+
Array.isArray(item?.dependsOn) ? [...item.dependsOn] : []
|
|
2725
|
+
]);
|
|
2726
|
+
const text7 = JSON.stringify([String(task ?? "").trim(), fields]);
|
|
2727
|
+
let first = 2166136261;
|
|
2728
|
+
let second = 2246822507;
|
|
2729
|
+
for (let index = 0; index < text7.length; index++) {
|
|
2730
|
+
const code = text7.charCodeAt(index);
|
|
2731
|
+
first = Math.imul(first ^ code, 16777619) >>> 0;
|
|
2732
|
+
second = Math.imul(second ^ code, 3266489909) >>> 0;
|
|
2733
|
+
}
|
|
2734
|
+
return `package-plan-v1-${first.toString(16).padStart(8, "0")}${second.toString(16).padStart(8, "0")}`;
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2097
2737
|
// .dsh-plugin/shared/run-ledger.mjs
|
|
2098
|
-
var
|
|
2738
|
+
var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2099
2739
|
var routeKey2 = (provider, model) => `${String(provider ?? "")}\0${String(model ?? "")}`;
|
|
2100
2740
|
var MAX_SPENDING_DAYS = 90;
|
|
2101
2741
|
var MAX_SPENDING_MONTHS = 24;
|
|
2102
2742
|
function periodSpending(value) {
|
|
2103
|
-
const amount = (field2) =>
|
|
2743
|
+
const amount = (field2) => finite2(value?.[field2]) && value[field2] >= 0 ? value[field2] : 0;
|
|
2104
2744
|
return {
|
|
2105
2745
|
costUsd: amount("costUsd"),
|
|
2106
2746
|
unknown: Math.floor(amount("unknown")),
|
|
@@ -2120,9 +2760,9 @@ function formatUsd(value) {
|
|
|
2120
2760
|
}
|
|
2121
2761
|
function budgetCheck({ estimateUsd = null, spent = { today: 0, month: 0 }, dailyLimitUsd = 0, monthlyLimitUsd = 0 } = {}) {
|
|
2122
2762
|
const limits = [];
|
|
2123
|
-
if (
|
|
2124
|
-
if (
|
|
2125
|
-
const estimateKnown =
|
|
2763
|
+
if (finite2(dailyLimitUsd) && dailyLimitUsd > 0) limits.push({ period: "daily", label: "\u4ECA\u65E5", limit: dailyLimitUsd, spent: spent.today ?? 0 });
|
|
2764
|
+
if (finite2(monthlyLimitUsd) && monthlyLimitUsd > 0) limits.push({ period: "monthly", label: "\u672C\u6708", limit: monthlyLimitUsd, spent: spent.month ?? 0 });
|
|
2765
|
+
const estimateKnown = finite2(estimateUsd);
|
|
2126
2766
|
const remaining = limits.length ? Math.max(0, Math.min(...limits.map((item) => item.limit - item.spent))) : null;
|
|
2127
2767
|
const exceeded = limits.find((item) => item.spent >= item.limit || estimateKnown && item.spent + estimateUsd > item.limit) ?? null;
|
|
2128
2768
|
return {
|
|
@@ -2138,12 +2778,12 @@ function applyQualityBiases(routes, biases) {
|
|
|
2138
2778
|
if (!biases || typeof biases !== "object") return routes;
|
|
2139
2779
|
return (Array.isArray(routes) ? routes : []).map((route) => {
|
|
2140
2780
|
const bias = biases[routeKey2(route.provider, route.model)];
|
|
2141
|
-
return
|
|
2781
|
+
return finite2(bias) && bias !== 0 ? { ...route, qualityBias: bias } : route;
|
|
2142
2782
|
});
|
|
2143
2783
|
}
|
|
2144
2784
|
|
|
2145
2785
|
// .dsh-plugin/shared/adaptive-feedback.mjs
|
|
2146
|
-
var
|
|
2786
|
+
var finite3 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2147
2787
|
var clean3 = (value) => typeof value === "string" ? value.trim() : "";
|
|
2148
2788
|
var routeKey3 = (provider, model) => `${provider}\0${model}`;
|
|
2149
2789
|
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -2162,8 +2802,8 @@ function applyFeedbackProfile(routes, profile) {
|
|
|
2162
2802
|
if (!Object.hasOwn(profile.adjustments, key)) return base;
|
|
2163
2803
|
const value = profile.adjustments[key];
|
|
2164
2804
|
if (!record(value)) return base;
|
|
2165
|
-
const limit =
|
|
2166
|
-
const adjustments = Object.fromEntries(Object.entries(value).filter(([, bias]) =>
|
|
2805
|
+
const limit = finite3(profile.maxAdjustment) && profile.maxAdjustment >= 0 && profile.maxAdjustment <= 0.1 ? profile.maxAdjustment : 0.1;
|
|
2806
|
+
const adjustments = Object.fromEntries(Object.entries(value).filter(([, bias]) => finite3(bias) && Math.abs(bias) <= limit));
|
|
2167
2807
|
if (!Object.keys(adjustments).length) return base;
|
|
2168
2808
|
return {
|
|
2169
2809
|
...base,
|
|
@@ -2801,7 +3441,59 @@ function billingSwitchText(item) {
|
|
|
2801
3441
|
if (!note?.reason) return null;
|
|
2802
3442
|
return note.reason;
|
|
2803
3443
|
}
|
|
2804
|
-
function
|
|
3444
|
+
function initialPackageAssignments(plan) {
|
|
3445
|
+
if (plan?.routingBypassed || plan?.mode === "direct") return {};
|
|
3446
|
+
const packages = plan?.team?.workPackages ?? [];
|
|
3447
|
+
if (!packages.length) return {};
|
|
3448
|
+
return parsePackageAssignments(Object.fromEntries(packages.map((item) => [
|
|
3449
|
+
item.id,
|
|
3450
|
+
{ kind: "api", provider: item.recommendedProvider, model: item.recommendedModel }
|
|
3451
|
+
])));
|
|
3452
|
+
}
|
|
3453
|
+
function manualAssignmentOptions(routes = [], toolSnapshot = null, health = null) {
|
|
3454
|
+
const options = [];
|
|
3455
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3456
|
+
for (const route of routes) {
|
|
3457
|
+
if (!route?.provider || !route?.model) continue;
|
|
3458
|
+
const binding = { kind: "api", provider: route.provider, model: route.model };
|
|
3459
|
+
const value = JSON.stringify(binding);
|
|
3460
|
+
if (seen.has(value)) continue;
|
|
3461
|
+
seen.add(value);
|
|
3462
|
+
options.push({ value, binding, label: `${route.provider}/${route.model} \xB7 \u6A21\u578B API`, disabled: false, reason: "" });
|
|
3463
|
+
}
|
|
3464
|
+
for (const tool of OFFICIAL_TOOLS) {
|
|
3465
|
+
const probe = toolSnapshot?.probes?.find((item) => item.id === tool.id);
|
|
3466
|
+
const report = health?.tools?.find((item) => item.id === tool.id);
|
|
3467
|
+
const ready = toolSnapshot?.readiness?.find((item) => item.id === tool.id);
|
|
3468
|
+
const capability = toolSnapshot?.capabilities?.find((item) => item.id === tool.id);
|
|
3469
|
+
const installed = probe ? probe.installed === true : report?.installed === true;
|
|
3470
|
+
const modes = ready?.readyModes ?? ready?.modes ?? capability?.modes;
|
|
3471
|
+
const reason = !installed ? "\u672A\u5B89\u88C5\u6216\u5B89\u88C5\u72B6\u6001\u672A\u77E5" : capability?.supported === false ? capability.reason || "\u4E0D\u652F\u6301\u6258\u7BA1\u6267\u884C" : ready?.ready === false ? ready.reason || "\u6267\u884C\u5165\u53E3\u5C1A\u672A\u5C31\u7EEA" : Array.isArray(modes) && !modes.includes("read-only") ? "\u4E0D\u652F\u6301\u53EA\u8BFB\u4EFB\u52A1" : report?.login?.state === "logged-out" ? "\u5C1A\u672A\u767B\u5F55" : "";
|
|
3472
|
+
const pending = !reason && ready?.ready !== true ? " \xB7 \u5F85\u6267\u884C\u9884\u89C8\u6838\u9A8C" : "";
|
|
3473
|
+
const binding = { kind: "tool", toolId: tool.id };
|
|
3474
|
+
options.push({
|
|
3475
|
+
value: JSON.stringify(binding),
|
|
3476
|
+
binding,
|
|
3477
|
+
disabled: Boolean(reason),
|
|
3478
|
+
reason,
|
|
3479
|
+
label: `${tool.label} \xB7 \u5B98\u65B9\u5DE5\u5177\u9ED8\u8BA4\u6A21\u578B${reason ? `\uFF08${reason}\uFF09` : pending}`
|
|
3480
|
+
});
|
|
3481
|
+
}
|
|
3482
|
+
return options;
|
|
3483
|
+
}
|
|
3484
|
+
function launchRequest({ task, mode, directRoute, budgetUsd, preset, workspace, executor = "routed", executionMode = "read-only", executionEnvironment = "harness", assignmentMode = "algorithm", packageAssignments, packagePlanKey: packagePlanKey2 } = {}) {
|
|
3485
|
+
if (!["algorithm", "manual"].includes(assignmentMode)) throw new Error("\u4E0D\u652F\u6301\u7684\u5206\u914D\u65B9\u5F0F\u3002");
|
|
3486
|
+
let manual = null;
|
|
3487
|
+
if (assignmentMode === "manual") {
|
|
3488
|
+
if (mode === "direct") throw new Error("\u6307\u5B9A\u5355\u4E00\u6A21\u578B\u6A21\u5F0F\u4E0D\u652F\u6301\u624B\u52A8\u5DE5\u4F5C\u5305\u5206\u914D\u3002");
|
|
3489
|
+
if (typeof packagePlanKey2 !== "string" || !packagePlanKey2.trim() || packagePlanKey2.length > 200) throw new Error("\u8BF7\u91CD\u65B0\u751F\u6210\u5DE5\u4F5C\u5305\u540E\u518D\u624B\u52A8\u5206\u914D\u3002");
|
|
3490
|
+
const assignments = parsePackageAssignments(packageAssignments);
|
|
3491
|
+
if (!assignments) throw new Error("\u8BF7\u9009\u62E9\u5DE5\u4F5C\u5305\u6267\u884C\u76EE\u6807\u3002");
|
|
3492
|
+
manual = { assignmentMode: "manual", packagePlanKey: packagePlanKey2, packageAssignments: assignments };
|
|
3493
|
+
executor = "routed";
|
|
3494
|
+
executionMode = "read-only";
|
|
3495
|
+
executionEnvironment = "harness";
|
|
3496
|
+
}
|
|
2805
3497
|
if (!["routed", "official-team"].includes(executor)) throw new Error("\u4E0D\u652F\u6301\u7684\u6267\u884C\u65B9\u5F0F\u3002");
|
|
2806
3498
|
if (!["read-only", "workspace-write"].includes(executionMode)) throw new Error("\u4E0D\u652F\u6301\u7684\u4EFB\u52A1\u6743\u9650\u3002");
|
|
2807
3499
|
if (executor === "official-team" && mode !== "team") throw new Error("\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u9700\u8981\u5148\u5728\u4E0A\u65B9\u9009\u62E9\u201C\u56E2\u961F\u5206\u5DE5\u201D\u3002");
|
|
@@ -2814,7 +3506,8 @@ function launchRequest({ task, mode, directRoute, budgetUsd, preset, workspace,
|
|
|
2814
3506
|
...executionEnvironment === "cli-native" ? { executionEnvironment } : {},
|
|
2815
3507
|
...mode === "direct" && directRoute ? { provider: directRoute.provider, model: directRoute.model } : { planMode: mode === "team" ? "team" : "single", preset },
|
|
2816
3508
|
...Number.isFinite(budget) && budget >= 0 ? { budgetUsd: budget } : {},
|
|
2817
|
-
...typeof workspace === "string" && workspace.trim() ? { workspace: workspace.trim() } : {}
|
|
3509
|
+
...typeof workspace === "string" && workspace.trim() ? { workspace: workspace.trim() } : {},
|
|
3510
|
+
...manual ?? {}
|
|
2818
3511
|
};
|
|
2819
3512
|
}
|
|
2820
3513
|
function rerunConfirmations({ run, item, override = null, choice = null, ledger = null, health = null, toolFor = () => null, headlessIds = /* @__PURE__ */ new Set() } = {}) {
|
|
@@ -2844,6 +3537,10 @@ function rerunConfirmations({ run, item, override = null, choice = null, ledger
|
|
|
2844
3537
|
|
|
2845
3538
|
// .dsh-plugin/client/adaptive-state.mjs
|
|
2846
3539
|
var ADAPTIVE_DEFAULTS = Object.freeze({
|
|
3540
|
+
routingEvidenceJson: "",
|
|
3541
|
+
resourceLearningEnabled: true,
|
|
3542
|
+
qualityEscalationEnabled: false,
|
|
3543
|
+
qualityGateJson: "",
|
|
2847
3544
|
feedbackLearningEnabled: true,
|
|
2848
3545
|
feedbackHalfLifeDays: 30,
|
|
2849
3546
|
feedbackPriorWeight: 3,
|
|
@@ -3265,7 +3962,7 @@ function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
|
|
|
3265
3962
|
const rerun = rerunSupport(run);
|
|
3266
3963
|
const canRerun = rerun.supported && !item.ok && !busy;
|
|
3267
3964
|
const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
|
|
3268
|
-
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.ok && item.diagnostic && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "CLI \u8BCA\u65AD", Number.isInteger(item.exitCode) ? `\uFF08\u9000\u51FA\u7801 ${item.exitCode}\uFF09` : ""), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.diagnostic)), 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: () => {
|
|
3965
|
+
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" : ""), item.manualAssignment && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u624B\u52A8\u5206\u914D \xB7 ", item.manualAssignment.kind === "tool" ? `\u5B98\u65B9\u5DE5\u5177 ${item.manualAssignment.toolId}\uFF08\u5382\u5546\u9ED8\u8BA4\u6A21\u578B\uFF09` : `\u6A21\u578B API ${item.manualAssignment.provider}/${item.manualAssignment.model}`, item.algorithmRecommendation?.provider ? ` \xB7 \u539F\u63A8\u8350 ${item.algorithmRecommendation.provider}/${item.algorithmRecommendation.model}` : ""), /* @__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.ok && item.diagnostic && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "CLI \u8BCA\u65AD", Number.isInteger(item.exitCode) ? `\uFF08\u9000\u51FA\u7801 ${item.exitCode}\uFF09` : ""), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.diagnostic)), 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: () => {
|
|
3269
3966
|
const [provider, model] = target.split("\0");
|
|
3270
3967
|
onRerun(run.id, item.id, { provider, model });
|
|
3271
3968
|
} }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
|
|
@@ -3320,18 +4017,23 @@ var STATUS_TEXT = Object.freeze({
|
|
|
3320
4017
|
"paused-budget": "\u5DF2\u56E0\u9884\u7B97\u6682\u505C\uFF0C\u672A\u542F\u52A8\u6A21\u578B",
|
|
3321
4018
|
"paused-subscription-failure": "\u6709\u6B65\u9AA4\u56E0\u8BA2\u9605\u8C03\u7528\u5931\u8D25\u800C\u6682\u505C\uFF0C\u8BF7\u5728\u4E0B\u65B9\u6267\u884C\u8BB0\u5F55\u4E2D\u9009\u62E9\u5982\u4F55\u7EE7\u7EED"
|
|
3322
4019
|
});
|
|
3323
|
-
function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger, previewRun, startRun, onStarted, disabledReason, planningRevision }) {
|
|
4020
|
+
function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger, previewRun, startRun, onStarted, disabledReason, planningRevision, assignmentMode = "algorithm", packageAssignments = {}, packagePlanKey: packagePlanKey2 }) {
|
|
3324
4021
|
const [preset, setPreset] = import_react3.default.useState(defaultPreset || "balanced");
|
|
3325
4022
|
const [executor, setExecutor] = import_react3.default.useState("routed");
|
|
3326
4023
|
const [executionMode, setExecutionMode] = import_react3.default.useState("read-only");
|
|
3327
4024
|
const [executionEnvironment, setExecutionEnvironment] = import_react3.default.useState("harness");
|
|
4025
|
+
const manual = assignmentMode === "manual" && mode !== "direct";
|
|
4026
|
+
const runExecutor = manual ? "routed" : executor;
|
|
4027
|
+
const runMode = manual ? "read-only" : executionMode;
|
|
4028
|
+
const runEnvironment = manual ? "harness" : executionEnvironment;
|
|
4029
|
+
const runPreset = manual ? defaultPreset || "balanced" : preset;
|
|
3328
4030
|
const lastWorkspace = [...ledger?.runs ?? []].map((run) => run.workspace).find(Boolean) ?? "";
|
|
3329
4031
|
const [workspace, setWorkspace] = import_react3.default.useState("");
|
|
3330
4032
|
const [phase, setPhase] = import_react3.default.useState({ kind: "idle" });
|
|
3331
4033
|
const mounted = import_react3.default.useRef(true);
|
|
3332
4034
|
const confirmRef = import_react3.default.useRef(null);
|
|
3333
4035
|
const pendingRequest = import_react3.default.useRef(0);
|
|
3334
|
-
const inputSignature = JSON.stringify([task, mode, directRoute?.provider, directRoute?.model, budgetUsd,
|
|
4036
|
+
const inputSignature = JSON.stringify([task, mode, directRoute?.provider, directRoute?.model, budgetUsd, runPreset, workspace, lastWorkspace, planningRevision, disabledReason, runExecutor, runMode, runEnvironment, assignmentMode, packagePlanKey2, packageAssignments]);
|
|
3335
4037
|
const latestSignature = import_react3.default.useRef(inputSignature);
|
|
3336
4038
|
latestSignature.current = inputSignature;
|
|
3337
4039
|
import_react3.default.useEffect(() => {
|
|
@@ -3345,12 +4047,12 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
3345
4047
|
setPreset(defaultPreset || "balanced");
|
|
3346
4048
|
}, [defaultPreset]);
|
|
3347
4049
|
import_react3.default.useEffect(() => {
|
|
3348
|
-
if (mode !== "team") {
|
|
4050
|
+
if (mode !== "team" || manual) {
|
|
3349
4051
|
setExecutor("routed");
|
|
3350
4052
|
setExecutionMode("read-only");
|
|
3351
4053
|
setExecutionEnvironment("harness");
|
|
3352
4054
|
}
|
|
3353
|
-
}, [mode]);
|
|
4055
|
+
}, [mode, manual]);
|
|
3354
4056
|
import_react3.default.useEffect(() => {
|
|
3355
4057
|
pendingRequest.current += 1;
|
|
3356
4058
|
setPhase((previous) => ["previewing", "preview", "error"].includes(previous.kind) ? { kind: "idle" } : previous);
|
|
@@ -3358,16 +4060,35 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
3358
4060
|
import_react3.default.useEffect(() => {
|
|
3359
4061
|
if (phase.kind === "preview") confirmRef.current?.focus();
|
|
3360
4062
|
}, [phase.kind]);
|
|
3361
|
-
const request = () => launchRequest({
|
|
4063
|
+
const request = () => launchRequest({
|
|
4064
|
+
task,
|
|
4065
|
+
mode,
|
|
4066
|
+
directRoute,
|
|
4067
|
+
budgetUsd,
|
|
4068
|
+
preset: runPreset,
|
|
4069
|
+
workspace: text2(workspace) || lastWorkspace,
|
|
4070
|
+
executor: runExecutor,
|
|
4071
|
+
executionMode: runMode,
|
|
4072
|
+
executionEnvironment: runEnvironment,
|
|
4073
|
+
assignmentMode: manual ? "manual" : "algorithm",
|
|
4074
|
+
packageAssignments,
|
|
4075
|
+
packagePlanKey: packagePlanKey2
|
|
4076
|
+
});
|
|
3362
4077
|
const unavailable = typeof previewRun !== "function" || typeof startRun !== "function";
|
|
3363
|
-
const blocked = disabledReason || (unavailable ? "\u5DE5\u4F5C\u53F0\u6267\u884C\u670D\u52A1\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6\u540E\u91CD\u8BD5\u3002" : !text2(task) ? "\u5148\u5728\u4E0A\u65B9\u201C\u4EFB\u52A1\u89C4\u5212\u201D\u4E2D\u63CF\u8FF0\u4EFB\u52A1\u3002" :
|
|
4078
|
+
const blocked = disabledReason || (unavailable ? "\u5DE5\u4F5C\u53F0\u6267\u884C\u670D\u52A1\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6\u540E\u91CD\u8BD5\u3002" : !text2(task) ? "\u5148\u5728\u4E0A\u65B9\u201C\u4EFB\u52A1\u89C4\u5212\u201D\u4E2D\u63CF\u8FF0\u4EFB\u52A1\u3002" : manual && !packagePlanKey2 ? "\u8BF7\u91CD\u65B0\u751F\u6210\u5DE5\u4F5C\u5305\u540E\u518D\u624B\u52A8\u5206\u914D\u3002" : runExecutor === "official-team" && mode !== "team" ? "\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u9700\u8981\u5148\u5728\u4E0A\u65B9\u9009\u62E9\u201C\u56E2\u961F\u5206\u5DE5\u201D\u3002" : "");
|
|
3364
4079
|
const busy = phase.kind === "previewing" || phase.kind === "running";
|
|
3365
4080
|
const recordedRun = phase.kind === "done" && phase.value.runId ? (ledger?.runs ?? []).find((run) => run.id === phase.value.runId) : null;
|
|
3366
4081
|
const resultStatus = recordedRun?.status ?? phase.value?.status;
|
|
3367
4082
|
const preview = async () => {
|
|
3368
4083
|
if (blocked || busy) return;
|
|
3369
4084
|
const current = ++pendingRequest.current;
|
|
3370
|
-
|
|
4085
|
+
let snapshot;
|
|
4086
|
+
try {
|
|
4087
|
+
snapshot = request();
|
|
4088
|
+
} catch (error) {
|
|
4089
|
+
setPhase({ kind: "error", message: text2(error?.message) || "\u5206\u914D\u8BBE\u7F6E\u65E0\u6548\u3002" });
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
3371
4092
|
const signature2 = inputSignature;
|
|
3372
4093
|
setPhase({ kind: "previewing" });
|
|
3373
4094
|
try {
|
|
@@ -3396,16 +4117,16 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
3396
4117
|
if (mounted.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u5931\u8D25\u3002" });
|
|
3397
4118
|
}
|
|
3398
4119
|
};
|
|
3399
|
-
return /* @__PURE__ */ import_react3.default.createElement("section", { className: "mr-card", "aria-label": "\u5728\u5DE5\u4F5C\u53F0\u6267\u884C" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react3.default.createElement("div", null, /* @__PURE__ */ import_react3.default.createElement("h2", { className: "mr-card-title" }, "\u5728\u5DE5\u4F5C\u53F0\u6267\u884C"), /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-card-copy" }, "\u4F7F\u7528\u4E0A\u65B9\u7684\u4EFB\u52A1\u63CF\u8FF0\u4E0E\u89C4\u5212\u6A21\u5F0F\uFF0C\u5148\u9884\u89C8\u6267\u884C\u8BA1\u5212\u3001\u6743\u9650\u4E0E\u9884\u4F30\u8D39\u7528\uFF0C\u786E\u8BA4\u540E\u624D\u4F1A\u542F\u52A8\u6267\u884C\u3002\u6A21\u578B\u8DEF\u7531\u6267\u884C\u53EA\u8BFB\u4EFB\u52A1\uFF1B\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u53EF\u9009\u62E9\u53EA\u8BFB\u68C0\u67E5\uFF0C\u6216\u5728\u9694\u79BB\u5DE5\u4F5C\u6811\u4E2D\u4F7F\u7528 CLI \u7684\u6B63\u5E38\u5DE5\u5177\u7F16\u8F91\u6587\u4EF6\u3002"))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-control-label", id: "mr-launch-executor" }, "\u6267\u884C\u65B9\u5F0F"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-executor" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed":
|
|
4120
|
+
return /* @__PURE__ */ import_react3.default.createElement("section", { className: "mr-card", "aria-label": "\u5728\u5DE5\u4F5C\u53F0\u6267\u884C" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react3.default.createElement("div", null, /* @__PURE__ */ import_react3.default.createElement("h2", { className: "mr-card-title" }, "\u5728\u5DE5\u4F5C\u53F0\u6267\u884C"), /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-card-copy" }, "\u4F7F\u7528\u4E0A\u65B9\u7684\u4EFB\u52A1\u63CF\u8FF0\u4E0E\u89C4\u5212\u6A21\u5F0F\uFF0C\u5148\u9884\u89C8\u6267\u884C\u8BA1\u5212\u3001\u6743\u9650\u4E0E\u9884\u4F30\u8D39\u7528\uFF0C\u786E\u8BA4\u540E\u624D\u4F1A\u542F\u52A8\u6267\u884C\u3002\u6A21\u578B\u8DEF\u7531\u6267\u884C\u53EA\u8BFB\u4EFB\u52A1\uFF1B\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u53EF\u9009\u62E9\u53EA\u8BFB\u68C0\u67E5\uFF0C\u6216\u5728\u9694\u79BB\u5DE5\u4F5C\u6811\u4E2D\u4F7F\u7528 CLI \u7684\u6B63\u5E38\u5DE5\u5177\u7F16\u8F91\u6587\u4EF6\u3002"))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-control-label", id: "mr-launch-executor" }, "\u6267\u884C\u65B9\u5F0F"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-executor" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": runExecutor === "routed", disabled: busy, onClick: () => {
|
|
3400
4121
|
setExecutor("routed");
|
|
3401
4122
|
setExecutionMode("read-only");
|
|
3402
4123
|
setExecutionEnvironment("harness");
|
|
3403
|
-
} }, "\u6A21\u578B\u8DEF\u7531\uFF08\u53EA\u8BFB\uFF09"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed":
|
|
3404
|
-
if (mode === "team") setExecutor("official-team");
|
|
3405
|
-
} }, "\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C"))),
|
|
4124
|
+
} }, manual ? "\u624B\u52A8\u5206\u914D\uFF08\u53EA\u8BFB\uFF09" : "\u6A21\u578B\u8DEF\u7531\uFF08\u53EA\u8BFB\uFF09"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": runExecutor === "official-team", disabled: busy || mode !== "team" || manual, title: manual ? "\u624B\u52A8\u5206\u914D\u6309\u5305\u6267\u884C\u53EA\u8BFB\u4EFB\u52A1" : mode !== "team" ? "\u5148\u5728\u4E0A\u65B9\u9009\u62E9\u201C\u56E2\u961F\u5206\u5DE5\u201D" : "\u7531\u5B98\u65B9 CLI \u534F\u4F5C\u6267\u884C\u5DE5\u4F5C\u5305", onClick: () => {
|
|
4125
|
+
if (mode === "team" && !manual) setExecutor("official-team");
|
|
4126
|
+
} }, "\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C"))), runExecutor === "official-team" && /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-control-label", id: "mr-launch-permission" }, "\u4EFB\u52A1\u6743\u9650"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-permission" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": executionMode === "read-only", disabled: busy, onClick: () => {
|
|
3406
4127
|
setExecutionMode("read-only");
|
|
3407
4128
|
setExecutionEnvironment("harness");
|
|
3408
|
-
} }, "\u53EA\u8BFB\u68C0\u67E5"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": executionMode === "workspace-write", disabled: busy, onClick: () => setExecutionMode("workspace-write") }, "\u7F16\u8F91\u6587\u4EF6"))),
|
|
4129
|
+
} }, "\u53EA\u8BFB\u68C0\u67E5"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": executionMode === "workspace-write", disabled: busy, onClick: () => setExecutionMode("workspace-write") }, "\u7F16\u8F91\u6587\u4EF6"))), runExecutor === "official-team" && executionMode === "workspace-write" && /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-control-label", id: "mr-launch-environment" }, "\u6267\u884C\u73AF\u5883"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-environment" }, /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": executionEnvironment === "harness", disabled: busy, onClick: () => setExecutionEnvironment("harness") }, "Harness \u53D7\u9650\u73AF\u5883"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed": executionEnvironment === "cli-native", disabled: busy, onClick: () => setExecutionEnvironment("cli-native") }, "\u5382\u5546 CLI \u6B63\u5E38\u73AF\u5883"))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-control-label", id: "mr-launch-preset" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-preset" }, Object.values(ROUTING_PRESETS).map((item) => /* @__PURE__ */ import_react3.default.createElement("button", { key: item.id, type: "button", title: manual ? "\u624B\u52A8\u5206\u914D\u6CBF\u7528\u5F53\u524D\u5EFA\u8BAE\u7684\u65B9\u6848\uFF1B\u66F4\u6539\u65B9\u6848\u540E\u8BF7\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\u3002" : item.description, "aria-pressed": runPreset === item.id, disabled: busy || mode === "direct" || manual, onClick: () => setPreset(item.id) }, item.label)))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group mr-launch-workspace" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-launch-workspace" }, "\u5DE5\u4F5C\u533A\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"), /* @__PURE__ */ import_react3.default.createElement("input", { className: "mr-input", id: "mr-launch-workspace", value: workspace, disabled: busy, placeholder: lastWorkspace ? `\u7559\u7A7A\u6CBF\u7528\u4E0A\u6B21\u8FD0\u884C\uFF1A${lastWorkspace}` : "\u4F8B\u5982 D:\\projects\\demo \u6216 /home/me/demo", onChange: (event) => setWorkspace(event.target.value) }))), /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, manual ? "\u624B\u52A8\u5206\u914D\u6309\u5305\u6267\u884C\u53EA\u8BFB\u4EFB\u52A1\uFF0C\u53EF\u6DF7\u5408\u6A21\u578B API \u4E0E\u5B98\u65B9\u5DE5\u5177\uFF1B\u5DE5\u5177\u4F7F\u7528\u9ED8\u8BA4\u6A21\u578B\u3002\u6240\u9009\u76EE\u6807\u3001\u5C31\u7EEA\u72B6\u6001\u548C\u8D39\u7528\u4EE5\u6267\u884C\u9884\u89C8\u4E3A\u51C6\u3002" : executor === "official-team" ? `${executionMode === "workspace-write" ? "\u7F16\u8F91\u6587\u4EF6\uFF1A\u5404\u5DE5\u4F5C\u5305\u5728\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u4F7F\u7528 CLI \u6B63\u5E38\u5DE5\u5177\uFF0C\u5B8C\u6210\u540E\u6574\u5408\u56DE\u6240\u9009\u5DE5\u4F5C\u533A\u3002" : "\u53EA\u8BFB\u68C0\u67E5\uFF1A\u5404\u5DE5\u4F5C\u5305\u4F7F\u7528\u53D7\u9650\u5DE5\u5177\u96C6\uFF0C\u4E0D\u4FEE\u6539\u5DE5\u4F5C\u533A\u6587\u4EF6\uFF1BClaude \u7981\u7528 shell\u3001\u6280\u80FD\u53CA\u65E2\u6709 MCP\uFF0C\u5E76\u5FFD\u7565\u7528\u6237\u8BBE\u7F6E\u3002"}\u5931\u8D25\u65F6\u4E0D\u4F1A\u81EA\u52A8\u66FF\u6362\u4E3A\u6A21\u578B\u76EE\u5F55 API\u3002\u5DF2\u767B\u5F55\u4E0D\u4EE3\u8868\u5F53\u524D\u4EFB\u52A1\u6743\u9650\u5DF2\u5C31\u7EEA\uFF0C\u9884\u89C8\u4F1A\u68C0\u67E5\u53EF\u7528\u5DE5\u5177\u3002` : mode === "direct" ? `\u6307\u5B9A\u6A21\u578B\uFF1A${directRoute ? `${directRoute.provider}/${directRoute.model}` : "\u672A\u9009\u62E9"}\uFF08\u8DF3\u8FC7\u8DEF\u7531\uFF0C\u65B9\u6848\u4E0D\u751F\u6548\uFF09` : mode === "team" ? "\u56E2\u961F\u5206\u5DE5\uFF1A\u6309\u4F9D\u8D56\u6267\u884C\u53EA\u8BFB\u5DE5\u4F5C\u5305\uFF0C\u6BCF\u6B65\u4F7F\u7528\u53EF\u7528\u7684\u5B98\u65B9 CLI \u6216\u6A21\u578B\u76EE\u5F55 API\u3002" : "\u5355\u4EFB\u52A1\uFF1A\u6309\u65B9\u6848\u9009\u62E9\u4E00\u6761\u8DEF\u7EBF\u3002"), mode !== "team" && !manual && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u4F7F\u7528\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u524D\uFF0C\u5148\u5728\u4E0A\u65B9\u9009\u62E9\u201C\u56E2\u961F\u5206\u5DE5\u201D\u3002"), runEnvironment === "cli-native" && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u5382\u5546 CLI \u4F7F\u7528\u539F\u767B\u5F55\u3001\u914D\u7F6E\u3001\u6280\u80FD\u53CA MCP\uFF0C\u4EE5\u5F53\u524D\u7528\u6237\u6743\u9650\u8FD0\u884C\uFF0C\u4E0D\u7ECF\u8FC7 Harness \u8FDB\u7A0B\u6C99\u7BB1\u3002\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u7528\u4E8E\u6536\u96C6\u6539\u52A8\uFF0C\u4E0D\u662F\u64CD\u4F5C\u7CFB\u7EDF\u8BFB\u5199\u8FB9\u754C\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u5207\u6362\u5230\u6B64\u73AF\u5883\u3002"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react3.default.createElement("button", { className: "mr-button", type: "button", disabled: Boolean(blocked) || busy, onClick: () => {
|
|
3409
4130
|
void preview();
|
|
3410
4131
|
} }, phase.kind === "previewing" ? "\u6B63\u5728\u751F\u6210\u9884\u89C8\u2026" : "\u9884\u89C8\u6267\u884C\u8BA1\u5212"), blocked && /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-caption" }, blocked)), phase.kind === "previewing" && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u6309\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u3001\u767B\u5F55\u72B6\u6001\u548C\u9884\u7B97\u751F\u6210\u6267\u884C\u8BA1\u5212\u2026"), phase.kind === "error" && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-error", role: "alert" }, phase.message), (phase.kind === "preview" && phase.signature === inputSignature || phase.kind === "running") && /* @__PURE__ */ import_react3.default.createElement(
|
|
3411
4132
|
LaunchPreview,
|
|
@@ -3430,8 +4151,12 @@ function LaunchPreview({ value, request, changed, running, confirmRef, onConfirm
|
|
|
3430
4151
|
const native = (value.executionEnvironment ?? request?.executionEnvironment) === "cli-native";
|
|
3431
4152
|
const readOnly = value.readOnly !== false && (value.executionMode ?? request?.executionMode) !== "workspace-write";
|
|
3432
4153
|
const blocked = value.status === "blocked";
|
|
4154
|
+
const manual = request?.assignmentMode === "manual" || value.assignmentMode === "manual";
|
|
3433
4155
|
const blocking = [...new Set([value.reason, ...Array.isArray(value.blocking) ? value.blocking : [value.blocking]].map(reasonText).filter(Boolean))];
|
|
3434
|
-
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-launch-preview", role: "region", "aria-label": "\u6267\u884C\u9884\u89C8" }, changed && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-error", role: "alert" }, "\u786E\u8BA4\u671F\u95F4\u60C5\u51B5\u6709\u53D8\u5316\uFF08\u4F8B\u5982\u9884\u7B97\u6216\u767B\u5F55\u72B6\u6001\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u4E0B\u9762\u7684\u786E\u8BA4\u9879\u3002"), blocked && /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-error", role: "alert" }, /* @__PURE__ */ import_react3.default.createElement("strong", null, "\u5F53\u524D\u65E0\u6CD5\u542F\u52A8\u6267\u884C\u3002"), blocking.length ? /* @__PURE__ */ import_react3.default.createElement("ul", null, blocking.map((message) => /* @__PURE__ */ import_react3.default.createElement("li", { key: message }, message))) : /* @__PURE__ */ import_react3.default.createElement("p", null, "\u6267\u884C\u6761\u4EF6\u5C1A\u672A\u6EE1\u8DB3\uFF0C\u8BF7\u68C0\u67E5\u6240\u9009\u6743\u9650\u3001\u5DE5\u4F5C\u533A\u548C\u5B98\u65B9\u5DE5\u5177\u72B6\u6001\u540E\u91CD\u65B0\u9884\u89C8\u3002")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, officialTeam ? "\u6267\u884C\u65B9\u5F0F" : "\u8DEF\u7EBF"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, officialTeam ? "\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C" : value.selected ? `${value.selected.provider}/${value.selected.model}` : "\u6682\u65E0\u8DEF\u7EBF", value.routingBypassed ? "\uFF08\u6307\u5B9A\u6A21\u578B\uFF09" : "")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30\u8D39\u7528"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, value.estimatedCost === null || value.estimatedCost === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : money(value.estimatedCost))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u65B9\u6848"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[value.decision?.preset]?.label ?? "\u2014", value.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u5DE5\u4F5C\u533A"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value mr-break" }, /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace)))), officialTeam && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u4EFB\u52A1\u6743\u9650\uFF1A", readOnly ? "\u53EA\u8BFB\u68C0\u67E5\uFF0C\u4E0D\u4FEE\u6539\u5DE5\u4F5C\u533A\u6587\u4EF6\u3002\u4F7F\u7528\u53D7\u9650\u5DE5\u5177\u96C6\uFF1BClaude \u7981\u7528 shell\u3001\u6280\u80FD\u53CA\u65E2\u6709 MCP\uFF0C\u5E76\u5FFD\u7565\u7528\u6237\u8BBE\u7F6E\u3002" : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, "\u7F16\u8F91\u6587\u4EF6\u3002\u7F16\u8F91\u8303\u56F4\uFF1A\u6240\u9009\u5DE5\u4F5C\u533A ", /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace), " \u5185\u7684\u4EFB\u52A1\u6587\u4EF6\u3002\u5B98\u65B9 CLI \u4F7F\u7528\u81EA\u5DF1\u7684\u6B63\u5E38\u5DE5\u5177\uFF0C\u5728\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u5B8C\u6210\u540E\u6574\u5408\u56DE\u8BE5\u5DE5\u4F5C\u533A\u3002"), "\u5931\u8D25\u65F6\u4E0D\u4F1A\u81EA\u52A8\u66FF\u6362\u4E3A\u6A21\u578B\u76EE\u5F55 API\u3002"), native && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u73AF\u5883\uFF1A\u5382\u5546 CLI \u6B63\u5E38\u73AF\u5883\uFF0C\u4EE5\u5F53\u524D\u7528\u6237\u6743\u9650\u8FD0\u884C\uFF0C\u4E0D\u7ECF Harness \u8FDB\u7A0B\u6C99\u7BB1\u3002\u5DE5\u4F5C\u6811\u4E0D\u9650\u5236\u5DE5\u5177\u8BBF\u95EE\u5DE5\u4F5C\u6811\u5916\u8D44\u6E90\u3002"), !officialTeam && !readOnly && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u7F16\u8F91\u8303\u56F4\uFF1A\u6240\u9009\u5DE5\u4F5C\u533A ", /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace), " \u5185\u7684\u4EFB\u52A1\u6587\u4EF6\uFF1B\u5728\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u5B8C\u6210\u540E\u6574\u5408\u56DE\u8BE5\u5DE5\u4F5C\u533A\u3002\u4E0D\u4F1A\u81EA\u52A8\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002"), value.budget?.message && /* @__PURE__ */ import_react3.default.createElement("p", { className: value.budget.exceeded ? "mr-error" : "mr-caption" }, "\u9884\u7B97\u68C0\u67E5\uFF1A", value.budget.message), packages.length > 0 && /* @__PURE__ */ import_react3.default.createElement("ol", { className: "mr-launch-packages" }, packages.map((item) =>
|
|
4156
|
+
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-launch-preview", role: "region", "aria-label": "\u6267\u884C\u9884\u89C8" }, changed && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-error", role: "alert" }, "\u786E\u8BA4\u671F\u95F4\u60C5\u51B5\u6709\u53D8\u5316\uFF08\u4F8B\u5982\u9884\u7B97\u6216\u767B\u5F55\u72B6\u6001\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u4E0B\u9762\u7684\u786E\u8BA4\u9879\u3002"), blocked && /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-error", role: "alert" }, /* @__PURE__ */ import_react3.default.createElement("strong", null, "\u5F53\u524D\u65E0\u6CD5\u542F\u52A8\u6267\u884C\u3002"), blocking.length ? /* @__PURE__ */ import_react3.default.createElement("ul", null, blocking.map((message) => /* @__PURE__ */ import_react3.default.createElement("li", { key: message }, message))) : /* @__PURE__ */ import_react3.default.createElement("p", null, "\u6267\u884C\u6761\u4EF6\u5C1A\u672A\u6EE1\u8DB3\uFF0C\u8BF7\u68C0\u67E5\u6240\u9009\u6743\u9650\u3001\u5DE5\u4F5C\u533A\u548C\u5B98\u65B9\u5DE5\u5177\u72B6\u6001\u540E\u91CD\u65B0\u9884\u89C8\u3002")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, officialTeam || manual ? "\u6267\u884C\u65B9\u5F0F" : "\u8DEF\u7EBF"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, manual ? "\u624B\u52A8\u5206\u914D \xB7 \u6309\u5305\u53EA\u8BFB\u6267\u884C" : officialTeam ? "\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C" : value.selected ? `${value.selected.provider}/${value.selected.model}` : "\u6682\u65E0\u8DEF\u7EBF", value.routingBypassed ? "\uFF08\u6307\u5B9A\u6A21\u578B\uFF09" : "")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30\u8D39\u7528"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, value.estimatedCost === null || value.estimatedCost === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : money(value.estimatedCost))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u65B9\u6848"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[value.decision?.preset]?.label ?? "\u2014", value.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u5DE5\u4F5C\u533A"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value mr-break" }, /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace)))), officialTeam && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u4EFB\u52A1\u6743\u9650\uFF1A", readOnly ? "\u53EA\u8BFB\u68C0\u67E5\uFF0C\u4E0D\u4FEE\u6539\u5DE5\u4F5C\u533A\u6587\u4EF6\u3002\u4F7F\u7528\u53D7\u9650\u5DE5\u5177\u96C6\uFF1BClaude \u7981\u7528 shell\u3001\u6280\u80FD\u53CA\u65E2\u6709 MCP\uFF0C\u5E76\u5FFD\u7565\u7528\u6237\u8BBE\u7F6E\u3002" : /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, "\u7F16\u8F91\u6587\u4EF6\u3002\u7F16\u8F91\u8303\u56F4\uFF1A\u6240\u9009\u5DE5\u4F5C\u533A ", /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace), " \u5185\u7684\u4EFB\u52A1\u6587\u4EF6\u3002\u5B98\u65B9 CLI \u4F7F\u7528\u81EA\u5DF1\u7684\u6B63\u5E38\u5DE5\u5177\uFF0C\u5728\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u5B8C\u6210\u540E\u6574\u5408\u56DE\u8BE5\u5DE5\u4F5C\u533A\u3002"), "\u5931\u8D25\u65F6\u4E0D\u4F1A\u81EA\u52A8\u66FF\u6362\u4E3A\u6A21\u578B\u76EE\u5F55 API\u3002"), native && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u73AF\u5883\uFF1A\u5382\u5546 CLI \u6B63\u5E38\u73AF\u5883\uFF0C\u4EE5\u5F53\u524D\u7528\u6237\u6743\u9650\u8FD0\u884C\uFF0C\u4E0D\u7ECF Harness \u8FDB\u7A0B\u6C99\u7BB1\u3002\u5DE5\u4F5C\u6811\u4E0D\u9650\u5236\u5DE5\u5177\u8BBF\u95EE\u5DE5\u4F5C\u6811\u5916\u8D44\u6E90\u3002"), !officialTeam && !readOnly && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u7F16\u8F91\u8303\u56F4\uFF1A\u6240\u9009\u5DE5\u4F5C\u533A ", /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace), " \u5185\u7684\u4EFB\u52A1\u6587\u4EF6\uFF1B\u5728\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u5B8C\u6210\u540E\u6574\u5408\u56DE\u8BE5\u5DE5\u4F5C\u533A\u3002\u4E0D\u4F1A\u81EA\u52A8\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002"), value.budget?.message && /* @__PURE__ */ import_react3.default.createElement("p", { className: value.budget.exceeded ? "mr-error" : "mr-caption" }, "\u9884\u7B97\u68C0\u67E5\uFF1A", value.budget.message), packages.length > 0 && /* @__PURE__ */ import_react3.default.createElement("ol", { className: "mr-launch-packages" }, packages.map((item) => {
|
|
4157
|
+
const tool = item.manualAssignment?.kind === "tool";
|
|
4158
|
+
return /* @__PURE__ */ import_react3.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react3.default.createElement("strong", null, item.name), (manual || item.selectionSource === "manual") && /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-pill" }, "\u624B\u52A8"), " \u2192 ", tool ? `${item.toolLabel || item.toolId || item.manualAssignment.toolId} \xB7 \u9ED8\u8BA4\u6A21\u578B` : item.route || item.toolLabel || item.toolId || item.tool || "\u5F85\u5206\u914D\u8DEF\u7EBF", " ", /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-caption" }, "\uFF08\u9884\u4F30 ", tool ? "\u8D39\u7528\u672A\u77E5" : item.estimatedCost === null || item.estimatedCost === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : money(item.estimatedCost), item.channel === "official-cli" ? " \xB7 \u5B98\u65B9 CLI" : item.channel ? " \xB7 \u6A21\u578B\u76EE\u5F55 API" : "", "\uFF09"), item.channelDetail && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, item.channelDetail));
|
|
4159
|
+
})), reasons.length > 0 ? /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-confirm-box" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-section-title" }, "\u6267\u884C\u524D\u9700\u8981\u786E\u8BA4\u4EE5\u4E0B ", reasons.length, " \u9879\uFF1A"), /* @__PURE__ */ import_react3.default.createElement("ol", null, reasons.map((item) => /* @__PURE__ */ import_react3.default.createElement("li", { key: item.code }, reasonText(item))))) : /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u5F53\u524D\u6CA1\u6709\u989D\u5916\u786E\u8BA4\u9879\u3002", value.estimatedCost === null || value.estimatedCost === void 0 ? "\u8D39\u7528\u672A\u77E5\uFF0C\u65E0\u6CD5\u786E\u8BA4\u672C\u6B21\u8D39\u7528\u662F\u5426\u5728\u9884\u7B97\u5185\u3002" : value.budget?.limited && value.budget?.estimateKnown && !value.budget?.exceeded ? "\u6309\u5DF2\u63D0\u4F9B\u5355\u4EF7\u4F30\u7B97\uFF0C\u672C\u6B21\u672A\u8D85\u51FA\u9884\u7B97\uFF1B\u5B9E\u9645\u8D39\u7528\u4EE5\u6267\u884C\u8BB0\u5F55\u548C\u8D26\u5355\u4E3A\u51C6\u3002" : "\u5B9E\u9645\u8D39\u7528\u4EE5\u6267\u884C\u8BB0\u5F55\u548C\u8D26\u5355\u4E3A\u51C6\u3002"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react3.default.createElement("button", { ref: confirmRef, className: "mr-button", type: "button", disabled: running || blocked, onClick: onConfirm }, running ? "\u6B63\u5728\u6267\u884C\u2026" : reasons.length ? "\u5168\u90E8\u786E\u8BA4\u5E76\u6267\u884C" : "\u786E\u8BA4\u6267\u884C"), /* @__PURE__ */ import_react3.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: running, onClick: onCancel }, "\u53D6\u6D88"), running && /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-caption", role: "status", "aria-live": "polite" }, "\u6A21\u578B\u8C03\u7528\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF0C\u8BF7\u52FF\u5173\u95ED\u5DE5\u4F5C\u53F0\u3002")));
|
|
3435
4160
|
}
|
|
3436
4161
|
|
|
3437
4162
|
// .dsh-plugin/client/cli-terminal.jsx
|
|
@@ -12864,7 +13589,7 @@ var xterm_default = `/**
|
|
|
12864
13589
|
`;
|
|
12865
13590
|
|
|
12866
13591
|
// .dsh-plugin/client/host-version.mjs
|
|
12867
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
13592
|
+
var ROUTER_CLIENT_VERSION = true ? "0.22.0" : "";
|
|
12868
13593
|
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";
|
|
12869
13594
|
function isMissingRemoteMethod(message) {
|
|
12870
13595
|
const value = String(message ?? "");
|
|
@@ -13475,6 +14200,11 @@ var router_main_default = `.mr-workspace {
|
|
|
13475
14200
|
.mr-package-name { font-size: 12px; font-weight: 750; }
|
|
13476
14201
|
.mr-package-route { color: var(--mr-accent); font-size: 11px; font-weight: 700; }
|
|
13477
14202
|
.mr-package-copy { margin: 7px 0 0; color: var(--mr-muted); font-size: 12px; line-height: 1.65; overflow-wrap: anywhere; }
|
|
14203
|
+
.mr-assignment-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 12px 0; }
|
|
14204
|
+
.mr-assignment-target { display: grid; gap: 7px; margin: 12px 0; min-width: 0; }
|
|
14205
|
+
.mr-assignment-target label { font-size: 12px; font-weight: 650; }
|
|
14206
|
+
.mr-assignment-target select { width: 100%; min-width: 0; max-width: 100%; text-overflow: ellipsis; }
|
|
14207
|
+
.mr-launch-packages .mr-pill { margin-left: 6px; }
|
|
13478
14208
|
.mr-notice { margin-top: 18px; padding: 14px 16px; border: 1px solid rgba(49, 92, 200, .16); border-radius: 12px; background: #eff4ff; color: #354d7a; font-size: 11px; line-height: 1.65; }
|
|
13479
14209
|
.mr-notice code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; }
|
|
13480
14210
|
@media (max-width: 850px) { .mr-grid { grid-template-columns: 1fr; } .mr-shell { padding: 24px 18px 48px; } }
|
|
@@ -13698,6 +14428,7 @@ var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
|
13698
14428
|
var routingSettingsSignature = (value) => JSON.stringify([
|
|
13699
14429
|
value.modelProfilesJson,
|
|
13700
14430
|
value.routingPreset,
|
|
14431
|
+
value.allowManualReassign,
|
|
13701
14432
|
...Object.keys(ADAPTIVE_DEFAULTS).map((key) => value[key] ?? ADAPTIVE_DEFAULTS[key])
|
|
13702
14433
|
]);
|
|
13703
14434
|
function RouterPanelIcon({ size = 20, active = false }) {
|
|
@@ -13716,12 +14447,25 @@ function ChannelBadge({ item }) {
|
|
|
13716
14447
|
const official = item.executionChannel === "official-cli";
|
|
13717
14448
|
return /* @__PURE__ */ import_react5.default.createElement("span", { className: official ? "mr-pill mr-pill-channel-ok" : "mr-pill", title: item.channelDetail ?? "" }, official ? `\u5B98\u65B9 CLI \xB7 ${item.channelLabel ?? item.channelTool}` : "\u6A21\u578B\u76EE\u5F55 API");
|
|
13718
14449
|
}
|
|
13719
|
-
function PlanResults({ plan, ledger, headingRef }) {
|
|
14450
|
+
function PlanResults({ plan, ledger, headingRef, assignmentMode = "algorithm", packageAssignments = {}, assignmentOptions = [], manualAllowed = true, onAssignmentModeChange, onPackageAssignmentChange, onRestoreAssignments }) {
|
|
13720
14451
|
const selected = plan.selected;
|
|
13721
14452
|
const budget = planBudget(ledger, plan.estimatedCost);
|
|
13722
14453
|
const packageNames = new Map((plan.team?.workPackages ?? []).map((item) => [item.id, item.name]));
|
|
13723
14454
|
const purposeLabel = { analysis: "\u4EFB\u52A1\u5206\u6790", execution: "\u4EFB\u52A1\u5B9E\u65BD", verification: "\u72EC\u7ACB\u9A8C\u8BC1", synthesis: "\u7ED3\u679C\u6574\u5408" };
|
|
13724
|
-
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\u6309\u8BA1\u8D39\u8BBE\u7F6E\u6682\u505C\u6216\u4F7F\u7528\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.
|
|
14455
|
+
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" }, assignmentMode === "manual" ? "\u7B97\u6CD5\u539F\u63A8\u8350\u8DEF\u7EBF" : "\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" }, assignmentMode === "manual" ? "\u8C03\u6574\u524D\u7B97\u6CD5\u65B9\u6848\u4F30\u7B97" : "\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" }, assignmentMode === "manual" ? "\u7B97\u6CD5\u539F\u65B9\u6848\u9884\u7B97\u63D0\u793A\uFF1A" : "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A", budget.message, " ", assignmentMode === "manual" ? "\u624B\u52A8\u65B9\u6848\u5C06\u91CD\u65B0\u9884\u89C8\u8D39\u7528\uFF0C\u8D85\u9884\u7B97\u65F6\u6682\u505C\u786E\u8BA4\uFF0C\u4E0D\u81EA\u52A8\u66FF\u6362\u76EE\u6807\u3002" : "\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" }, assignmentMode === "manual" ? "\u7B97\u6CD5\u539F\u65B9\u6848\uFF1A" : "\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\u6309\u8BA1\u8D39\u8BBE\u7F6E\u6682\u505C\u6216\u4F7F\u7528\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" }, assignmentMode === "manual" ? "\u7B97\u6CD5\u539F\u63A8\u8350\u6E20\u9053" : "\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.routingBypassed && plan.team && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("h3", { className: "mr-section-title" }, plan.mode === "team" ? "\u56E2\u961F\u5DE5\u4F5C\u5305" : "\u4EFB\u52A1\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-assignment-controls" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u5DE5\u4F5C\u5305\u5206\u914D\u65B9\u5F0F" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-pressed": assignmentMode === "algorithm", onClick: () => onAssignmentModeChange?.("algorithm") }, "\u6309\u7B97\u6CD5\u63A8\u8350\u5206\u914D"), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-pressed": assignmentMode === "manual", disabled: !manualAllowed || !plan.team.workPackages.length, title: !manualAllowed ? "\u8BBE\u7F6E\u4E2D\u5DF2\u5173\u95ED\u624B\u52A8\u6539\u6D3E" : "\u4E3A\u6BCF\u4E2A\u5DE5\u4F5C\u5305\u9009\u62E9\u6A21\u578B API \u6216\u5B98\u65B9\u5DE5\u5177", onClick: () => onAssignmentModeChange?.("manual") }, "\u624B\u52A8\u8C03\u6574\u5206\u914D")), assignmentMode === "manual" && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: onRestoreAssignments }, "\u6062\u590D\u63A8\u8350\u5206\u914D")), !manualAllowed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u8BBE\u7F6E\u4E2D\u5DF2\u5173\u95ED\u624B\u52A8\u6539\u6D3E\u3002"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, assignmentMode === "manual" ? "\u624B\u52A8\u5206\u914D\u53EF\u6DF7\u5408\u6A21\u578B API \u4E0E\u5B98\u65B9\u5DE5\u5177\uFF0C\u6309\u4F9D\u8D56\u6267\u884C\u53EA\u8BFB\u4EFB\u52A1\uFF1B\u5DE5\u5177\u4F7F\u7528\u9ED8\u8BA4\u6A21\u578B\u3002\u4E0A\u65B9\u8D39\u7528\u4ECD\u662F\u7B97\u6CD5\u5EFA\u8BAE\u4F30\u7B97\uFF0C\u624B\u52A8\u76EE\u6807\u4E0E\u8D39\u7528\u4EE5\u6267\u884C\u9884\u89C8\u4E3A\u51C6\uFF0C\u9884\u89C8\u4F1A\u6838\u9A8C\u5957\u9910\u8BA1\u8D39\u4E0E\u5DE5\u5177\u5C31\u7EEA\u72B6\u6001\u3002" : "\u4E0B\u65B9\u6A21\u578B\u662F\u5DE5\u4F5C\u5305\u7684\u89C4\u5212\u5EFA\u8BAE\u3002\u6A21\u578B\u8DEF\u7531\u6309\u53EA\u8BFB\u65B9\u5F0F\u6267\u884C\uFF0C\u6BCF\u6B65\u53EF\u4F7F\u7528\u5B98\u65B9 CLI \u6216\u6A21\u578B\u76EE\u5F55 API\uFF1B\u5982\u9700\u7F16\u8F91\u6587\u4EF6\uFF0C\u53EF\u5728\u4E0B\u65B9\u6267\u884C\u533A\u9009\u62E9\u201C\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u201D\u548C\u201C\u7F16\u8F91\u6587\u4EF6\u201D\u6743\u9650\u3002CLI \u8BF7\u6C42\u6A21\u578B\u540D\u9700\u7B26\u5408\u5382\u5546\u89C4\u5219\uFF0C\u5B9E\u9645\u6A21\u578B\u4EE5\u8FD0\u884C\u8BB0\u5F55\u4E3A\u51C6\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" }, "\u7B97\u6CD5\u63A8\u8350\uFF1A", 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, open: assignmentMode === "manual" ? true : void 0 }, /* @__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" }, "\u7B97\u6CD5\u63A8\u8350\uFF1A", item.recommendedProvider, "/", item.recommendedModel)), assignmentMode === "manual" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-assignment-target" }, /* @__PURE__ */ import_react5.default.createElement("label", { htmlFor: `mr-assignment-${item.id}` }, item.name, " \u6267\u884C\u76EE\u6807"), /* @__PURE__ */ import_react5.default.createElement(
|
|
14456
|
+
"select",
|
|
14457
|
+
{
|
|
14458
|
+
className: "mr-input",
|
|
14459
|
+
id: `mr-assignment-${item.id}`,
|
|
14460
|
+
value: JSON.stringify(packageAssignments[item.id] ?? {}),
|
|
14461
|
+
onChange: (event) => {
|
|
14462
|
+
const option = assignmentOptions.find((candidate) => candidate.value === event.target.value && !candidate.disabled);
|
|
14463
|
+
if (option) onPackageAssignmentChange?.(item.id, { ...option.binding });
|
|
14464
|
+
}
|
|
14465
|
+
},
|
|
14466
|
+
/* @__PURE__ */ import_react5.default.createElement("optgroup", { label: "\u6A21\u578B\u76EE\u5F55 API" }, assignmentOptions.filter((option) => option.binding.kind === "api").map((option) => /* @__PURE__ */ import_react5.default.createElement("option", { key: option.value, value: option.value, disabled: option.disabled }, option.label))),
|
|
14467
|
+
/* @__PURE__ */ import_react5.default.createElement("optgroup", { label: "\u5B98\u65B9\u5DE5\u5177\uFF08\u9ED8\u8BA4\u6A21\u578B\uFF09" }, assignmentOptions.filter((option) => option.binding.kind === "tool").map((option) => /* @__PURE__ */ import_react5.default.createElement("option", { key: option.value, value: option.value, disabled: option.disabled }, option.label)))
|
|
14468
|
+
)), 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 ", assignmentMode === "manual" ? "\u539F\u63A8\u8350\u8D39\u7528" : "\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" }, assignmentMode === "manual" && /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, "\u539F\u63A8\u8350\u6E20\u9053\uFF1A"), /* @__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" && assignmentMode !== "manual" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.team.handoff)));
|
|
13725
14469
|
}
|
|
13726
14470
|
var remoteError = (response, fallback) => remoteErrorText(
|
|
13727
14471
|
text5(response?.error?.message) || text5(response?.value?.error) || (typeof response?.error === "string" ? response.error : ""),
|
|
@@ -14379,6 +15123,8 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14379
15123
|
const [budget, setBudget] = import_react5.default.useState(() => String(settingsScope.getSnapshot().value?.budgetUsd ?? 0));
|
|
14380
15124
|
const [query, setQuery] = import_react5.default.useState("");
|
|
14381
15125
|
const [plan, setPlan] = import_react5.default.useState(null);
|
|
15126
|
+
const [assignmentMode, setAssignmentMode] = import_react5.default.useState("algorithm");
|
|
15127
|
+
const [packageAssignments, setPackageAssignments] = import_react5.default.useState({});
|
|
14382
15128
|
const [planError, setPlanError] = import_react5.default.useState("");
|
|
14383
15129
|
const [toolProbes, setToolProbes] = import_react5.default.useState(null);
|
|
14384
15130
|
const [routingSettings, setRoutingSettings] = import_react5.default.useState(() => {
|
|
@@ -14434,12 +15180,18 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14434
15180
|
}, [routingSettings]);
|
|
14435
15181
|
const dataRevision = workbench.ledger.value?.dynamicData?.revision ?? "";
|
|
14436
15182
|
const feedbackRevision = workbench.ledger.value?.learning?.revision ?? "";
|
|
15183
|
+
const evidenceRevision = workbench.ledger.value?.routingEvidence?.revision ?? "";
|
|
15184
|
+
const manualAllowed = workbench.ledger.value?.settings?.allowManualReassign !== false && settingsScope.getSnapshot().value?.allowManualReassign !== false;
|
|
14437
15185
|
import_react5.default.useEffect(() => {
|
|
14438
|
-
|
|
15186
|
+
setAssignmentMode("algorithm");
|
|
15187
|
+
setPackageAssignments({});
|
|
15188
|
+
}, [plan, task, mode, routingSettings, catalogState.catalog, toolProbes, workbench.health.report?.tools, manualAllowed]);
|
|
15189
|
+
import_react5.default.useEffect(() => {
|
|
15190
|
+
if (plan && plan.workbenchRevision !== `${dataRevision}/${feedbackRevision}/${evidenceRevision}`) {
|
|
14439
15191
|
setPlan(null);
|
|
14440
15192
|
setPlanError("");
|
|
14441
15193
|
}
|
|
14442
|
-
}, [dataRevision, feedbackRevision, plan]);
|
|
15194
|
+
}, [dataRevision, feedbackRevision, evidenceRevision, plan]);
|
|
14443
15195
|
import_react5.default.useEffect(() => {
|
|
14444
15196
|
mounted.current = true;
|
|
14445
15197
|
const request = ++catalogRequest.current;
|
|
@@ -14456,6 +15208,23 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14456
15208
|
};
|
|
14457
15209
|
}, []);
|
|
14458
15210
|
const routes = routesFromModelCatalog(catalogState.catalog);
|
|
15211
|
+
const assignmentOptions = manualAssignmentOptions(routes, toolProbes, workbench.health.report);
|
|
15212
|
+
const currentPackagePlanKey = packagePlanKey(plan, task);
|
|
15213
|
+
const effectiveAssignmentMode = assignmentMode === "manual" && currentPackagePlanKey && manualAllowed && mode !== "direct" ? "manual" : "algorithm";
|
|
15214
|
+
const changeAssignmentMode = (next) => {
|
|
15215
|
+
if (next === "manual") {
|
|
15216
|
+
if (!manualAllowed || !currentPackagePlanKey) return;
|
|
15217
|
+
setPackageAssignments(initialPackageAssignments(plan));
|
|
15218
|
+
setAssignmentMode("manual");
|
|
15219
|
+
} else {
|
|
15220
|
+
setAssignmentMode("algorithm");
|
|
15221
|
+
setPackageAssignments({});
|
|
15222
|
+
}
|
|
15223
|
+
};
|
|
15224
|
+
const changePackageAssignment = (id2, binding) => {
|
|
15225
|
+
if (!manualAllowed || effectiveAssignmentMode !== "manual" || !plan.team.workPackages.some((item) => item.id === id2)) return;
|
|
15226
|
+
setPackageAssignments((previous) => ({ ...previous, [id2]: binding }));
|
|
15227
|
+
};
|
|
14459
15228
|
const providerCount = new Set(routes.map((route) => route.provider)).size;
|
|
14460
15229
|
const refresh = async () => {
|
|
14461
15230
|
const request = ++catalogRequest.current;
|
|
@@ -14502,6 +15271,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14502
15271
|
const next = createWorkspacePlan(task, catalogState.catalog, {
|
|
14503
15272
|
...ledger.routingData,
|
|
14504
15273
|
learning: ledger.learning,
|
|
15274
|
+
routingEvidence: ledger.routingEvidence,
|
|
14505
15275
|
mode,
|
|
14506
15276
|
...direct ? { directProvider: direct.provider, directModel: direct.model } : {},
|
|
14507
15277
|
budgetUsd: parsedBudget,
|
|
@@ -14511,7 +15281,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14511
15281
|
preset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
|
|
14512
15282
|
loggedOutToolIds: (workbench.health.report?.tools ?? []).filter((item) => item.installed && item.login?.state === "logged-out").map((item) => item.id)
|
|
14513
15283
|
});
|
|
14514
|
-
setPlan({ ...next, workbenchRevision: `${ledger.dynamicData?.revision ?? ""}/${ledger.learning?.revision ?? ""}` });
|
|
15284
|
+
setPlan({ ...next, workbenchRevision: `${ledger.dynamicData?.revision ?? ""}/${ledger.learning?.revision ?? ""}/${ledger.routingEvidence?.revision ?? ""}` });
|
|
14515
15285
|
} catch (error) {
|
|
14516
15286
|
if (request !== generationRequest.current || inputs !== generationInputs.current || !mounted.current) return;
|
|
14517
15287
|
setPlan(null);
|
|
@@ -14541,7 +15311,23 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14541
15311
|
budgetValue.current = event.target.value;
|
|
14542
15312
|
setBudget(event.target.value);
|
|
14543
15313
|
invalidatePlan();
|
|
14544
|
-
} }))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button", type: "button", disabled: catalogState.status !== "ready" || routes.length === 0 || toolProbes === null, onClick: generate }, "\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55\u2026" : catalogState.status === "error" ? "\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u201C\u6A21\u578B\u914D\u7F6E\u201D\u4E2D\u5237\u65B0\u3002" : routes.length === 0 ? "\u8BF7\u5148\u5728 Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\u3002" : toolProbes === null ? "\u6B63\u5728\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u2026" : "\u9884\u7B97 0 \u4E3A\u4E0D\u9650\uFF1B\u8D39\u7528\u4E3A\u4F30\u7B97\u3002")), planError && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, planError))), /* @__PURE__ */ import_react5.default.createElement("aside", { className: "mr-planning-guide", "aria-label": "\u89C4\u5212\u4F7F\u7528\u63D0\u793A" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-eyebrow" }, "\u5DE5\u4F5C\u6D41\u7A0B"), /* @__PURE__ */ import_react5.default.createElement("ol", { className: "mr-workflow" }, /* @__PURE__ */ import_react5.default.createElement("li", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "01"), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u63CF\u8FF0\u4EFB\u52A1"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u9009\u62E9\u5355\u4EFB\u52A1\u3001\u56E2\u961F\u5206\u5DE5\u6216\u6307\u5B9A\u6A21\u578B\u3002"))), /* @__PURE__ */ import_react5.default.createElement("li", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "02"), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u6838\u5BF9\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u68C0\u67E5\u6A21\u578B\u3001\u5DE5\u4F5C\u5305\u4F9D\u8D56\u548C\u4F30\u7B97\u8D39\u7528\u3002"))), /* @__PURE__ */ import_react5.default.createElement("li", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "03"), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u9884\u89C8\u5E76\u786E\u8BA4\u6267\u884C"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u786E\u8BA4\u540E\u8C03\u7528\u6A21\u578B\uFF0C\u7ED3\u679C\u5199\u5165\u6267\u884C\u8BB0\u5F55\u3002")))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-guide-links" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => selectView("models") }, "\u914D\u7F6E\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B \u2192"), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => selectView("tools") }, "\u68C0\u67E5\u5B98\u65B9\u5DE5\u5177\u4E0E\u767B\u5F55 \u2192")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u7F3A\u5C11\u4EF7\u683C\u65F6\u4F1A\u63D0\u793A\u201C\u4EF7\u683C\u5F85\u914D\u7F6E\u201D\u3002\u53EA\u8BFB\u68C0\u67E5\u53EF\u76F4\u63A5\u9884\u89C8\uFF1B\u4FEE\u6539\u6587\u4EF6\u65F6\uFF0C\u5148\u9009\u201C\u56E2\u961F\u5206\u5DE5\u201D\uFF0C\u518D\u5728\u6267\u884C\u533A\u9009\u62E9\u201C\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u201D\u548C\u201C\u7F16\u8F91\u6587\u4EF6\u201D\u6743\u9650\uFF0C\u6838\u5BF9\u9884\u89C8\u540E\u786E\u8BA4\u6267\u884C\u3002"))), plan && /* @__PURE__ */ import_react5.default.createElement(
|
|
15314
|
+
} }))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button", type: "button", disabled: catalogState.status !== "ready" || routes.length === 0 || toolProbes === null, onClick: generate }, "\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55\u2026" : catalogState.status === "error" ? "\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u201C\u6A21\u578B\u914D\u7F6E\u201D\u4E2D\u5237\u65B0\u3002" : routes.length === 0 ? "\u8BF7\u5148\u5728 Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\u3002" : toolProbes === null ? "\u6B63\u5728\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u2026" : "\u9884\u7B97 0 \u4E3A\u4E0D\u9650\uFF1B\u8D39\u7528\u4E3A\u4F30\u7B97\u3002")), planError && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, planError))), /* @__PURE__ */ import_react5.default.createElement("aside", { className: "mr-planning-guide", "aria-label": "\u89C4\u5212\u4F7F\u7528\u63D0\u793A" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-eyebrow" }, "\u5DE5\u4F5C\u6D41\u7A0B"), /* @__PURE__ */ import_react5.default.createElement("ol", { className: "mr-workflow" }, /* @__PURE__ */ import_react5.default.createElement("li", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "01"), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u63CF\u8FF0\u4EFB\u52A1"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u9009\u62E9\u5355\u4EFB\u52A1\u3001\u56E2\u961F\u5206\u5DE5\u6216\u6307\u5B9A\u6A21\u578B\u3002"))), /* @__PURE__ */ import_react5.default.createElement("li", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "02"), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u6838\u5BF9\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u68C0\u67E5\u6A21\u578B\u3001\u5DE5\u4F5C\u5305\u4F9D\u8D56\u548C\u4F30\u7B97\u8D39\u7528\u3002"))), /* @__PURE__ */ import_react5.default.createElement("li", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "03"), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u9884\u89C8\u5E76\u786E\u8BA4\u6267\u884C"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u786E\u8BA4\u540E\u8C03\u7528\u6A21\u578B\uFF0C\u7ED3\u679C\u5199\u5165\u6267\u884C\u8BB0\u5F55\u3002")))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-guide-links" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => selectView("models") }, "\u914D\u7F6E\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B \u2192"), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => selectView("tools") }, "\u68C0\u67E5\u5B98\u65B9\u5DE5\u5177\u4E0E\u767B\u5F55 \u2192")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u7F3A\u5C11\u4EF7\u683C\u65F6\u4F1A\u63D0\u793A\u201C\u4EF7\u683C\u5F85\u914D\u7F6E\u201D\u3002\u53EA\u8BFB\u68C0\u67E5\u53EF\u76F4\u63A5\u9884\u89C8\uFF1B\u4FEE\u6539\u6587\u4EF6\u65F6\uFF0C\u5148\u9009\u201C\u56E2\u961F\u5206\u5DE5\u201D\uFF0C\u518D\u5728\u6267\u884C\u533A\u9009\u62E9\u201C\u5B98\u65B9\u5DE5\u5177\u534F\u4F5C\u201D\u548C\u201C\u7F16\u8F91\u6587\u4EF6\u201D\u6743\u9650\uFF0C\u6838\u5BF9\u9884\u89C8\u540E\u786E\u8BA4\u6267\u884C\u3002"))), plan && /* @__PURE__ */ import_react5.default.createElement(
|
|
15315
|
+
PlanResults,
|
|
15316
|
+
{
|
|
15317
|
+
plan,
|
|
15318
|
+
ledger: workbench.ledger.value,
|
|
15319
|
+
headingRef: resultHeading,
|
|
15320
|
+
assignmentMode: effectiveAssignmentMode,
|
|
15321
|
+
packageAssignments,
|
|
15322
|
+
assignmentOptions,
|
|
15323
|
+
manualAllowed,
|
|
15324
|
+
onAssignmentModeChange: changeAssignmentMode,
|
|
15325
|
+
onPackageAssignmentChange: changePackageAssignment,
|
|
15326
|
+
onRestoreAssignments: () => {
|
|
15327
|
+
if (manualAllowed && currentPackagePlanKey) setPackageAssignments(initialPackageAssignments(plan));
|
|
15328
|
+
}
|
|
15329
|
+
}
|
|
15330
|
+
), /* @__PURE__ */ import_react5.default.createElement(
|
|
14545
15331
|
RunLauncher,
|
|
14546
15332
|
{
|
|
14547
15333
|
task,
|
|
@@ -14550,7 +15336,10 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14550
15336
|
ledger: workbench.ledger.value,
|
|
14551
15337
|
previewRun,
|
|
14552
15338
|
startRun,
|
|
14553
|
-
planningRevision: `${routingSettings}/${dataRevision}/${feedbackRevision}`,
|
|
15339
|
+
planningRevision: `${routingSettings}/${dataRevision}/${feedbackRevision}/${evidenceRevision}`,
|
|
15340
|
+
assignmentMode: effectiveAssignmentMode,
|
|
15341
|
+
packageAssignments: effectiveAssignmentMode === "manual" ? packageAssignments : {},
|
|
15342
|
+
packagePlanKey: currentPackagePlanKey,
|
|
14554
15343
|
directRoute: mode === "direct" ? routes.find((route) => `${route.provider}/${route.model}` === directKey) ?? routes[0] ?? null : null,
|
|
14555
15344
|
defaultPreset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
|
|
14556
15345
|
disabledReason: catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55\u2026" : catalogState.status === "error" ? "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u201C\u6A21\u578B\u914D\u7F6E\u201D\u4E2D\u5237\u65B0\u3002" : routes.length === 0 ? "\u8BF7\u5148\u5728\u5B98\u65B9\u201C\u6A21\u578B\u201D\u9875\u914D\u7F6E\u81F3\u5C11\u4E00\u6761\u6A21\u578B\u8DEF\u7EBF\u3002" : "",
|
|
@@ -14575,7 +15364,14 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14575
15364
|
void workbench.rerun(runId, packageId, override, choice);
|
|
14576
15365
|
}
|
|
14577
15366
|
}
|
|
14578
|
-
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view", role: "tabpanel", id: "mr-panel-models", "aria-labelledby": "mr-tab-models", hidden: view !== "models" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u6A21\u578B\u914D\u7F6E"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u4ECE\u5B98\u65B9\u76EE\u5F55\u9009\u62E9\u8DEF\u7EBF\uFF0C\u8865\u9F50\u6BD4\u8F83\u6240\u9700\u7684\u4EF7\u683C\u3001\u80FD\u529B\u4E0E\u6267\u884C\u65B9\u5F0F\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-grid mr-model-grid" }, /* @__PURE__ */ import_react5.default.createElement(ModelProfileEditor, { routes, settingsScope, onSaved: invalidatePlan }), /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u6A21\u578B\u76EE\u5F55" }, /* @__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" }, "\u6A21\u578B\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, routes.length, " \u6761\u8DEF\u7EBF \xB7 \u53EA\u8BFB\u53D6\u5B98\u65B9\u76EE\u5F55\uFF0C\u4E0D\u8BFB\u53D6 API Key\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: catalogState.status === "loading", onClick: refresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, catalogState.status === "error" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-error", role: "alert" }, catalogState.error), catalogState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-empty" }, "\u6B63\u5728\u52A0\u8F7D\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u2026"), catalogState.status === "ready" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-label", htmlFor: "mr-model-search" }, "\u641C\u7D22\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("input", { className: "mr-input mr-search", id: "mr-model-search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: "\u6A21\u578B\u6216\u4F9B\u5E94\u5546" }), /* @__PURE__ */ import_react5.default.createElement(RouteList, { routes, query }), catalogState.catalog?.failures?.length > 0 && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, catalogState.catalog.failures.length, " \u4E2A\u4F9B\u5E94\u5546\u7684\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u9875\u68C0\u67E5\u914D\u7F6E\u3002")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 13 } }, "\u76EE\u5F55\u767B\u8BB0\u4E0D\u4EE3\u8868\u51ED\u636E\u6216\u7F51\u7EDC\u5F53\u524D\u53EF\u7528\uFF1B\u56FE\u50CF\u80FD\u529B\u9700\u8981\u5728\u5B9E\u9645\u4F7F\u7528\u524D\u6838\u5BF9\u3002"))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-tools", "aria-labelledby": "mr-tab-tools", hidden: view !== "tools" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u7BA1\u7406\u672C\u673A CLI\u3001\u68C0\u67E5\u767B\u5F55\u72B6\u6001\uFF0C\u6216\u6253\u5F00\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\u3002")),
|
|
15367
|
+
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view", role: "tabpanel", id: "mr-panel-models", "aria-labelledby": "mr-tab-models", hidden: view !== "models" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u6A21\u578B\u914D\u7F6E"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u4ECE\u5B98\u65B9\u76EE\u5F55\u9009\u62E9\u8DEF\u7EBF\uFF0C\u8865\u9F50\u6BD4\u8F83\u6240\u9700\u7684\u4EF7\u683C\u3001\u80FD\u529B\u4E0E\u6267\u884C\u65B9\u5F0F\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-grid mr-model-grid" }, /* @__PURE__ */ import_react5.default.createElement(ModelProfileEditor, { routes, settingsScope, onSaved: invalidatePlan }), /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u6A21\u578B\u76EE\u5F55" }, /* @__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" }, "\u6A21\u578B\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, routes.length, " \u6761\u8DEF\u7EBF \xB7 \u53EA\u8BFB\u53D6\u5B98\u65B9\u76EE\u5F55\uFF0C\u4E0D\u8BFB\u53D6 API Key\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: catalogState.status === "loading", onClick: refresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, catalogState.status === "error" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-error", role: "alert" }, catalogState.error), catalogState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-empty" }, "\u6B63\u5728\u52A0\u8F7D\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u2026"), catalogState.status === "ready" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-label", htmlFor: "mr-model-search" }, "\u641C\u7D22\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("input", { className: "mr-input mr-search", id: "mr-model-search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: "\u6A21\u578B\u6216\u4F9B\u5E94\u5546" }), /* @__PURE__ */ import_react5.default.createElement(RouteList, { routes, query }), catalogState.catalog?.failures?.length > 0 && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, catalogState.catalog.failures.length, " \u4E2A\u4F9B\u5E94\u5546\u7684\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u9875\u68C0\u67E5\u914D\u7F6E\u3002")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 13 } }, "\u76EE\u5F55\u767B\u8BB0\u4E0D\u4EE3\u8868\u51ED\u636E\u6216\u7F51\u7EDC\u5F53\u524D\u53EF\u7528\uFF1B\u56FE\u50CF\u80FD\u529B\u9700\u8981\u5728\u5B9E\u9645\u4F7F\u7528\u524D\u6838\u5BF9\u3002"))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-tools", "aria-labelledby": "mr-tab-tools", hidden: view !== "tools" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u7BA1\u7406\u672C\u673A CLI\u3001\u68C0\u67E5\u767B\u5F55\u72B6\u6001\uFF0C\u6216\u6253\u5F00\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\u3002")), terminalApi && /* @__PURE__ */ import_react5.default.createElement(
|
|
15368
|
+
CliTerminalCard,
|
|
15369
|
+
{
|
|
15370
|
+
api: terminalApi,
|
|
15371
|
+
health: workbench.health.report,
|
|
15372
|
+
settingsSignature: toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)
|
|
15373
|
+
}
|
|
15374
|
+
), workbench.health.report && !workbench.health.report.onboarding?.completedAt && /* @__PURE__ */ import_react5.default.createElement(
|
|
14579
15375
|
OnboardingBanner,
|
|
14580
15376
|
{
|
|
14581
15377
|
health: workbench.health.report,
|
|
@@ -14605,13 +15401,6 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14605
15401
|
void workbench.refreshHealth(true);
|
|
14606
15402
|
}
|
|
14607
15403
|
}
|
|
14608
|
-
), terminalApi && /* @__PURE__ */ import_react5.default.createElement(
|
|
14609
|
-
CliTerminalCard,
|
|
14610
|
-
{
|
|
14611
|
-
api: terminalApi,
|
|
14612
|
-
health: workbench.health.report,
|
|
14613
|
-
settingsSignature: toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)
|
|
14614
|
-
}
|
|
14615
15404
|
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-controls", "aria-labelledby": "mr-tab-controls", hidden: view !== "controls" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u9884\u7B97\u4E0E\u5B89\u5168"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u8BBE\u7F6E\u6210\u672C\u4E0E\u8D28\u91CF\u7B56\u7565\uFF0C\u6838\u5BF9\u8BA2\u9605\u8BA1\u8D39\u548C\u6267\u884C\u8FB9\u754C\u3002")), /* @__PURE__ */ import_react5.default.createElement(
|
|
14616
15405
|
CostControlCard,
|
|
14617
15406
|
{
|
|
@@ -14756,6 +15545,14 @@ function parseRunRequest(value) {
|
|
|
14756
15545
|
if (request.executionMode !== void 0 && !["read-only", "workspace-write"].includes(request.executionMode)) throw new TypeError("executionMode is invalid");
|
|
14757
15546
|
if (request.executionEnvironment !== void 0 && !["harness", "cli-native"].includes(request.executionEnvironment)) throw new TypeError("executionEnvironment is invalid");
|
|
14758
15547
|
const officialTeam = request.executor === "official-team";
|
|
15548
|
+
if (request.assignmentMode !== void 0 && !["algorithm", "manual"].includes(request.assignmentMode)) throw new TypeError("assignmentMode is invalid");
|
|
15549
|
+
const manual = request.assignmentMode === "manual";
|
|
15550
|
+
if (manual && (officialTeam || provider || model)) throw new TypeError("manual assignments require routed work packages without an explicit global route");
|
|
15551
|
+
if (!manual && (request.packageAssignments !== void 0 || request.packagePlanKey !== void 0)) throw new TypeError("package assignments require manual assignmentMode");
|
|
15552
|
+
const packageAssignments = manual ? parsePackageAssignments(request.packageAssignments) : void 0;
|
|
15553
|
+
if (manual && (!packageAssignments || typeof request.packagePlanKey !== "string" || request.packagePlanKey.length > 200 || !request.packagePlanKey)) {
|
|
15554
|
+
throw new TypeError("manual assignments require packageAssignments and a current packagePlanKey");
|
|
15555
|
+
}
|
|
14759
15556
|
if (officialTeam && (request.planMode !== "team" || provider || model)) throw new TypeError("official-team requires a team plan without an explicit route");
|
|
14760
15557
|
if (!officialTeam && request.executionMode === "workspace-write") throw new TypeError("workspace-write requires official-team");
|
|
14761
15558
|
if (request.executionEnvironment === "cli-native" && (!officialTeam || request.executionMode !== "workspace-write")) {
|
|
@@ -14772,6 +15569,7 @@ function parseRunRequest(value) {
|
|
|
14772
15569
|
...request.executionEnvironment === void 0 ? {} : { executionEnvironment: request.executionEnvironment }
|
|
14773
15570
|
} : {},
|
|
14774
15571
|
...provider ? { provider, model } : {},
|
|
15572
|
+
...manual ? { assignmentMode: "manual", packageAssignments, packagePlanKey: request.packagePlanKey } : {},
|
|
14775
15573
|
...["single", "team"].includes(request.planMode) ? { planMode: request.planMode } : {},
|
|
14776
15574
|
...["economy", "balanced", "quality"].includes(request.preset) ? { preset: request.preset } : {},
|
|
14777
15575
|
...request.budgetUsd !== void 0 ? { budgetUsd: request.budgetUsd } : {},
|