@ljwei-stak/dsh-model-router 0.21.1 → 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 +872 -80
- 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-tools-remote.mjs +10 -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/CHANGELOG.md +14 -0
- package/README.i18n.yaml +2 -2
- package/README.md +12 -8
- package/README.zh.md +12 -8
- 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 +2 -2
- package/docs/releases/0.22.0-validation.md +28 -0
- package/package.json +15 -4
package/.dsh-plugin/client.js
CHANGED
|
@@ -1052,51 +1052,118 @@ function liveBenchRow(snapshot, model) {
|
|
|
1052
1052
|
// .dsh-plugin/shared/assignment-solver.mjs
|
|
1053
1053
|
var EPSILON = 1e-12;
|
|
1054
1054
|
var compareText = (a, b2) => a < b2 ? -1 : a > b2 ? 1 : 0;
|
|
1055
|
-
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;
|
|
1056
1061
|
function compareStates(left, right, minimizeCost = false) {
|
|
1057
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));
|
|
1058
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));
|
|
1059
1077
|
function solveCandidateAssignments({ tasks = [], pools = [], budget = Infinity, beamWidth = 256, exactLimit = 4096, handoffPenalty = 0.015, minimizeCost = false } = {}) {
|
|
1060
1078
|
if (!tasks.length || tasks.length !== pools.length) return null;
|
|
1079
|
+
const taskCount = tasks.length;
|
|
1080
|
+
const taskIndexById = /* @__PURE__ */ new Map();
|
|
1061
1081
|
const preceding = /* @__PURE__ */ new Set();
|
|
1062
|
-
for (
|
|
1063
|
-
|
|
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))) {
|
|
1064
1085
|
throw new RangeError("Assignment tasks must have unique ids and known dependencies in topological order");
|
|
1065
1086
|
}
|
|
1066
1087
|
preceding.add(task.id);
|
|
1088
|
+
taskIndexById.set(task.id, index);
|
|
1067
1089
|
}
|
|
1068
1090
|
const constrained = Number.isFinite(budget);
|
|
1069
|
-
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)));
|
|
1070
1092
|
if (options.some((pool) => pool.length === 0)) return null;
|
|
1071
|
-
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);
|
|
1072
1105
|
let searchSpace = 1;
|
|
1073
1106
|
let searchSpaceCapped = false;
|
|
1074
|
-
for (let index =
|
|
1075
|
-
|
|
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;
|
|
1076
1123
|
const product = searchSpace * options[index].length;
|
|
1077
1124
|
if (product > Number.MAX_SAFE_INTEGER) searchSpaceCapped = true;
|
|
1078
1125
|
searchSpace = Math.min(Number.MAX_SAFE_INTEGER, product);
|
|
1079
1126
|
}
|
|
1080
1127
|
if (constrained && suffixMinimum[0] > budget + EPSILON) return null;
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1083
|
-
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;
|
|
1084
1150
|
let states = [{ choices: [], routesByTask: /* @__PURE__ */ new Map(), score: 0, cost: 0, switches: 0, relaxedCount: 0, qualityShortfall: 0 }];
|
|
1085
|
-
for (let index = 0; index <
|
|
1086
|
-
const task = tasks[index];
|
|
1151
|
+
for (let index = 0; index < taskCount; index++) {
|
|
1087
1152
|
const expanded = [];
|
|
1088
1153
|
for (const state of states) {
|
|
1089
|
-
for (
|
|
1154
|
+
for (let optionIndex = 0; optionIndex < options[index].length; optionIndex++) {
|
|
1155
|
+
const option = options[index][optionIndex];
|
|
1090
1156
|
const cost = state.cost + option.cost;
|
|
1091
1157
|
if (constrained && cost + suffixMinimum[index + 1] > budget + EPSILON) continue;
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
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
|
+
}
|
|
1096
1163
|
const penalty = switches * handoffPenalty;
|
|
1097
1164
|
const shortfall = Math.max(0, Number(option.qualityShortfall) || 0);
|
|
1098
1165
|
const routesByTask2 = new Map(state.routesByTask);
|
|
1099
|
-
routesByTask2.set(
|
|
1166
|
+
routesByTask2.set(tasks[index].id, handoffRoutes[index][optionIndex]);
|
|
1100
1167
|
expanded.push({
|
|
1101
1168
|
choices: [...state.choices, { ...option, handoffPenalty: penalty }],
|
|
1102
1169
|
routesByTask: routesByTask2,
|
|
@@ -1110,22 +1177,404 @@ function solveCandidateAssignments({ tasks = [], pools = [], budget = Infinity,
|
|
|
1110
1177
|
}
|
|
1111
1178
|
}
|
|
1112
1179
|
if (!expanded.length) return null;
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
states = expanded
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
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;
|
|
1122
1279
|
}
|
|
1123
1280
|
states.sort((left, right) => compareStates(left, right, minimizeCost));
|
|
1281
|
+
search.retainedStates = states.length;
|
|
1124
1282
|
const best = states[0];
|
|
1125
1283
|
const { routesByTask, ...result } = best;
|
|
1126
1284
|
return { ...result, minimumCostLowerBound: suffixMinimum[0], search };
|
|
1127
1285
|
}
|
|
1128
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
|
+
|
|
1129
1578
|
// .dsh-plugin/shared/router.mjs
|
|
1130
1579
|
var OBJECTIVE_WEIGHTS = Object.freeze({
|
|
1131
1580
|
simple: Object.freeze({ quality: 0.28, cost: 0.45, latency: 0.14, specialty: 0.04, reasoning: 0.07, risk: 0.02 }),
|
|
@@ -1184,7 +1633,7 @@ var OPENCODE_CATALOG_PROVIDERS = Object.freeze([
|
|
|
1184
1633
|
]);
|
|
1185
1634
|
function classifyTask(text7) {
|
|
1186
1635
|
const value = String(text7 ?? "");
|
|
1187
|
-
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";
|
|
1188
1637
|
return detectTaskTypes(value)[0] ?? "general";
|
|
1189
1638
|
}
|
|
1190
1639
|
var TASK_TYPE_RULES = Object.freeze([
|
|
@@ -1235,10 +1684,12 @@ function specialtyMatch(model, taskType, liveScores = {}) {
|
|
|
1235
1684
|
return 0.38;
|
|
1236
1685
|
}
|
|
1237
1686
|
function qualityForTask(row, taskType) {
|
|
1687
|
+
if (row?.queryEvidence?.type === taskType) return row.queryEvidence.quality;
|
|
1238
1688
|
const base = asScore(row?.liveScores?.[taskType]) ?? asScore(row?.liveOverall) ?? row?.metadata?.quality ?? row?.baseQuality ?? row?.quality ?? 0;
|
|
1239
1689
|
return row?.qualityBias ? clamp(base + row.qualityBias) : base;
|
|
1240
1690
|
}
|
|
1241
1691
|
function qualitySourceForTask(row, taskType) {
|
|
1692
|
+
if (row?.queryEvidence?.type === taskType) return "recorded-query-evidence";
|
|
1242
1693
|
return asScore(row?.liveScores?.[taskType]) !== void 0 || asScore(row?.liveOverall) !== void 0 ? "livebench" : row?.fallbackQualitySource ?? row?.qualitySource ?? "unknown";
|
|
1243
1694
|
}
|
|
1244
1695
|
function specialtyForTask(row, taskType) {
|
|
@@ -1394,9 +1845,9 @@ function explicitRequirements(text7) {
|
|
|
1394
1845
|
const marker = /^(?:[-*•]\s+|\d{1,2}[.)、](?!\d)\s*|[一二三四五六七八九十]{1,3}[、.)]\s*)(.+)$/u;
|
|
1395
1846
|
const marked = lines.map((line) => marker.exec(line)?.[1]).filter(Boolean).map(requirementText).filter(looksLikeRequirement);
|
|
1396
1847
|
if (marked.length >= 2) return marked;
|
|
1397
|
-
const
|
|
1398
|
-
if (
|
|
1399
|
-
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);
|
|
1400
1851
|
}
|
|
1401
1852
|
const clauses = value.split(/[;;,,]/u).map(requirementText).filter(Boolean);
|
|
1402
1853
|
if (clauses.length >= 2 && clauses.every(looksLikeRequirement)) {
|
|
@@ -1539,7 +1990,7 @@ function compareText2(left, right) {
|
|
|
1539
1990
|
return a < b2 ? -1 : a > b2 ? 1 : 0;
|
|
1540
1991
|
}
|
|
1541
1992
|
function compareRowsStable(left, right) {
|
|
1542
|
-
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 ?? ""));
|
|
1543
1994
|
}
|
|
1544
1995
|
function reasoningEffortRank(effort) {
|
|
1545
1996
|
const normalized2 = String(effort ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
|
|
@@ -1565,6 +2016,13 @@ function selectReasoningEffort(efforts, preferred = "medium") {
|
|
|
1565
2016
|
}
|
|
1566
2017
|
function reasoningDecision(row, task) {
|
|
1567
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
|
+
};
|
|
1568
2026
|
const efforts = Array.isArray(row.reasoningEfforts) ? row.reasoningEfforts : [];
|
|
1569
2027
|
if (efforts.length === 0) {
|
|
1570
2028
|
const knownUnsupported = row.reasoningKnown === true;
|
|
@@ -1577,7 +2035,7 @@ function reasoningDecision(row, task) {
|
|
|
1577
2035
|
};
|
|
1578
2036
|
}
|
|
1579
2037
|
const preferredRank = reasoningEffortRank(preferred);
|
|
1580
|
-
const chosen = selectReasoningEffort(efforts, preferred);
|
|
2038
|
+
const chosen = Object.hasOwn(row, "actionEffort") ? row.actionEffort : selectReasoningEffort(efforts, preferred);
|
|
1581
2039
|
const distance = Math.abs(reasoningEffortRank(chosen) - preferredRank);
|
|
1582
2040
|
return {
|
|
1583
2041
|
reasoningEffort: chosen,
|
|
@@ -1595,16 +2053,88 @@ function candidateUtility(row, task, weights, cacheReadRatio = 0, cacheWriteRati
|
|
|
1595
2053
|
const reasoning = reasoningDecision(row, task);
|
|
1596
2054
|
const reference = taskCost({ pricing: COST_REFERENCE_PRICING, reasoningKnown: true, reasoningEfforts: [] }, task, text7, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1597
2055
|
const cost = row.pricing === null ? 0 : 1 / (1 + taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio) / Math.max(reference, 1e-12));
|
|
1598
|
-
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;
|
|
1599
2059
|
return { score, floor, qualityGap, preferenceAdjustment, ...reasoning };
|
|
1600
2060
|
}
|
|
1601
2061
|
function taskCost(row, task, text7, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
1602
2062
|
if (row?.pricing === null) return 0;
|
|
1603
|
-
const
|
|
1604
|
-
const tokens = taskTokenBudget(text7, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity, cacheReadRatio, cacheWriteRatio);
|
|
2063
|
+
const tokens = resourceTokenBudget(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1605
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;
|
|
1606
2065
|
}
|
|
1607
|
-
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) {
|
|
1608
2138
|
if (left.pricing === null || right.pricing === null) return false;
|
|
1609
2139
|
const leftReasoning = reasoningDecision(left, task);
|
|
1610
2140
|
const rightReasoning = reasoningDecision(right, task);
|
|
@@ -1629,7 +2159,8 @@ function dominates(left, right, task, text7, complexity, cacheReadRatio, cacheWr
|
|
|
1629
2159
|
return noWorse && strictlyBetter;
|
|
1630
2160
|
}
|
|
1631
2161
|
function eligibleRowsForTask(rows, task) {
|
|
1632
|
-
|
|
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));
|
|
1633
2164
|
}
|
|
1634
2165
|
function candidatePool(rows, task, weights, text7, complexity, cacheReadRatio, cacheWriteRatio, dependencySensitive = false) {
|
|
1635
2166
|
const eligibleRows = eligibleRowsForTask(rows, task);
|
|
@@ -1642,7 +2173,7 @@ function candidatePool(rows, task, weights, text7, complexity, cacheReadRatio, c
|
|
|
1642
2173
|
decision: candidateUtility(row, task, taskWeights, cacheReadRatio, cacheWriteRatio, text7, complexity),
|
|
1643
2174
|
cost: taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio)
|
|
1644
2175
|
}));
|
|
1645
|
-
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)));
|
|
1646
2177
|
const essential = [
|
|
1647
2178
|
scored.filter((item) => item.row.pricing !== null).sort((left, right) => left.cost - right.cost || compareRowsStable(left.row, right.row))[0],
|
|
1648
2179
|
scored.slice().sort((left, right) => right.decision.score - left.decision.score || compareRowsStable(left.row, right.row))[0],
|
|
@@ -1667,6 +2198,8 @@ function solveAssignments({ rows, tasks, weights, text: text7, complexity, budge
|
|
|
1667
2198
|
route: routeKey(option.row.provider, option.row.model),
|
|
1668
2199
|
score: option.decision.score,
|
|
1669
2200
|
cost: option.cost,
|
|
2201
|
+
actionId: option.row.actionId,
|
|
2202
|
+
handoffRoute: routeKey(option.row.provider, option.row.model),
|
|
1670
2203
|
qualityShortfall: Math.max(0, option.decision.floor - qualityForTask(option.row, tasks[index].type)),
|
|
1671
2204
|
pricingKnown: option.row.pricing !== null,
|
|
1672
2205
|
payload: option
|
|
@@ -1676,7 +2209,7 @@ function solveAssignments({ rows, tasks, weights, text: text7, complexity, budge
|
|
|
1676
2209
|
...result,
|
|
1677
2210
|
assignments: result.choices.map((choice, index) => ({
|
|
1678
2211
|
task: tasks[index],
|
|
1679
|
-
row: choice.payload.row,
|
|
2212
|
+
row: { ...choice.payload.row, estimatedCost: choice.payload.row.pricing === null ? null : choice.cost },
|
|
1680
2213
|
decision: { ...choice.payload.decision, relaxed: choice.qualityShortfall > 0 },
|
|
1681
2214
|
estimatedCost: choice.cost,
|
|
1682
2215
|
handoffPenalty: choice.handoffPenalty
|
|
@@ -1686,7 +2219,7 @@ function solveAssignments({ rows, tasks, weights, text: text7, complexity, budge
|
|
|
1686
2219
|
minimumFeasibleCost: result.minimumCostLowerBound
|
|
1687
2220
|
};
|
|
1688
2221
|
}
|
|
1689
|
-
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 } = {}) {
|
|
1690
2223
|
const presetId = normalizeRoutingPreset(preset);
|
|
1691
2224
|
const firstLine = String(text7 ?? "").split(/\r?\n/u)[0].trim();
|
|
1692
2225
|
const transformOnly = /^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(firstLine) && !/(?:执行|完成|实施|分配)/u.test(firstLine);
|
|
@@ -1702,6 +2235,8 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1702
2235
|
return {
|
|
1703
2236
|
provider: String(entry.provider ?? ""),
|
|
1704
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,
|
|
1705
2240
|
benchmarkModel: typeof entry.benchmarkModel === "string" ? entry.benchmarkModel : void 0,
|
|
1706
2241
|
reasoningEfforts: [...new Set(reasoningEfforts)],
|
|
1707
2242
|
defaultReasoningEffort: entry.defaultReasoningEffort === void 0 ? void 0 : String(entry.defaultReasoningEffort),
|
|
@@ -1764,6 +2299,13 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1764
2299
|
reasoningEfforts: route.reasoningEfforts,
|
|
1765
2300
|
defaultReasoningEffort: route.defaultReasoningEffort,
|
|
1766
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(),
|
|
1767
2309
|
inputModalities: route.inputModalities,
|
|
1768
2310
|
pricing: pricingRow,
|
|
1769
2311
|
score: 0,
|
|
@@ -1840,13 +2382,14 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1840
2382
|
recommendedReasoningEffort: decision?.reasoningEffort,
|
|
1841
2383
|
preferredReasoningEffort: decision?.preferredReasoningEffort ?? task.preferredReasoningEffort,
|
|
1842
2384
|
reasoningFit: Number(Number(decision?.reasoningFit ?? 0).toFixed(3)),
|
|
2385
|
+
...decision?.reasoningExecutionNotice ? { reasoningExecutionNotice: decision.reasoningExecutionNotice } : {},
|
|
1843
2386
|
purpose: task.purpose,
|
|
1844
2387
|
criticality: task.criticality,
|
|
1845
2388
|
qualityFloor: Number(task.qualityFloor.toFixed(3)),
|
|
1846
2389
|
dependsOn: [...task.dependsOn ?? []]
|
|
1847
2390
|
}));
|
|
1848
2391
|
const costBreakdown = assignments.map(({ task, row, decision, estimatedCost, handoffPenalty }, index) => {
|
|
1849
|
-
const tokens =
|
|
2392
|
+
const tokens = resourceTokenBudget(row, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1850
2393
|
const taskEstimate = estimatedCost ?? taskCost(row, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1851
2394
|
return {
|
|
1852
2395
|
stage: index + 1,
|
|
@@ -1862,6 +2405,11 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1862
2405
|
cacheReadTokens: tokens.cacheReadTokens,
|
|
1863
2406
|
cacheWriteTokens: tokens.cacheWriteTokens,
|
|
1864
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 } : {},
|
|
1865
2413
|
estimatedCost: row?.pricing === null || row === null ? null : Number(taskEstimate.toFixed(6)),
|
|
1866
2414
|
quality: qualitySourceForTask(row, task.type) === "unknown" || row === null ? null : Number(qualityForTask(row, task.type).toFixed(3)),
|
|
1867
2415
|
qualitySource: qualitySourceForTask(row, task.type),
|
|
@@ -1876,7 +2424,8 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1876
2424
|
return { task, strongest };
|
|
1877
2425
|
});
|
|
1878
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;
|
|
1879
|
-
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)));
|
|
1880
2429
|
const budgetExceeded = Number(budgetUsd) > 0 && totalEstimate !== null ? totalEstimate > Number(budgetUsd) : null;
|
|
1881
2430
|
const savings = baselineCost === null || totalEstimate === null || !qualityEvidenceComplete ? null : baselineCost <= 0 ? 0 : clamp((baselineCost - totalEstimate) / baselineCost);
|
|
1882
2431
|
const paretoPruned = (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.pruned, 0);
|
|
@@ -1891,7 +2440,13 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1891
2440
|
taskType,
|
|
1892
2441
|
taskTypes: [...new Set(taskNodes.map((task) => task.type).filter((type) => type !== "reasoning"))],
|
|
1893
2442
|
objectiveWeights: weights,
|
|
1894
|
-
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) => {
|
|
1895
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);
|
|
1896
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 };
|
|
1897
2452
|
}),
|
|
@@ -1903,6 +2458,11 @@ function buildPlan({ text: text7 = "", available = [], mode = "collective", pric
|
|
|
1903
2458
|
costBreakdown,
|
|
1904
2459
|
optimization: {
|
|
1905
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",
|
|
1906
2466
|
personalization: learning ? {
|
|
1907
2467
|
policyVersion: learning.policyVersion,
|
|
1908
2468
|
revision: learning.revision,
|
|
@@ -2015,12 +2575,14 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2015
2575
|
liveBenchError = "",
|
|
2016
2576
|
dataVersions = null,
|
|
2017
2577
|
learning = null,
|
|
2578
|
+
routingEvidence = null,
|
|
2018
2579
|
cacheReadRatio = 0,
|
|
2019
2580
|
cacheWriteRatio = 0,
|
|
2020
2581
|
directProvider = "",
|
|
2021
2582
|
directModel = "",
|
|
2022
2583
|
preset = "balanced",
|
|
2023
|
-
loggedOutToolIds = []
|
|
2584
|
+
loggedOutToolIds = [],
|
|
2585
|
+
forceOfficialCli = false
|
|
2024
2586
|
} = {}) {
|
|
2025
2587
|
const taskText = clean2(task);
|
|
2026
2588
|
if (!taskText) throw new Error("task must contain text");
|
|
@@ -2042,13 +2604,28 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2042
2604
|
const channelOf = (provider, model) => {
|
|
2043
2605
|
const route = routes.find((item) => item.provider === provider && item.model === model);
|
|
2044
2606
|
const key = `${String(provider ?? "")}\0${String(model ?? "")}\0${route?.execution ?? ""}`;
|
|
2045
|
-
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
|
+
}
|
|
2046
2616
|
return channelCache.get(key);
|
|
2047
2617
|
};
|
|
2048
2618
|
const needsImage = detectTaskTypes(taskText).includes("vision");
|
|
2049
2619
|
const plan = buildPlan({
|
|
2050
2620
|
text: taskText,
|
|
2051
|
-
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
|
+
}),
|
|
2052
2629
|
mode: directRoute ? "single" : selectedMode,
|
|
2053
2630
|
budgetUsd: Math.max(0, Number.isFinite(budgetUsd) ? budgetUsd : 0),
|
|
2054
2631
|
pricing,
|
|
@@ -2056,6 +2633,7 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2056
2633
|
liveBenchError,
|
|
2057
2634
|
dataVersions,
|
|
2058
2635
|
learning,
|
|
2636
|
+
routingEvidence,
|
|
2059
2637
|
cacheReadRatio,
|
|
2060
2638
|
cacheWriteRatio,
|
|
2061
2639
|
preset
|
|
@@ -2093,6 +2671,7 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2093
2671
|
recommendedModel: item.recommended,
|
|
2094
2672
|
estimatedCost: plan.costBreakdown[index]?.estimatedCost ?? null,
|
|
2095
2673
|
...item.recommendedReasoningEffort ? { recommendedReasoningEffort: item.recommendedReasoningEffort } : {},
|
|
2674
|
+
...item.reasoningExecutionNotice ? { reasoningExecutionNotice: item.reasoningExecutionNotice } : {},
|
|
2096
2675
|
...annotate(channelOf(item.recommendedProvider, item.recommended)),
|
|
2097
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"]
|
|
2098
2677
|
}))
|
|
@@ -2100,13 +2679,68 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
2100
2679
|
};
|
|
2101
2680
|
}
|
|
2102
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
|
+
|
|
2103
2737
|
// .dsh-plugin/shared/run-ledger.mjs
|
|
2104
|
-
var
|
|
2738
|
+
var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2105
2739
|
var routeKey2 = (provider, model) => `${String(provider ?? "")}\0${String(model ?? "")}`;
|
|
2106
2740
|
var MAX_SPENDING_DAYS = 90;
|
|
2107
2741
|
var MAX_SPENDING_MONTHS = 24;
|
|
2108
2742
|
function periodSpending(value) {
|
|
2109
|
-
const amount = (field2) =>
|
|
2743
|
+
const amount = (field2) => finite2(value?.[field2]) && value[field2] >= 0 ? value[field2] : 0;
|
|
2110
2744
|
return {
|
|
2111
2745
|
costUsd: amount("costUsd"),
|
|
2112
2746
|
unknown: Math.floor(amount("unknown")),
|
|
@@ -2126,9 +2760,9 @@ function formatUsd(value) {
|
|
|
2126
2760
|
}
|
|
2127
2761
|
function budgetCheck({ estimateUsd = null, spent = { today: 0, month: 0 }, dailyLimitUsd = 0, monthlyLimitUsd = 0 } = {}) {
|
|
2128
2762
|
const limits = [];
|
|
2129
|
-
if (
|
|
2130
|
-
if (
|
|
2131
|
-
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);
|
|
2132
2766
|
const remaining = limits.length ? Math.max(0, Math.min(...limits.map((item) => item.limit - item.spent))) : null;
|
|
2133
2767
|
const exceeded = limits.find((item) => item.spent >= item.limit || estimateKnown && item.spent + estimateUsd > item.limit) ?? null;
|
|
2134
2768
|
return {
|
|
@@ -2144,12 +2778,12 @@ function applyQualityBiases(routes, biases) {
|
|
|
2144
2778
|
if (!biases || typeof biases !== "object") return routes;
|
|
2145
2779
|
return (Array.isArray(routes) ? routes : []).map((route) => {
|
|
2146
2780
|
const bias = biases[routeKey2(route.provider, route.model)];
|
|
2147
|
-
return
|
|
2781
|
+
return finite2(bias) && bias !== 0 ? { ...route, qualityBias: bias } : route;
|
|
2148
2782
|
});
|
|
2149
2783
|
}
|
|
2150
2784
|
|
|
2151
2785
|
// .dsh-plugin/shared/adaptive-feedback.mjs
|
|
2152
|
-
var
|
|
2786
|
+
var finite3 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2153
2787
|
var clean3 = (value) => typeof value === "string" ? value.trim() : "";
|
|
2154
2788
|
var routeKey3 = (provider, model) => `${provider}\0${model}`;
|
|
2155
2789
|
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -2168,8 +2802,8 @@ function applyFeedbackProfile(routes, profile) {
|
|
|
2168
2802
|
if (!Object.hasOwn(profile.adjustments, key)) return base;
|
|
2169
2803
|
const value = profile.adjustments[key];
|
|
2170
2804
|
if (!record(value)) return base;
|
|
2171
|
-
const limit =
|
|
2172
|
-
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));
|
|
2173
2807
|
if (!Object.keys(adjustments).length) return base;
|
|
2174
2808
|
return {
|
|
2175
2809
|
...base,
|
|
@@ -2807,7 +3441,59 @@ function billingSwitchText(item) {
|
|
|
2807
3441
|
if (!note?.reason) return null;
|
|
2808
3442
|
return note.reason;
|
|
2809
3443
|
}
|
|
2810
|
-
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
|
+
}
|
|
2811
3497
|
if (!["routed", "official-team"].includes(executor)) throw new Error("\u4E0D\u652F\u6301\u7684\u6267\u884C\u65B9\u5F0F\u3002");
|
|
2812
3498
|
if (!["read-only", "workspace-write"].includes(executionMode)) throw new Error("\u4E0D\u652F\u6301\u7684\u4EFB\u52A1\u6743\u9650\u3002");
|
|
2813
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");
|
|
@@ -2820,7 +3506,8 @@ function launchRequest({ task, mode, directRoute, budgetUsd, preset, workspace,
|
|
|
2820
3506
|
...executionEnvironment === "cli-native" ? { executionEnvironment } : {},
|
|
2821
3507
|
...mode === "direct" && directRoute ? { provider: directRoute.provider, model: directRoute.model } : { planMode: mode === "team" ? "team" : "single", preset },
|
|
2822
3508
|
...Number.isFinite(budget) && budget >= 0 ? { budgetUsd: budget } : {},
|
|
2823
|
-
...typeof workspace === "string" && workspace.trim() ? { workspace: workspace.trim() } : {}
|
|
3509
|
+
...typeof workspace === "string" && workspace.trim() ? { workspace: workspace.trim() } : {},
|
|
3510
|
+
...manual ?? {}
|
|
2824
3511
|
};
|
|
2825
3512
|
}
|
|
2826
3513
|
function rerunConfirmations({ run, item, override = null, choice = null, ledger = null, health = null, toolFor = () => null, headlessIds = /* @__PURE__ */ new Set() } = {}) {
|
|
@@ -2850,6 +3537,10 @@ function rerunConfirmations({ run, item, override = null, choice = null, ledger
|
|
|
2850
3537
|
|
|
2851
3538
|
// .dsh-plugin/client/adaptive-state.mjs
|
|
2852
3539
|
var ADAPTIVE_DEFAULTS = Object.freeze({
|
|
3540
|
+
routingEvidenceJson: "",
|
|
3541
|
+
resourceLearningEnabled: true,
|
|
3542
|
+
qualityEscalationEnabled: false,
|
|
3543
|
+
qualityGateJson: "",
|
|
2853
3544
|
feedbackLearningEnabled: true,
|
|
2854
3545
|
feedbackHalfLifeDays: 30,
|
|
2855
3546
|
feedbackPriorWeight: 3,
|
|
@@ -3271,7 +3962,7 @@ function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
|
|
|
3271
3962
|
const rerun = rerunSupport(run);
|
|
3272
3963
|
const canRerun = rerun.supported && !item.ok && !busy;
|
|
3273
3964
|
const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
|
|
3274
|
-
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: () => {
|
|
3275
3966
|
const [provider, model] = target.split("\0");
|
|
3276
3967
|
onRerun(run.id, item.id, { provider, model });
|
|
3277
3968
|
} }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
|
|
@@ -3326,18 +4017,23 @@ var STATUS_TEXT = Object.freeze({
|
|
|
3326
4017
|
"paused-budget": "\u5DF2\u56E0\u9884\u7B97\u6682\u505C\uFF0C\u672A\u542F\u52A8\u6A21\u578B",
|
|
3327
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"
|
|
3328
4019
|
});
|
|
3329
|
-
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 }) {
|
|
3330
4021
|
const [preset, setPreset] = import_react3.default.useState(defaultPreset || "balanced");
|
|
3331
4022
|
const [executor, setExecutor] = import_react3.default.useState("routed");
|
|
3332
4023
|
const [executionMode, setExecutionMode] = import_react3.default.useState("read-only");
|
|
3333
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;
|
|
3334
4030
|
const lastWorkspace = [...ledger?.runs ?? []].map((run) => run.workspace).find(Boolean) ?? "";
|
|
3335
4031
|
const [workspace, setWorkspace] = import_react3.default.useState("");
|
|
3336
4032
|
const [phase, setPhase] = import_react3.default.useState({ kind: "idle" });
|
|
3337
4033
|
const mounted = import_react3.default.useRef(true);
|
|
3338
4034
|
const confirmRef = import_react3.default.useRef(null);
|
|
3339
4035
|
const pendingRequest = import_react3.default.useRef(0);
|
|
3340
|
-
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]);
|
|
3341
4037
|
const latestSignature = import_react3.default.useRef(inputSignature);
|
|
3342
4038
|
latestSignature.current = inputSignature;
|
|
3343
4039
|
import_react3.default.useEffect(() => {
|
|
@@ -3351,12 +4047,12 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
3351
4047
|
setPreset(defaultPreset || "balanced");
|
|
3352
4048
|
}, [defaultPreset]);
|
|
3353
4049
|
import_react3.default.useEffect(() => {
|
|
3354
|
-
if (mode !== "team") {
|
|
4050
|
+
if (mode !== "team" || manual) {
|
|
3355
4051
|
setExecutor("routed");
|
|
3356
4052
|
setExecutionMode("read-only");
|
|
3357
4053
|
setExecutionEnvironment("harness");
|
|
3358
4054
|
}
|
|
3359
|
-
}, [mode]);
|
|
4055
|
+
}, [mode, manual]);
|
|
3360
4056
|
import_react3.default.useEffect(() => {
|
|
3361
4057
|
pendingRequest.current += 1;
|
|
3362
4058
|
setPhase((previous) => ["previewing", "preview", "error"].includes(previous.kind) ? { kind: "idle" } : previous);
|
|
@@ -3364,16 +4060,35 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
3364
4060
|
import_react3.default.useEffect(() => {
|
|
3365
4061
|
if (phase.kind === "preview") confirmRef.current?.focus();
|
|
3366
4062
|
}, [phase.kind]);
|
|
3367
|
-
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
|
+
});
|
|
3368
4077
|
const unavailable = typeof previewRun !== "function" || typeof startRun !== "function";
|
|
3369
|
-
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" : "");
|
|
3370
4079
|
const busy = phase.kind === "previewing" || phase.kind === "running";
|
|
3371
4080
|
const recordedRun = phase.kind === "done" && phase.value.runId ? (ledger?.runs ?? []).find((run) => run.id === phase.value.runId) : null;
|
|
3372
4081
|
const resultStatus = recordedRun?.status ?? phase.value?.status;
|
|
3373
4082
|
const preview = async () => {
|
|
3374
4083
|
if (blocked || busy) return;
|
|
3375
4084
|
const current = ++pendingRequest.current;
|
|
3376
|
-
|
|
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
|
+
}
|
|
3377
4092
|
const signature2 = inputSignature;
|
|
3378
4093
|
setPhase({ kind: "previewing" });
|
|
3379
4094
|
try {
|
|
@@ -3402,16 +4117,16 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
3402
4117
|
if (mounted.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u5931\u8D25\u3002" });
|
|
3403
4118
|
}
|
|
3404
4119
|
};
|
|
3405
|
-
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: () => {
|
|
3406
4121
|
setExecutor("routed");
|
|
3407
4122
|
setExecutionMode("read-only");
|
|
3408
4123
|
setExecutionEnvironment("harness");
|
|
3409
|
-
} }, "\u6A21\u578B\u8DEF\u7531\uFF08\u53EA\u8BFB\uFF09"), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", "aria-pressed":
|
|
3410
|
-
if (mode === "team") setExecutor("official-team");
|
|
3411
|
-
} }, "\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: () => {
|
|
3412
4127
|
setExecutionMode("read-only");
|
|
3413
4128
|
setExecutionEnvironment("harness");
|
|
3414
|
-
} }, "\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: () => {
|
|
3415
4130
|
void preview();
|
|
3416
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(
|
|
3417
4132
|
LaunchPreview,
|
|
@@ -3436,8 +4151,12 @@ function LaunchPreview({ value, request, changed, running, confirmRef, onConfirm
|
|
|
3436
4151
|
const native = (value.executionEnvironment ?? request?.executionEnvironment) === "cli-native";
|
|
3437
4152
|
const readOnly = value.readOnly !== false && (value.executionMode ?? request?.executionMode) !== "workspace-write";
|
|
3438
4153
|
const blocked = value.status === "blocked";
|
|
4154
|
+
const manual = request?.assignmentMode === "manual" || value.assignmentMode === "manual";
|
|
3439
4155
|
const blocking = [...new Set([value.reason, ...Array.isArray(value.blocking) ? value.blocking : [value.blocking]].map(reasonText).filter(Boolean))];
|
|
3440
|
-
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")));
|
|
3441
4160
|
}
|
|
3442
4161
|
|
|
3443
4162
|
// .dsh-plugin/client/cli-terminal.jsx
|
|
@@ -12870,7 +13589,7 @@ var xterm_default = `/**
|
|
|
12870
13589
|
`;
|
|
12871
13590
|
|
|
12872
13591
|
// .dsh-plugin/client/host-version.mjs
|
|
12873
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
13592
|
+
var ROUTER_CLIENT_VERSION = true ? "0.22.0" : "";
|
|
12874
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";
|
|
12875
13594
|
function isMissingRemoteMethod(message) {
|
|
12876
13595
|
const value = String(message ?? "");
|
|
@@ -13481,6 +14200,11 @@ var router_main_default = `.mr-workspace {
|
|
|
13481
14200
|
.mr-package-name { font-size: 12px; font-weight: 750; }
|
|
13482
14201
|
.mr-package-route { color: var(--mr-accent); font-size: 11px; font-weight: 700; }
|
|
13483
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; }
|
|
13484
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; }
|
|
13485
14209
|
.mr-notice code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; }
|
|
13486
14210
|
@media (max-width: 850px) { .mr-grid { grid-template-columns: 1fr; } .mr-shell { padding: 24px 18px 48px; } }
|
|
@@ -13704,6 +14428,7 @@ var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
|
13704
14428
|
var routingSettingsSignature = (value) => JSON.stringify([
|
|
13705
14429
|
value.modelProfilesJson,
|
|
13706
14430
|
value.routingPreset,
|
|
14431
|
+
value.allowManualReassign,
|
|
13707
14432
|
...Object.keys(ADAPTIVE_DEFAULTS).map((key) => value[key] ?? ADAPTIVE_DEFAULTS[key])
|
|
13708
14433
|
]);
|
|
13709
14434
|
function RouterPanelIcon({ size = 20, active = false }) {
|
|
@@ -13722,12 +14447,25 @@ function ChannelBadge({ item }) {
|
|
|
13722
14447
|
const official = item.executionChannel === "official-cli";
|
|
13723
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");
|
|
13724
14449
|
}
|
|
13725
|
-
function PlanResults({ plan, ledger, headingRef }) {
|
|
14450
|
+
function PlanResults({ plan, ledger, headingRef, assignmentMode = "algorithm", packageAssignments = {}, assignmentOptions = [], manualAllowed = true, onAssignmentModeChange, onPackageAssignmentChange, onRestoreAssignments }) {
|
|
13726
14451
|
const selected = plan.selected;
|
|
13727
14452
|
const budget = planBudget(ledger, plan.estimatedCost);
|
|
13728
14453
|
const packageNames = new Map((plan.team?.workPackages ?? []).map((item) => [item.id, item.name]));
|
|
13729
14454
|
const purposeLabel = { analysis: "\u4EFB\u52A1\u5206\u6790", execution: "\u4EFB\u52A1\u5B9E\u65BD", verification: "\u72EC\u7ACB\u9A8C\u8BC1", synthesis: "\u7ED3\u679C\u6574\u5408" };
|
|
13730
|
-
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)));
|
|
13731
14469
|
}
|
|
13732
14470
|
var remoteError = (response, fallback) => remoteErrorText(
|
|
13733
14471
|
text5(response?.error?.message) || text5(response?.value?.error) || (typeof response?.error === "string" ? response.error : ""),
|
|
@@ -14385,6 +15123,8 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14385
15123
|
const [budget, setBudget] = import_react5.default.useState(() => String(settingsScope.getSnapshot().value?.budgetUsd ?? 0));
|
|
14386
15124
|
const [query, setQuery] = import_react5.default.useState("");
|
|
14387
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({});
|
|
14388
15128
|
const [planError, setPlanError] = import_react5.default.useState("");
|
|
14389
15129
|
const [toolProbes, setToolProbes] = import_react5.default.useState(null);
|
|
14390
15130
|
const [routingSettings, setRoutingSettings] = import_react5.default.useState(() => {
|
|
@@ -14440,12 +15180,18 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14440
15180
|
}, [routingSettings]);
|
|
14441
15181
|
const dataRevision = workbench.ledger.value?.dynamicData?.revision ?? "";
|
|
14442
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;
|
|
15185
|
+
import_react5.default.useEffect(() => {
|
|
15186
|
+
setAssignmentMode("algorithm");
|
|
15187
|
+
setPackageAssignments({});
|
|
15188
|
+
}, [plan, task, mode, routingSettings, catalogState.catalog, toolProbes, workbench.health.report?.tools, manualAllowed]);
|
|
14443
15189
|
import_react5.default.useEffect(() => {
|
|
14444
|
-
if (plan && plan.workbenchRevision !== `${dataRevision}/${feedbackRevision}`) {
|
|
15190
|
+
if (plan && plan.workbenchRevision !== `${dataRevision}/${feedbackRevision}/${evidenceRevision}`) {
|
|
14445
15191
|
setPlan(null);
|
|
14446
15192
|
setPlanError("");
|
|
14447
15193
|
}
|
|
14448
|
-
}, [dataRevision, feedbackRevision, plan]);
|
|
15194
|
+
}, [dataRevision, feedbackRevision, evidenceRevision, plan]);
|
|
14449
15195
|
import_react5.default.useEffect(() => {
|
|
14450
15196
|
mounted.current = true;
|
|
14451
15197
|
const request = ++catalogRequest.current;
|
|
@@ -14462,6 +15208,23 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14462
15208
|
};
|
|
14463
15209
|
}, []);
|
|
14464
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
|
+
};
|
|
14465
15228
|
const providerCount = new Set(routes.map((route) => route.provider)).size;
|
|
14466
15229
|
const refresh = async () => {
|
|
14467
15230
|
const request = ++catalogRequest.current;
|
|
@@ -14508,6 +15271,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14508
15271
|
const next = createWorkspacePlan(task, catalogState.catalog, {
|
|
14509
15272
|
...ledger.routingData,
|
|
14510
15273
|
learning: ledger.learning,
|
|
15274
|
+
routingEvidence: ledger.routingEvidence,
|
|
14511
15275
|
mode,
|
|
14512
15276
|
...direct ? { directProvider: direct.provider, directModel: direct.model } : {},
|
|
14513
15277
|
budgetUsd: parsedBudget,
|
|
@@ -14517,7 +15281,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14517
15281
|
preset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
|
|
14518
15282
|
loggedOutToolIds: (workbench.health.report?.tools ?? []).filter((item) => item.installed && item.login?.state === "logged-out").map((item) => item.id)
|
|
14519
15283
|
});
|
|
14520
|
-
setPlan({ ...next, workbenchRevision: `${ledger.dynamicData?.revision ?? ""}/${ledger.learning?.revision ?? ""}` });
|
|
15284
|
+
setPlan({ ...next, workbenchRevision: `${ledger.dynamicData?.revision ?? ""}/${ledger.learning?.revision ?? ""}/${ledger.routingEvidence?.revision ?? ""}` });
|
|
14521
15285
|
} catch (error) {
|
|
14522
15286
|
if (request !== generationRequest.current || inputs !== generationInputs.current || !mounted.current) return;
|
|
14523
15287
|
setPlan(null);
|
|
@@ -14547,7 +15311,23 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14547
15311
|
budgetValue.current = event.target.value;
|
|
14548
15312
|
setBudget(event.target.value);
|
|
14549
15313
|
invalidatePlan();
|
|
14550
|
-
} }))), /* @__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(
|
|
14551
15331
|
RunLauncher,
|
|
14552
15332
|
{
|
|
14553
15333
|
task,
|
|
@@ -14556,7 +15336,10 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14556
15336
|
ledger: workbench.ledger.value,
|
|
14557
15337
|
previewRun,
|
|
14558
15338
|
startRun,
|
|
14559
|
-
planningRevision: `${routingSettings}/${dataRevision}/${feedbackRevision}`,
|
|
15339
|
+
planningRevision: `${routingSettings}/${dataRevision}/${feedbackRevision}/${evidenceRevision}`,
|
|
15340
|
+
assignmentMode: effectiveAssignmentMode,
|
|
15341
|
+
packageAssignments: effectiveAssignmentMode === "manual" ? packageAssignments : {},
|
|
15342
|
+
packagePlanKey: currentPackagePlanKey,
|
|
14560
15343
|
directRoute: mode === "direct" ? routes.find((route) => `${route.provider}/${route.model}` === directKey) ?? routes[0] ?? null : null,
|
|
14561
15344
|
defaultPreset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
|
|
14562
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" : "",
|
|
@@ -14762,6 +15545,14 @@ function parseRunRequest(value) {
|
|
|
14762
15545
|
if (request.executionMode !== void 0 && !["read-only", "workspace-write"].includes(request.executionMode)) throw new TypeError("executionMode is invalid");
|
|
14763
15546
|
if (request.executionEnvironment !== void 0 && !["harness", "cli-native"].includes(request.executionEnvironment)) throw new TypeError("executionEnvironment is invalid");
|
|
14764
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
|
+
}
|
|
14765
15556
|
if (officialTeam && (request.planMode !== "team" || provider || model)) throw new TypeError("official-team requires a team plan without an explicit route");
|
|
14766
15557
|
if (!officialTeam && request.executionMode === "workspace-write") throw new TypeError("workspace-write requires official-team");
|
|
14767
15558
|
if (request.executionEnvironment === "cli-native" && (!officialTeam || request.executionMode !== "workspace-write")) {
|
|
@@ -14778,6 +15569,7 @@ function parseRunRequest(value) {
|
|
|
14778
15569
|
...request.executionEnvironment === void 0 ? {} : { executionEnvironment: request.executionEnvironment }
|
|
14779
15570
|
} : {},
|
|
14780
15571
|
...provider ? { provider, model } : {},
|
|
15572
|
+
...manual ? { assignmentMode: "manual", packageAssignments, packagePlanKey: request.packagePlanKey } : {},
|
|
14781
15573
|
...["single", "team"].includes(request.planMode) ? { planMode: request.planMode } : {},
|
|
14782
15574
|
...["economy", "balanced", "quality"].includes(request.preset) ? { preset: request.preset } : {},
|
|
14783
15575
|
...request.budgetUsd !== void 0 ? { budgetUsd: request.budgetUsd } : {},
|