@ljwei-stak/dsh-model-router 0.14.0 → 0.16.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 +790 -228
- package/.dsh-plugin/index.mjs +124 -29
- package/.dsh-plugin/shared/adaptive-feedback.mjs +192 -0
- package/.dsh-plugin/shared/assignment-solver.mjs +86 -0
- package/.dsh-plugin/shared/dynamic-data-view.mjs +65 -0
- package/.dsh-plugin/shared/dynamic-data.mjs +294 -0
- package/.dsh-plugin/shared/harness-plan.mjs +5 -2
- package/.dsh-plugin/shared/livebench.mjs +57 -20
- package/.dsh-plugin/shared/model-profiles.mjs +7 -1
- package/.dsh-plugin/shared/official-tools-remote.mjs +3 -1
- package/.dsh-plugin/shared/router-state.mjs +18 -7
- package/.dsh-plugin/shared/router.mjs +115 -152
- package/.dsh-plugin/shared/run-ledger.mjs +93 -24
- package/CHANGELOG.md +29 -0
- package/INSTALLATION_GUIDE.zh.md +41 -27
- package/README.md +158 -363
- package/README.zh.md +157 -353
- package/docs/ROUTING_ADAPTIVE_LEARNING.zh.md +151 -0
- package/docs/ROUTING_DERIVATION_EXPERIMENTS.zh.md +684 -0
- package/docs/ROUTING_LIVEBENCH_DATA_SEARCH.zh.md +74 -0
- package/docs/ROUTING_LIVEBENCH_VALIDATION.zh.md +154 -0
- package/docs/ROUTING_RESEARCH.zh.md +59 -0
- package/docs/ROUTING_SELFTEST_STEPS.zh.md +192 -0
- package/docs/WORKBENCH_USER_GUIDE.zh.md +192 -0
- package/docs/assets/workbench-task-preview.jpg +0 -0
- package/package.json +21 -2
package/.dsh-plugin/client.js
CHANGED
|
@@ -174,7 +174,7 @@ function nonnegative(value, label) {
|
|
|
174
174
|
function normalizeProfile(entry, index) {
|
|
175
175
|
const label = `\u7B2C ${index + 1} \u4E2A\u6A21\u578B`;
|
|
176
176
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) throw new Error(`${label} \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
177
|
-
const allowed = /* @__PURE__ */ new Set(["provider", "model", "quality", "pricing", "specialties", "cliModel", "execution", "billing", "subscription", "apiRoute"]);
|
|
177
|
+
const allowed = /* @__PURE__ */ new Set(["provider", "model", "benchmarkModel", "quality", "pricing", "specialties", "cliModel", "execution", "billing", "subscription", "apiRoute"]);
|
|
178
178
|
const unknown = Object.keys(entry).find((key) => !allowed.has(key));
|
|
179
179
|
if (unknown) throw new Error(`${label} \u542B\u4E0D\u652F\u6301\u7684\u5B57\u6BB5 ${unknown}\uFF1B\u4E0D\u8981\u5728\u8FD9\u91CC\u586B\u5199\u5BC6\u94A5\u6216\u547D\u4EE4`);
|
|
180
180
|
const provider = id(entry.provider);
|
|
@@ -183,6 +183,11 @@ function normalizeProfile(entry, index) {
|
|
|
183
183
|
throw new Error(`${label} \u9700\u8981\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E provider \u548C model`);
|
|
184
184
|
}
|
|
185
185
|
const profile = { provider, model };
|
|
186
|
+
if (entry.benchmarkModel !== void 0) {
|
|
187
|
+
const benchmarkModel = id(entry.benchmarkModel);
|
|
188
|
+
if (!benchmarkModel || benchmarkModel.length > 240 || /[\u0000-\u001f]/u.test(benchmarkModel)) throw new Error(`${label} \u7684 benchmarkModel \u9700\u8981\u51C6\u786E\u7684\u57FA\u51C6\u6A21\u578B\u540D\u79F0`);
|
|
189
|
+
profile.benchmarkModel = benchmarkModel;
|
|
190
|
+
}
|
|
186
191
|
if (entry.quality !== void 0) {
|
|
187
192
|
const value = nonnegative(entry.quality, `${label} \u7684 quality`);
|
|
188
193
|
if (value > 100) throw new Error(`${label} \u7684 quality \u5E94\u5728 0 \u5230 100 \u4E4B\u95F4`);
|
|
@@ -278,6 +283,7 @@ function applyModelProfiles(routes, profiles) {
|
|
|
278
283
|
if (!profile) return route;
|
|
279
284
|
return {
|
|
280
285
|
...route,
|
|
286
|
+
...profile.benchmarkModel === void 0 ? {} : { benchmarkModel: profile.benchmarkModel },
|
|
281
287
|
...profile.quality === void 0 ? {} : { quality: profile.quality, qualitySource: "user" },
|
|
282
288
|
...profile.pricing === void 0 ? {} : { pricing: { ...profile.pricing }, pricingSource: "user" },
|
|
283
289
|
...profile.specialties === void 0 ? {} : { specialties: [...profile.specialties] },
|
|
@@ -466,7 +472,7 @@ var TASK_ALIASES = Object.freeze({
|
|
|
466
472
|
var CATEGORY_TO_TASK = Object.freeze({
|
|
467
473
|
reasoning: "reasoning",
|
|
468
474
|
coding: "code",
|
|
469
|
-
|
|
475
|
+
// Agentic Coding is a different task family, not silently a Coding score.
|
|
470
476
|
mathematics: "math",
|
|
471
477
|
"data analysis": "research",
|
|
472
478
|
language: "writing",
|
|
@@ -478,7 +484,85 @@ function normalized(value) {
|
|
|
478
484
|
return String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
479
485
|
}
|
|
480
486
|
function liveBenchRow(snapshot, model) {
|
|
481
|
-
|
|
487
|
+
const row = snapshot?.models?.[normalized(model)] ?? null;
|
|
488
|
+
return snapshot?.exactModelMatch === true && row?.model !== model ? null : row;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// .dsh-plugin/shared/assignment-solver.mjs
|
|
492
|
+
var EPSILON = 1e-12;
|
|
493
|
+
var compareText = (a, b2) => a < b2 ? -1 : a > b2 ? 1 : 0;
|
|
494
|
+
var signature = (state) => JSON.stringify(state.choices.map((option) => option.route));
|
|
495
|
+
function compareStates(left, right, minimizeCost = false) {
|
|
496
|
+
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));
|
|
497
|
+
}
|
|
498
|
+
function solveCandidateAssignments({ tasks = [], pools = [], budget = Infinity, beamWidth = 256, exactLimit = 4096, handoffPenalty = 0.015, minimizeCost = false } = {}) {
|
|
499
|
+
if (!tasks.length || tasks.length !== pools.length) return null;
|
|
500
|
+
const preceding = /* @__PURE__ */ new Set();
|
|
501
|
+
for (const task of tasks) {
|
|
502
|
+
if (!task.id || preceding.has(task.id) || (task.dependsOn ?? []).some((id2) => !preceding.has(id2))) {
|
|
503
|
+
throw new RangeError("Assignment tasks must have unique ids and known dependencies in topological order");
|
|
504
|
+
}
|
|
505
|
+
preceding.add(task.id);
|
|
506
|
+
}
|
|
507
|
+
const constrained = Number.isFinite(budget);
|
|
508
|
+
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)));
|
|
509
|
+
if (options.some((pool) => pool.length === 0)) return null;
|
|
510
|
+
const suffixMinimum = Array(tasks.length + 1).fill(0);
|
|
511
|
+
let searchSpace = 1;
|
|
512
|
+
let searchSpaceCapped = false;
|
|
513
|
+
for (let index = tasks.length - 1; index >= 0; index--) {
|
|
514
|
+
suffixMinimum[index] = suffixMinimum[index + 1] + Math.min(...options[index].map((option) => option.cost));
|
|
515
|
+
const product = searchSpace * options[index].length;
|
|
516
|
+
if (product > Number.MAX_SAFE_INTEGER) searchSpaceCapped = true;
|
|
517
|
+
searchSpace = Math.min(Number.MAX_SAFE_INTEGER, product);
|
|
518
|
+
}
|
|
519
|
+
if (constrained && suffixMinimum[0] > budget + EPSILON) return null;
|
|
520
|
+
const exact = !searchSpaceCapped && searchSpace <= Math.max(1, exactLimit);
|
|
521
|
+
const width = Math.max(1, Math.floor(beamWidth) || 256);
|
|
522
|
+
const search = { method: exact ? "exact" : "beam", exact, searchSpace, searchSpaceCapped, expandedStates: 0, beamPruned: 0 };
|
|
523
|
+
let states = [{ choices: [], routesByTask: /* @__PURE__ */ new Map(), score: 0, cost: 0, switches: 0, relaxedCount: 0, qualityShortfall: 0 }];
|
|
524
|
+
for (let index = 0; index < tasks.length; index++) {
|
|
525
|
+
const task = tasks[index];
|
|
526
|
+
const expanded = [];
|
|
527
|
+
for (const state of states) {
|
|
528
|
+
for (const option of options[index]) {
|
|
529
|
+
const cost = state.cost + option.cost;
|
|
530
|
+
if (constrained && cost + suffixMinimum[index + 1] > budget + EPSILON) continue;
|
|
531
|
+
const switches = (task.dependsOn ?? []).reduce((count, dependency) => {
|
|
532
|
+
const route = state.routesByTask.get(dependency);
|
|
533
|
+
return count + (route !== void 0 && route !== option.route ? 1 : 0);
|
|
534
|
+
}, 0);
|
|
535
|
+
const penalty = switches * handoffPenalty;
|
|
536
|
+
const shortfall = Math.max(0, Number(option.qualityShortfall) || 0);
|
|
537
|
+
const routesByTask2 = new Map(state.routesByTask);
|
|
538
|
+
routesByTask2.set(task.id, option.route);
|
|
539
|
+
expanded.push({
|
|
540
|
+
choices: [...state.choices, { ...option, handoffPenalty: penalty }],
|
|
541
|
+
routesByTask: routesByTask2,
|
|
542
|
+
score: state.score + option.score - penalty,
|
|
543
|
+
cost,
|
|
544
|
+
switches: state.switches + switches,
|
|
545
|
+
relaxedCount: state.relaxedCount + (shortfall > 0 ? 1 : 0),
|
|
546
|
+
qualityShortfall: state.qualityShortfall + shortfall
|
|
547
|
+
});
|
|
548
|
+
search.expandedStates++;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (!expanded.length) return null;
|
|
552
|
+
expanded.sort((left, right) => compareStates(left, right, minimizeCost));
|
|
553
|
+
if (!exact && expanded.length > width) {
|
|
554
|
+
states = expanded.slice(0, width);
|
|
555
|
+
if (constrained && index < tasks.length - 1) {
|
|
556
|
+
const cheapest = expanded.reduce((best2, state) => compareStates(state, best2, true) < 0 ? state : best2);
|
|
557
|
+
if (!states.includes(cheapest)) states[width - 1] = cheapest;
|
|
558
|
+
}
|
|
559
|
+
search.beamPruned += expanded.length - states.length;
|
|
560
|
+
} else states = expanded;
|
|
561
|
+
}
|
|
562
|
+
states.sort((left, right) => compareStates(left, right, minimizeCost));
|
|
563
|
+
const best = states[0];
|
|
564
|
+
const { routesByTask, ...result } = best;
|
|
565
|
+
return { ...result, minimumCostLowerBound: suffixMinimum[0], search };
|
|
482
566
|
}
|
|
483
567
|
|
|
484
568
|
// .dsh-plugin/shared/router.mjs
|
|
@@ -590,9 +674,12 @@ function specialtyMatch(model, taskType, liveScores = {}) {
|
|
|
590
674
|
return 0.38;
|
|
591
675
|
}
|
|
592
676
|
function qualityForTask(row, taskType) {
|
|
593
|
-
const base = asScore(row?.liveScores?.[taskType]) ?? asScore(row?.liveOverall) ?? row?.metadata?.quality ?? row?.quality ?? 0;
|
|
677
|
+
const base = asScore(row?.liveScores?.[taskType]) ?? asScore(row?.liveOverall) ?? row?.metadata?.quality ?? row?.baseQuality ?? row?.quality ?? 0;
|
|
594
678
|
return row?.qualityBias ? clamp(base + row.qualityBias) : base;
|
|
595
679
|
}
|
|
680
|
+
function qualitySourceForTask(row, taskType) {
|
|
681
|
+
return asScore(row?.liveScores?.[taskType]) !== void 0 || asScore(row?.liveOverall) !== void 0 ? "livebench" : row?.fallbackQualitySource ?? row?.qualitySource ?? "unknown";
|
|
682
|
+
}
|
|
596
683
|
function specialtyForTask(row, taskType) {
|
|
597
684
|
return specialtyMatch(row.metadata, taskType, row.liveScores);
|
|
598
685
|
}
|
|
@@ -644,20 +731,7 @@ function normalizedCacheRatios(cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
|
644
731
|
const write = Number.isFinite(Number(cacheWriteRatio)) ? Math.min(clamp(Number(cacheWriteRatio)), 1 - read) : 0;
|
|
645
732
|
return { read, write };
|
|
646
733
|
}
|
|
647
|
-
|
|
648
|
-
const { read, write } = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
|
|
649
|
-
return {
|
|
650
|
-
input: (1 - read - write) * Number(pricing.input) + read * Number(pricing.cacheRead) + write * Number(pricing.cacheWrite),
|
|
651
|
-
output: Number(pricing.output)
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
function costScore(pricing, maxCost, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
655
|
-
if (pricing === null) return 0;
|
|
656
|
-
const effective = effectivePricing(pricing, cacheReadRatio, cacheWriteRatio);
|
|
657
|
-
const mean = (effective.input + effective.output) / 2;
|
|
658
|
-
if (maxCost <= 0) return mean === 0 ? 1 : 0;
|
|
659
|
-
return clamp(1 - mean / maxCost);
|
|
660
|
-
}
|
|
734
|
+
var COST_REFERENCE_PRICING = Object.freeze({ input: 1, output: 5, cacheRead: 1, cacheWrite: 1, currency: "USD" });
|
|
661
735
|
function estimateCost(model, text6, outputTokens = 900, pricingOverrides = {}, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
662
736
|
const pricing = pricingFor(model, pricingOverrides);
|
|
663
737
|
if (pricing === null) return null;
|
|
@@ -898,13 +972,13 @@ function weightsForTask(weights, task) {
|
|
|
898
972
|
if (task.weights) return task.weights;
|
|
899
973
|
return task.purpose === "synthesis" ? SYNTHESIS_WEIGHTS : OBJECTIVE_WEIGHTS[task.difficulty] ?? weights;
|
|
900
974
|
}
|
|
901
|
-
function
|
|
975
|
+
function compareText2(left, right) {
|
|
902
976
|
const a = String(left);
|
|
903
977
|
const b2 = String(right);
|
|
904
978
|
return a < b2 ? -1 : a > b2 ? 1 : 0;
|
|
905
979
|
}
|
|
906
980
|
function compareRowsStable(left, right) {
|
|
907
|
-
return
|
|
981
|
+
return compareText2(routeKey(left.provider, left.model), routeKey(right.provider, right.model));
|
|
908
982
|
}
|
|
909
983
|
function reasoningEffortRank(effort) {
|
|
910
984
|
const normalized2 = String(effort ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
|
|
@@ -925,7 +999,7 @@ function selectReasoningEffort(efforts, preferred = "medium") {
|
|
|
925
999
|
return exact.slice().sort((left, right) => {
|
|
926
1000
|
const distance = Math.abs(reasoningEffortRank(left) - preferredRank) - Math.abs(reasoningEffortRank(right) - preferredRank);
|
|
927
1001
|
if (distance !== 0) return distance;
|
|
928
|
-
return reasoningEffortRank(left) - reasoningEffortRank(right) ||
|
|
1002
|
+
return reasoningEffortRank(left) - reasoningEffortRank(right) || compareText2(left, right);
|
|
929
1003
|
})[0];
|
|
930
1004
|
}
|
|
931
1005
|
function reasoningDecision(row, task) {
|
|
@@ -951,16 +1025,17 @@ function reasoningDecision(row, task) {
|
|
|
951
1025
|
multiplier: reasoningEffortMultiplier(chosen)
|
|
952
1026
|
};
|
|
953
1027
|
}
|
|
954
|
-
function candidateUtility(row, task, weights,
|
|
1028
|
+
function candidateUtility(row, task, weights, cacheReadRatio = 0, cacheWriteRatio = 0, text6 = "", complexity = "balanced") {
|
|
955
1029
|
const quality = qualityForTask(row, task.type);
|
|
1030
|
+
const rawPreference = row.preferenceAdjustments?.[task.type];
|
|
1031
|
+
const preferenceAdjustment = Number.isFinite(rawPreference) ? clamp(rawPreference, -0.1, 0.1) : 0;
|
|
956
1032
|
const floor = Number(task.qualityFloor ?? taskQualityFloor("complex", task));
|
|
957
1033
|
const qualityGap = Math.max(0, floor - quality);
|
|
958
|
-
const duplicatePenalty = 0;
|
|
959
|
-
const synthesisPreference = task.purpose === "synthesis" && /deepseek[- ]?v4[- ]?pro/i.test(row.model) ? 0.025 : 0;
|
|
960
1034
|
const reasoning = reasoningDecision(row, task);
|
|
961
|
-
const
|
|
962
|
-
const
|
|
963
|
-
|
|
1035
|
+
const reference = taskCost({ pricing: COST_REFERENCE_PRICING, reasoningKnown: true, reasoningEfforts: [] }, task, text6, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1036
|
+
const cost = row.pricing === null ? 0 : 1 / (1 + taskCost(row, task, text6, complexity, cacheReadRatio, cacheWriteRatio) / Math.max(reference, 1e-12));
|
|
1037
|
+
const score = weights.quality * quality + weights.cost * cost + weights.latency * (1 - clamp(row.latency * reasoning.multiplier.latency)) + weights.specialty * specialtyForTask(row, task.type) + (weights.reasoning ?? 0) * reasoning.reasoningFit - weights.risk * row.risk - qualityGap * (task.criticality ?? 0.75) + preferenceAdjustment;
|
|
1038
|
+
return { score, floor, qualityGap, preferenceAdjustment, ...reasoning };
|
|
964
1039
|
}
|
|
965
1040
|
function taskCost(row, task, text6, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
966
1041
|
if (row?.pricing === null) return 0;
|
|
@@ -992,96 +1067,65 @@ function dominates(left, right, task, text6, complexity, cacheReadRatio, cacheWr
|
|
|
992
1067
|
const strictlyBetter = leftValues.quality > rightValues.quality || leftValues.cost < rightValues.cost || leftValues.latency < rightValues.latency || leftValues.specialty > rightValues.specialty || leftValues.reasoning > rightValues.reasoning || leftValues.risk < rightValues.risk;
|
|
993
1068
|
return noWorse && strictlyBetter;
|
|
994
1069
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
1070
|
+
function eligibleRowsForTask(rows, task) {
|
|
1071
|
+
return task.type === "vision" ? rows.filter((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image")) : rows;
|
|
1072
|
+
}
|
|
1073
|
+
function candidatePool(rows, task, weights, text6, complexity, cacheReadRatio, cacheWriteRatio, dependencySensitive = false) {
|
|
1074
|
+
const eligibleRows = eligibleRowsForTask(rows, task);
|
|
997
1075
|
const floor = Number(task.qualityFloor ?? 0);
|
|
998
1076
|
const feasible = eligibleRows.filter((row) => qualityForTask(row, task.type) >= floor);
|
|
999
1077
|
const source = feasible.length > 0 ? feasible : eligibleRows.slice().sort((left, right) => qualityForTask(right, task.type) - qualityForTask(left, task.type) || compareRowsStable(left, right)).slice(0, 3);
|
|
1000
1078
|
const taskWeights = weightsForTask(weights, task);
|
|
1001
1079
|
const scored = source.map((row) => ({
|
|
1002
1080
|
row,
|
|
1003
|
-
decision: candidateUtility(row, task, taskWeights,
|
|
1081
|
+
decision: candidateUtility(row, task, taskWeights, cacheReadRatio, cacheWriteRatio, text6, complexity),
|
|
1004
1082
|
cost: taskCost(row, task, text6, complexity, cacheReadRatio, cacheWriteRatio)
|
|
1005
1083
|
}));
|
|
1006
|
-
const frontier = scored.filter((item) => !
|
|
1084
|
+
const frontier = dependencySensitive ? scored : scored.filter((item) => !scored.some((other) => other !== item && other.decision.score >= item.decision.score && dominates(other.row, item.row, task, text6, complexity, cacheReadRatio, cacheWriteRatio)));
|
|
1007
1085
|
const essential = [
|
|
1008
|
-
scored.
|
|
1086
|
+
scored.filter((item) => item.row.pricing !== null).sort((left, right) => left.cost - right.cost || compareRowsStable(left.row, right.row))[0],
|
|
1009
1087
|
scored.slice().sort((left, right) => right.decision.score - left.decision.score || compareRowsStable(left.row, right.row))[0],
|
|
1010
1088
|
scored.slice().sort((left, right) => qualityForTask(right.row, task.type) - qualityForTask(left.row, task.type) || compareRowsStable(left.row, right.row))[0]
|
|
1011
1089
|
].filter(Boolean);
|
|
1012
|
-
const
|
|
1090
|
+
const all = [...frontier, ...essential].filter((item, index, all2) => all2.findIndex((candidate) => candidate.row === item.row) === index).sort((left, right) => right.decision.score - left.decision.score || left.cost - right.cost || compareRowsStable(left.row, right.row));
|
|
1091
|
+
const anchors = [...new Set(essential)];
|
|
1092
|
+
const ordered = [...anchors, ...all.filter((item) => !anchors.includes(item))].slice(0, ROUTING_CANDIDATE_LIMIT).sort((left, right) => right.decision.score - left.decision.score || left.cost - right.cost || compareRowsStable(left.row, right.row));
|
|
1013
1093
|
return {
|
|
1014
1094
|
options: ordered,
|
|
1015
1095
|
relaxed: feasible.length === 0,
|
|
1016
|
-
pruned: Math.max(0,
|
|
1096
|
+
pruned: Math.max(0, scored.length - all.length),
|
|
1097
|
+
filtered: Math.max(0, eligibleRows.length - source.length),
|
|
1098
|
+
truncated: Math.max(0, all.length - ordered.length),
|
|
1099
|
+
dependencySensitive
|
|
1017
1100
|
};
|
|
1018
1101
|
}
|
|
1019
|
-
function
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
if (
|
|
1031
|
-
const suffixMinimum = Array(tasks.length + 1).fill(0);
|
|
1032
|
-
for (let index = tasks.length - 1; index >= 0; index -= 1) {
|
|
1033
|
-
const costOptions = Number.isFinite(budget) ? pools[index].options.filter((option) => option.row.pricing !== null) : pools[index].options;
|
|
1034
|
-
if (costOptions.length === 0) return null;
|
|
1035
|
-
suffixMinimum[index] = suffixMinimum[index + 1] + Math.min(...costOptions.map((option) => option.cost));
|
|
1036
|
-
}
|
|
1037
|
-
if (Number.isFinite(budget) && suffixMinimum[0] > budget + 1e-12) return null;
|
|
1038
|
-
let states = [{ assignments: [], routesByTask: /* @__PURE__ */ new Map(), usedRoutes: /* @__PURE__ */ new Set(), score: 0, cost: 0, switches: 0, relaxedCount: 0, qualityShortfall: 0 }];
|
|
1039
|
-
for (let index = 0; index < tasks.length; index += 1) {
|
|
1040
|
-
const task = tasks[index];
|
|
1041
|
-
const pool = pools[index];
|
|
1042
|
-
const expanded = [];
|
|
1043
|
-
for (const state of states) {
|
|
1044
|
-
for (const option of pool.options) {
|
|
1045
|
-
if (Number.isFinite(budget) && option.row.pricing === null) continue;
|
|
1046
|
-
const nextCost = state.cost + option.cost;
|
|
1047
|
-
if (Number.isFinite(budget) && nextCost + suffixMinimum[index + 1] > budget + 1e-12) continue;
|
|
1048
|
-
const taskWeights = weightsForTask(weights, task);
|
|
1049
|
-
const decision = candidateUtility(option.row, task, taskWeights, maxCost, state.usedRoutes, cacheReadRatio, cacheWriteRatio);
|
|
1050
|
-
const route = routeKey(option.row.provider, option.row.model);
|
|
1051
|
-
const dependencySwitches = (task.dependsOn ?? []).reduce((count, dependency) => {
|
|
1052
|
-
const dependencyRoute = state.routesByTask.get(dependency);
|
|
1053
|
-
return count + (dependencyRoute !== void 0 && dependencyRoute !== route ? 1 : 0);
|
|
1054
|
-
}, 0);
|
|
1055
|
-
const handoffPenalty = dependencySwitches * 0.015;
|
|
1056
|
-
const qualityShortfall = Math.max(0, decision.floor - qualityForTask(option.row, task.type));
|
|
1057
|
-
const usedRoutes = new Set(state.usedRoutes);
|
|
1058
|
-
usedRoutes.add(route);
|
|
1059
|
-
const routesByTask = new Map(state.routesByTask);
|
|
1060
|
-
routesByTask.set(task.id, route);
|
|
1061
|
-
expanded.push({
|
|
1062
|
-
assignments: [...state.assignments, { task, row: option.row, decision: { ...decision, relaxed: qualityShortfall > 0 }, estimatedCost: option.cost, handoffPenalty }],
|
|
1063
|
-
routesByTask,
|
|
1064
|
-
usedRoutes,
|
|
1065
|
-
score: state.score + decision.score - handoffPenalty,
|
|
1066
|
-
cost: nextCost,
|
|
1067
|
-
switches: state.switches + dependencySwitches,
|
|
1068
|
-
relaxedCount: state.relaxedCount + (qualityShortfall > 0 ? 1 : 0),
|
|
1069
|
-
qualityShortfall: state.qualityShortfall + qualityShortfall
|
|
1070
|
-
});
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
if (expanded.length === 0) return null;
|
|
1074
|
-
expanded.sort(minimizeCost ? compareCostStates : compareUtilityStates);
|
|
1075
|
-
states = expanded.slice(0, ROUTING_BEAM_WIDTH);
|
|
1076
|
-
}
|
|
1077
|
-
states.sort(minimizeCost ? compareCostStates : compareUtilityStates);
|
|
1102
|
+
function solveAssignments({ rows, tasks, weights, text: text6, complexity, budget, cacheReadRatio, cacheWriteRatio, minimizeCost = false }) {
|
|
1103
|
+
const dependencySensitive = tasks.some((task) => (task.dependsOn ?? []).length > 0);
|
|
1104
|
+
const pools = tasks.map((task) => candidatePool(rows, task, weights, text6, complexity, cacheReadRatio, cacheWriteRatio, dependencySensitive));
|
|
1105
|
+
const result = solveCandidateAssignments({ tasks, pools: pools.map((pool, index) => pool.options.map((option) => ({
|
|
1106
|
+
route: routeKey(option.row.provider, option.row.model),
|
|
1107
|
+
score: option.decision.score,
|
|
1108
|
+
cost: option.cost,
|
|
1109
|
+
qualityShortfall: Math.max(0, option.decision.floor - qualityForTask(option.row, tasks[index].type)),
|
|
1110
|
+
pricingKnown: option.row.pricing !== null,
|
|
1111
|
+
payload: option
|
|
1112
|
+
}))), budget, beamWidth: ROUTING_BEAM_WIDTH, minimizeCost });
|
|
1113
|
+
if (!result) return null;
|
|
1078
1114
|
return {
|
|
1079
|
-
...
|
|
1115
|
+
...result,
|
|
1116
|
+
assignments: result.choices.map((choice, index) => ({
|
|
1117
|
+
task: tasks[index],
|
|
1118
|
+
row: choice.payload.row,
|
|
1119
|
+
decision: { ...choice.payload.decision, relaxed: choice.qualityShortfall > 0 },
|
|
1120
|
+
estimatedCost: choice.cost,
|
|
1121
|
+
handoffPenalty: choice.handoffPenalty
|
|
1122
|
+
})),
|
|
1123
|
+
usedRoutes: new Set(result.choices.map((choice) => choice.route)),
|
|
1080
1124
|
candidatePools: pools,
|
|
1081
|
-
minimumFeasibleCost:
|
|
1125
|
+
minimumFeasibleCost: result.minimumCostLowerBound
|
|
1082
1126
|
};
|
|
1083
1127
|
}
|
|
1084
|
-
function buildPlan({ text: text6 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0, preset = DEFAULT_ROUTING_PRESET } = {}) {
|
|
1128
|
+
function buildPlan({ text: text6 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", dataVersions = null, learning = null, budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0, preset = DEFAULT_ROUTING_PRESET } = {}) {
|
|
1085
1129
|
const presetId = normalizeRoutingPreset(preset);
|
|
1086
1130
|
const firstLine = String(text6 ?? "").split(/\r?\n/u)[0].trim();
|
|
1087
1131
|
const transformOnly = /^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(firstLine) && !/(?:执行|完成|实施|分配)/u.test(firstLine);
|
|
@@ -1097,17 +1141,21 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1097
1141
|
return {
|
|
1098
1142
|
provider: String(entry.provider ?? ""),
|
|
1099
1143
|
model: String(entry.model ?? ""),
|
|
1144
|
+
benchmarkModel: typeof entry.benchmarkModel === "string" ? entry.benchmarkModel : void 0,
|
|
1100
1145
|
reasoningEfforts: [...new Set(reasoningEfforts)],
|
|
1101
1146
|
defaultReasoningEffort: entry.defaultReasoningEffort === void 0 ? void 0 : String(entry.defaultReasoningEffort),
|
|
1102
1147
|
reasoningKnown: entry.reasoningKnown === true || entry.reasoningKnown === void 0 && Array.isArray(entry.reasoningEfforts),
|
|
1103
1148
|
quality: asScore(entry.quality),
|
|
1104
1149
|
qualityBias: Number.isFinite(entry.qualityBias) ? clamp(entry.qualityBias, -0.05, 0.05) : 0,
|
|
1150
|
+
preferenceAdjustments: entry.preferenceAdjustments ?? null,
|
|
1105
1151
|
qualitySource: entry.qualitySource === "user" ? "user" : "route",
|
|
1106
1152
|
latency: asScore(entry.latency),
|
|
1107
1153
|
risk: asScore(entry.risk),
|
|
1108
1154
|
specialties: Array.isArray(entry.specialties) ? entry.specialties.filter((item) => typeof item === "string") : null,
|
|
1109
1155
|
pricing: normalizePricing({ route: entry.pricing ?? entry.price }).route ?? null,
|
|
1110
|
-
pricingSource: entry.pricingSource === "user" ? "user" : "route",
|
|
1156
|
+
pricingSource: entry.pricingSource === "user" ? "user" : entry.pricingSource === "dynamic" ? "dynamic" : "route",
|
|
1157
|
+
pricingVersion: entry.pricingVersion ?? null,
|
|
1158
|
+
snapshotAsOf: entry.snapshotAsOf ?? null,
|
|
1111
1159
|
inputModalities: Array.isArray(entry.inputModalities) ? entry.inputModalities.map((item) => String(item).toLowerCase()) : []
|
|
1112
1160
|
};
|
|
1113
1161
|
}) : [];
|
|
@@ -1123,10 +1171,12 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1123
1171
|
...route.risk === void 0 ? {} : { risk: route.risk },
|
|
1124
1172
|
...route.specialties === null ? {} : { specialties: route.specialties }
|
|
1125
1173
|
};
|
|
1126
|
-
const live = liveBenchRow(liveBench, route.model);
|
|
1174
|
+
const live = liveBenchRow(liveBench, route.benchmarkModel ?? route.model);
|
|
1127
1175
|
const liveScores = live?.scores ?? {};
|
|
1128
|
-
const liveOverall = asScore(live?.overall);
|
|
1129
|
-
const
|
|
1176
|
+
const liveOverall = live?.overallSource === "explicit" || live?.overallSource === void 0 && Object.keys(liveScores).length === 0 ? asScore(live?.overall) : void 0;
|
|
1177
|
+
const baseQuality = asScore(metadata.quality) ?? 0;
|
|
1178
|
+
const quality = clamp((asScore(liveScores?.[taskType]) ?? liveOverall ?? baseQuality) + route.qualityBias);
|
|
1179
|
+
const fallbackQualitySource = route.quality !== void 0 ? route.qualitySource : catalog ? "catalog-heuristic" : "unknown";
|
|
1130
1180
|
const qualitySource = liveOverall !== void 0 || asScore(liveScores?.[taskType]) !== void 0 ? "livebench" : route.quality !== void 0 ? route.qualitySource : catalog ? "catalog-heuristic" : "unknown";
|
|
1131
1181
|
const userPrice = normalizedPrices[normalize(`${route.provider}/${route.model}`)] ?? normalizedPrices[normalize(route.model)];
|
|
1132
1182
|
const pricingRow = userPrice ?? route.pricing ?? null;
|
|
@@ -1137,9 +1187,14 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1137
1187
|
model: route.model,
|
|
1138
1188
|
metadata,
|
|
1139
1189
|
quality,
|
|
1190
|
+
baseQuality,
|
|
1191
|
+
fallbackQualitySource,
|
|
1140
1192
|
qualityBias: route.qualityBias,
|
|
1193
|
+
preferenceAdjustments: route.preferenceAdjustments,
|
|
1141
1194
|
qualitySource,
|
|
1142
1195
|
pricingSource,
|
|
1196
|
+
pricingVersion: route.pricingVersion,
|
|
1197
|
+
snapshotAsOf: route.snapshotAsOf,
|
|
1143
1198
|
liveScores,
|
|
1144
1199
|
liveOverall,
|
|
1145
1200
|
latency: metadata.latency ?? 0.5,
|
|
@@ -1160,10 +1215,6 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1160
1215
|
}, text6, 900, {}, cacheReadRatio, cacheWriteRatio)
|
|
1161
1216
|
});
|
|
1162
1217
|
}
|
|
1163
|
-
const maxCost = Math.max(1, ...rows.filter((row) => row.pricing !== null).map((row) => {
|
|
1164
|
-
const effective = effectivePricing(row.pricing, cacheReadRatio, cacheWriteRatio);
|
|
1165
|
-
return effective.input + effective.output;
|
|
1166
|
-
}));
|
|
1167
1218
|
const taskNodes = taskPackages(taskType, text6, complexity.band).map((task) => presetId === DEFAULT_ROUTING_PRESET ? task : {
|
|
1168
1219
|
...task,
|
|
1169
1220
|
qualityFloor: presetFloor(task.qualityFloor, presetId),
|
|
@@ -1175,7 +1226,6 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1175
1226
|
rows,
|
|
1176
1227
|
tasks: taskNodes,
|
|
1177
1228
|
weights,
|
|
1178
|
-
maxCost,
|
|
1179
1229
|
text: text6,
|
|
1180
1230
|
complexity: complexity.band,
|
|
1181
1231
|
budget: Number.POSITIVE_INFINITY,
|
|
@@ -1186,7 +1236,6 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1186
1236
|
rows,
|
|
1187
1237
|
tasks: taskNodes,
|
|
1188
1238
|
weights,
|
|
1189
|
-
maxCost,
|
|
1190
1239
|
text: text6,
|
|
1191
1240
|
complexity: complexity.band,
|
|
1192
1241
|
budget,
|
|
@@ -1197,7 +1246,6 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1197
1246
|
rows,
|
|
1198
1247
|
tasks: taskNodes,
|
|
1199
1248
|
weights,
|
|
1200
|
-
maxCost,
|
|
1201
1249
|
text: text6,
|
|
1202
1250
|
complexity: complexity.band,
|
|
1203
1251
|
budget: Number.POSITIVE_INFINITY,
|
|
@@ -1210,7 +1258,8 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1210
1258
|
const usedRoutes = optimized?.usedRoutes ?? /* @__PURE__ */ new Set();
|
|
1211
1259
|
const constraintRelaxed = (optimized?.relaxedCount ?? 0) > 0;
|
|
1212
1260
|
for (const row of rows) {
|
|
1213
|
-
row.score = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band] }, weights,
|
|
1261
|
+
row.score = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band] }, weights, cacheReadRatio, cacheWriteRatio, text6, complexity.band).score;
|
|
1262
|
+
if (row.pricing !== null && taskNodes[0]) row.estimatedCost = taskCost(row, taskNodes[0], text6, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1214
1263
|
}
|
|
1215
1264
|
rows.sort((left, right) => right.score - left.score || compareRowsStable(left, right));
|
|
1216
1265
|
const selectedAssignment = assignments[0];
|
|
@@ -1225,7 +1274,7 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1225
1274
|
difficulty: task.difficulty,
|
|
1226
1275
|
recommended: row?.model ?? "\u5F85\u53D1\u73B0\u6A21\u578B",
|
|
1227
1276
|
recommendedProvider: row?.provider ?? "",
|
|
1228
|
-
qualitySource: row
|
|
1277
|
+
qualitySource: qualitySourceForTask(row, task.type),
|
|
1229
1278
|
pricingSource: row?.pricingSource ?? "unknown",
|
|
1230
1279
|
recommendedReasoningEffort: decision?.reasoningEffort,
|
|
1231
1280
|
preferredReasoningEffort: decision?.preferredReasoningEffort ?? task.preferredReasoningEffort,
|
|
@@ -1253,25 +1302,25 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1253
1302
|
cacheWriteTokens: tokens.cacheWriteTokens,
|
|
1254
1303
|
outputTokens: tokens.outputTokens,
|
|
1255
1304
|
estimatedCost: row?.pricing === null || row === null ? null : Number(taskEstimate.toFixed(6)),
|
|
1256
|
-
quality: row
|
|
1257
|
-
qualitySource: row
|
|
1305
|
+
quality: qualitySourceForTask(row, task.type) === "unknown" || row === null ? null : Number(qualityForTask(row, task.type).toFixed(3)),
|
|
1306
|
+
qualitySource: qualitySourceForTask(row, task.type),
|
|
1258
1307
|
pricingSource: row?.pricingSource ?? "unknown",
|
|
1259
1308
|
handoffPenalty: Number(Number(handoffPenalty ?? 0).toFixed(3))
|
|
1260
1309
|
};
|
|
1261
1310
|
});
|
|
1262
1311
|
const pricingComplete = assignments.length > 0 && assignments.every(({ row }) => row?.pricing !== null);
|
|
1263
|
-
const totalEstimate = pricingComplete ?
|
|
1312
|
+
const totalEstimate = pricingComplete ? assignments.reduce((sum, { task, row, estimatedCost }) => sum + (estimatedCost ?? taskCost(row, task, text6, complexity.band, cacheReadRatio, cacheWriteRatio)), 0) : null;
|
|
1264
1313
|
const baselineRows = assignments.map(({ task }) => {
|
|
1265
|
-
const strongest = rows.reduce((best, row) => qualityForTask(row, task.type) > (best === null ? -1 : qualityForTask(best, task.type)) ? row : best, null);
|
|
1314
|
+
const strongest = eligibleRowsForTask(rows, task).reduce((best, row) => qualityForTask(row, task.type) > (best === null ? -1 : qualityForTask(best, task.type)) ? row : best, null);
|
|
1266
1315
|
return { task, strongest };
|
|
1267
1316
|
});
|
|
1268
1317
|
const baselineCost = baselineRows.every((item) => item.strongest?.pricing !== null && item.strongest !== null) ? baselineRows.reduce((sum, { task, strongest }) => sum + taskCost(strongest, task, text6, complexity.band, cacheReadRatio, cacheWriteRatio), 0) : null;
|
|
1269
|
-
const qualityEvidenceComplete = assignments.length > 0 && assignments.every(({ row }) => ["livebench", "route", "user"].includes(row
|
|
1318
|
+
const qualityEvidenceComplete = assignments.length > 0 && assignments.every(({ row, task }) => ["livebench", "route", "user"].includes(qualitySourceForTask(row, task.type))) && baselineRows.every(({ strongest, task }) => ["livebench", "route", "user"].includes(qualitySourceForTask(strongest, task.type)));
|
|
1270
1319
|
const budgetExceeded = Number(budgetUsd) > 0 && totalEstimate !== null ? totalEstimate > Number(budgetUsd) : null;
|
|
1271
1320
|
const savings = baselineCost === null || totalEstimate === null || !qualityEvidenceComplete ? null : baselineCost <= 0 ? 0 : clamp((baselineCost - totalEstimate) / baselineCost);
|
|
1272
1321
|
const paretoPruned = (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.pruned, 0);
|
|
1273
1322
|
const minimumFeasibleCost = rows.every((row) => row.pricing !== null) ? optimized?.minimumFeasibleCost ?? minimumCostPlan?.cost ?? 0 : null;
|
|
1274
|
-
const reason = selected === null ? unassignableTasks.length > 0 ? `\u56FE\u50CF\u5DE5\u4F5C\u5305 ${unassignableTasks.join("\u3001")} \u6CA1\u6709\u53EF\u7528\u7684\u56FE\u50CF\u6A21\u578B\uFF0C\u65E0\u6CD5\u5F62\u6210\u5B8C\u6574\u5206\u914D\u8BA1\u5212\u3002` : "\u5C1A\u672A\u53D1\u73B0\u53EF\u7528\u6A21\u578B\uFF0C\u4FDD\u7559 Harness \u539F\u59CB\u6A21\u578B\u9009\u62E9\u3002" : `${complexity.band === "simple" ? "\u4F4E\u590D\u6742\u5EA6\u4F18\u5148\u6210\u672C\u3001\u54CD\u5E94\u901F\u5EA6\u4E0E\u8F83\u4F4E\u63A8\u7406\u5F00\u9500" : complexity.band === "balanced" ? "\u5728\u8D28\u91CF\u3001\u6210\u672C\u3001\u63A8\u7406\u7B49\u7EA7\u3001\u5EF6\u8FDF\u4E0E\u98CE\u9669\u4E4B\u95F4\u5E73\u8861" : "\u9AD8\u590D\u6742\u5EA6\u6267\u884C\u5305\u542B\u63A8\u7406\u7B49\u7EA7\u7684\u4F9D\u8D56\u611F\u77E5\
|
|
1323
|
+
const reason = selected === null ? unassignableTasks.length > 0 ? `\u56FE\u50CF\u5DE5\u4F5C\u5305 ${unassignableTasks.join("\u3001")} \u6CA1\u6709\u53EF\u7528\u7684\u56FE\u50CF\u6A21\u578B\uFF0C\u65E0\u6CD5\u5F62\u6210\u5B8C\u6574\u5206\u914D\u8BA1\u5212\u3002` : "\u5C1A\u672A\u53D1\u73B0\u53EF\u7528\u6A21\u578B\uFF0C\u4FDD\u7559 Harness \u539F\u59CB\u6A21\u578B\u9009\u62E9\u3002" : `${complexity.band === "simple" ? "\u4F4E\u590D\u6742\u5EA6\u4F18\u5148\u6210\u672C\u3001\u54CD\u5E94\u901F\u5EA6\u4E0E\u8F83\u4F4E\u63A8\u7406\u5F00\u9500" : complexity.band === "balanced" ? "\u5728\u8D28\u91CF\u3001\u6210\u672C\u3001\u63A8\u7406\u7B49\u7EA7\u3001\u5EF6\u8FDF\u4E0E\u98CE\u9669\u4E4B\u95F4\u5E73\u8861" : "\u9AD8\u590D\u6742\u5EA6\u6267\u884C\u5305\u542B\u63A8\u7406\u7B49\u7EA7\u7684\u4F9D\u8D56\u611F\u77E5\u7EA6\u675F\u5206\u914D"}\uFF1B\u4EFB\u52A1\u7C7B\u578B\u4E3A ${taskType}\uFF0C${String(subtasks.length)} \u4E2A\u5DE5\u4F5C\u5305\u91C7\u7528${optimized?.search?.exact ? "\u4FDD\u7559\u5019\u9009\u7A7A\u95F4\u5185\u7684\u7CBE\u786E\u641C\u7D22" : "\u4FDD\u7559\u5019\u9009\u7A7A\u95F4\u5185\u7684\u6709\u754C\u8FD1\u4F3C\u641C\u7D22"}\u3002\u8D28\u91CF\u5206\u4E0E\u95E8\u69DB\u662F\u672A\u6821\u51C6\u7684\u4F30\u8BA1\uFF0C\u4E0D\u662F\u7B54\u5BF9\u6982\u7387\u3002`;
|
|
1275
1324
|
return {
|
|
1276
1325
|
mode,
|
|
1277
1326
|
preset: presetId,
|
|
@@ -1282,16 +1331,39 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1282
1331
|
taskTypes: [...new Set(taskNodes.map((task) => task.type).filter((type) => type !== "reasoning"))],
|
|
1283
1332
|
objectiveWeights: weights,
|
|
1284
1333
|
candidates: rows.slice(0, 8).map((row) => {
|
|
1285
|
-
const decision = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band], preferredReasoningEffort: complexity.band === "simple" ? "low" : "medium" }, weights,
|
|
1286
|
-
return { provider: row.provider, model: row.model, score: Number(row.score.toFixed(3)), 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 };
|
|
1334
|
+
const decision = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band], preferredReasoningEffort: complexity.band === "simple" ? "low" : "medium" }, weights, cacheReadRatio, cacheWriteRatio, text6, complexity.band);
|
|
1335
|
+
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 };
|
|
1287
1336
|
}),
|
|
1288
|
-
selected: selected === null ? null : { provider: selected.provider, model: selected.model, reasoningEffort: selectedAssignment?.decision?.reasoningEffort, estimatedCost: selected.estimatedCost === null ? null : Number(selected.estimatedCost.toFixed(6)), qualitySource: selected.
|
|
1337
|
+
selected: selected === null ? null : { provider: selected.provider, model: selected.model, reasoningEffort: selectedAssignment?.decision?.reasoningEffort, estimatedCost: selected.estimatedCost === null ? null : Number(selected.estimatedCost.toFixed(6)), qualitySource: qualitySourceForTask(selected, selectedAssignment?.task.type ?? taskType), pricingSource: selected.pricingSource },
|
|
1289
1338
|
subtasks,
|
|
1290
1339
|
synthesizer: synthesizer == null ? null : { provider: synthesizer.provider, model: synthesizer.model, reasoningEffort: synthesizerAssignment?.decision?.reasoningEffort },
|
|
1291
|
-
|
|
1340
|
+
// Preserve precision for downstream budget gates; formatting belongs to UI.
|
|
1341
|
+
estimatedCost: totalEstimate,
|
|
1292
1342
|
costBreakdown,
|
|
1293
1343
|
optimization: {
|
|
1294
|
-
|
|
1344
|
+
dataVersions,
|
|
1345
|
+
personalization: learning ? {
|
|
1346
|
+
policyVersion: learning.policyVersion,
|
|
1347
|
+
revision: learning.revision,
|
|
1348
|
+
enabled: learning.enabled,
|
|
1349
|
+
scope: learning.scope,
|
|
1350
|
+
window: learning.window,
|
|
1351
|
+
feedbackCount: learning.feedbackCount,
|
|
1352
|
+
effectiveWeight: learning.effectiveWeight,
|
|
1353
|
+
halfLifeDays: learning.halfLifeDays,
|
|
1354
|
+
priorWeight: learning.priorWeight,
|
|
1355
|
+
maxAdjustment: learning.maxAdjustment,
|
|
1356
|
+
resetAt: learning.resetAt,
|
|
1357
|
+
semantics: "subjective-utility-not-objective-quality"
|
|
1358
|
+
} : null,
|
|
1359
|
+
solver: "dependency-safe quality-constrained exact/beam assignment",
|
|
1360
|
+
qualitySemantics: "uncalibrated-surrogate",
|
|
1361
|
+
costUtility: { method: "1/(1+estimated-task-cost/reference-task-cost)", referencePricing: COST_REFERENCE_PRICING },
|
|
1362
|
+
search: optimized?.search ?? null,
|
|
1363
|
+
optimalityScope: "retained-candidates-and-surrogate-objective",
|
|
1364
|
+
candidateTruncated: (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.truncated, 0),
|
|
1365
|
+
qualityFiltered: (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.filtered, 0),
|
|
1366
|
+
localParetoDisabled: (optimized?.candidatePools ?? []).some((pool) => pool.dependencySensitive),
|
|
1295
1367
|
qualityFloor: QUALITY_FLOORS[complexity.band],
|
|
1296
1368
|
budgetUsd: Number(Number(budgetUsd) > 0 ? Number(budgetUsd) : 0),
|
|
1297
1369
|
cacheReadRatio: normalizedCacheRatios(cacheReadRatio, cacheWriteRatio).read,
|
|
@@ -1308,7 +1380,7 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1308
1380
|
beamWidth: ROUTING_BEAM_WIDTH,
|
|
1309
1381
|
budgetFeasible: budget <= 0 ? pricingComplete ? true : null : budgetPlan !== null,
|
|
1310
1382
|
minimumFeasibleCost: minimumFeasibleCost === null ? null : Number(Number(minimumFeasibleCost).toFixed(6)),
|
|
1311
|
-
liveBench: liveBench?.fetchedAt ? { source: liveBench.source ?? "livebench", fetchedAt: liveBench.fetchedAt, models: Object.keys(liveBench.models ?? {}).length, stale: String(liveBenchError).length > 0, error: String(liveBenchError || "") } : { source: "experimental-baseline", fetchedAt: null, models: 0, stale: false, error: String(liveBenchError || "") }
|
|
1383
|
+
liveBench: liveBench?.fetchedAt ?? liveBench?.verifiedAt ? { source: liveBench.source ?? "livebench", fetchedAt: liveBench.fetchedAt ?? liveBench.verifiedAt, verifiedAt: liveBench.verifiedAt ?? liveBench.fetchedAt, publishedAt: liveBench.publishedAt ?? null, version: liveBench.version ?? null, models: Object.keys(liveBench.models ?? {}).length, stale: String(liveBenchError).length > 0, error: String(liveBenchError || "") } : { source: "experimental-baseline", fetchedAt: null, models: 0, stale: false, error: String(liveBenchError || "") }
|
|
1312
1384
|
},
|
|
1313
1385
|
reason,
|
|
1314
1386
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1379,6 +1451,9 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
1379
1451
|
runnableToolIds = [],
|
|
1380
1452
|
pricing = {},
|
|
1381
1453
|
liveBench = null,
|
|
1454
|
+
liveBenchError = "",
|
|
1455
|
+
dataVersions = null,
|
|
1456
|
+
learning = null,
|
|
1382
1457
|
cacheReadRatio = 0,
|
|
1383
1458
|
cacheWriteRatio = 0,
|
|
1384
1459
|
directProvider = "",
|
|
@@ -1417,6 +1492,9 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
1417
1492
|
budgetUsd: Math.max(0, Number.isFinite(budgetUsd) ? budgetUsd : 0),
|
|
1418
1493
|
pricing,
|
|
1419
1494
|
liveBench,
|
|
1495
|
+
liveBenchError,
|
|
1496
|
+
dataVersions,
|
|
1497
|
+
learning,
|
|
1420
1498
|
cacheReadRatio,
|
|
1421
1499
|
cacheWriteRatio,
|
|
1422
1500
|
preset
|
|
@@ -1433,7 +1511,7 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
1433
1511
|
...selectedChannel ? annotate(selectedChannel) : {},
|
|
1434
1512
|
availabilityNotice: "\u6A21\u578B\u76EE\u5F55\u5217\u51FA\u7684\u8DEF\u7EBF\u5C1A\u672A\u9A8C\u8BC1\u5F53\u524D\u51ED\u636E\u548C\u7F51\u7EDC\uFF1B\u5B9E\u9645\u53EF\u7528\u6027\u4EE5\u5B98\u65B9\u9002\u914D\u5668\u8C03\u7528\u7ED3\u679C\u4E3A\u51C6\u3002",
|
|
1435
1513
|
pricingNotice: plan.estimatedCost === null ? "\u90E8\u5206\u8DEF\u7EBF\u5C1A\u672A\u914D\u7F6E\u8BE5\u4F9B\u5E94\u5546\u7684\u7F8E\u5143\u8F93\u5165/\u8F93\u51FA\u5355\u4EF7\uFF0C\u65E0\u6CD5\u8BA1\u7B97\u53EF\u9760\u7684\u603B\u8D39\u7528\u4E0E\u8282\u7701\u6BD4\u4F8B\uFF1B\u8BF7\u5728\u6A21\u578B\u4EF7\u683C\u8BBE\u7F6E\u4E2D\u8865\u9F50\u3002" : "\u8D39\u7528\u6309\u5DF2\u63D0\u4F9B\u7684\u7F8E\u5143\u5355\u4EF7\u548C\u4F30\u8BA1 token \u6570\u8BA1\u7B97\uFF0C\u4E0D\u662F\u4F9B\u5E94\u5546\u8D26\u5355\uFF0C\u4E5F\u4E0D\u662F\u786C\u6027\u652F\u51FA\u4E0A\u9650\u3002",
|
|
1436
|
-
qualityNotice: plan.optimization.qualityEvidenceComplete ? "\u6A21\u578B\u8D28\u91CF\u4F7F\u7528\u5DF2\u63D0\u4F9B\u8BC4\u5206\u6216\u57FA\u51C6\u6570\u636E\u4F30\u8BA1\uFF0C\
|
|
1514
|
+
qualityNotice: plan.optimization.qualityEvidenceComplete ? "\u6A21\u578B\u8D28\u91CF\u4F7F\u7528\u5DF2\u63D0\u4F9B\u8BC4\u5206\u6216\u57FA\u51C6\u6570\u636E\u4F30\u8BA1\uFF1B\u5206\u6570\u4E0E\u95E8\u69DB\u4E0D\u662F\u7B54\u5BF9\u6982\u7387\uFF0C\u4E5F\u4E0D\u4FDD\u8BC1\u5B9E\u9645\u8D28\u91CF\uFF0C\u4ECD\u9700\u72EC\u7ACB\u4EFB\u52A1\u9A8C\u8BC1\u3002" : "\u90E8\u5206\u6A21\u578B\u8D28\u91CF\u7F3A\u5C11\u53EF\u6838\u9A8C\u8BC4\u5206\uFF1B\u76EE\u5F55\u542F\u53D1\u5F0F\u53EA\u4F9B\u9009\u62E9\u53C2\u8003\uFF0C\u8D28\u91CF\u95E8\u69DB\u548C\u8282\u7701\u6BD4\u4F8B\u65E0\u6CD5\u4FDD\u8BC1\u3002",
|
|
1437
1515
|
modalityNotice: needsImage ? plan.unassignableTasks.length > 0 ? "\u56FE\u50CF\u5DE5\u4F5C\u5305\u6CA1\u6709\u53EF\u786E\u8BA4\u652F\u6301\u56FE\u50CF\u8F93\u5165\u7684\u8DEF\u7EBF\uFF0C\u5F53\u524D\u8BA1\u5212\u65E0\u6CD5\u5B8C\u6574\u5206\u914D\uFF1B\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u914D\u7F6E\u652F\u6301\u56FE\u50CF\u7684\u6A21\u578B\u3002" : routes.some((route) => !Array.isArray(route.inputModalities) || route.inputModalities.length === 0) ? "\u56FE\u50CF\u5DE5\u4F5C\u5305\u53EA\u5206\u7ED9\u5DF2\u58F0\u660E\u56FE\u50CF\u80FD\u529B\u6216\u672A\u58F0\u660E\u8F93\u5165\u80FD\u529B\u7684\u6A21\u578B\uFF1B\u672A\u58F0\u660E\u80FD\u529B\u7684\u6A21\u578B\u4ECD\u9700\u5B9E\u9645\u9A8C\u8BC1\u3002\u5176\u4ED6\u6587\u672C\u5DE5\u4F5C\u5305\u53EF\u7EE7\u7EED\u4F7F\u7528\u7ECF\u6D4E\u578B\u6587\u672C\u6A21\u578B\u3002" : "\u56FE\u50CF\u5DE5\u4F5C\u5305\u53EA\u5206\u7ED9\u660E\u786E\u652F\u6301\u56FE\u50CF\u8F93\u5165\u7684\u6A21\u578B\uFF1B\u5176\u4ED6\u6587\u672C\u5DE5\u4F5C\u5305\u53EF\u7EE7\u7EED\u4F7F\u7528\u7ECF\u6D4E\u578B\u6587\u672C\u6A21\u578B\u3002" : null,
|
|
1438
1516
|
toolNotice: "\u6267\u884C\u6E20\u9053\u6309\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868\u548C\u5DF2\u6838\u9A8C\u9002\u914D\u5668\u6807\u6CE8\uFF1Aofficial-cli \u8868\u793A\u8BE5\u5382\u5546\u5B98\u65B9 CLI \u5DF2\u5B89\u88C5\u4E14\u53EF\u6258\u7BA1\u6267\u884C\uFF1Bharness-llm \u8868\u793A\u901A\u8FC7\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u8C03\u7528\u3002\u53EF\u5728\u5DE5\u4F5C\u53F0\u67E5\u770B\u5B89\u88C5\u4E0E\u6267\u884C\u652F\u6301\u72B6\u6001\u3002",
|
|
1439
1517
|
team: {
|
|
@@ -1464,6 +1542,24 @@ function createPlanFromRoutes(task, availableRoutes, {
|
|
|
1464
1542
|
// .dsh-plugin/shared/run-ledger.mjs
|
|
1465
1543
|
var finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
1466
1544
|
var routeKey2 = (provider, model) => `${String(provider ?? "")}\0${String(model ?? "")}`;
|
|
1545
|
+
var MAX_SPENDING_DAYS = 90;
|
|
1546
|
+
var MAX_SPENDING_MONTHS = 24;
|
|
1547
|
+
function periodSpending(value) {
|
|
1548
|
+
const amount = (field2) => finite(value?.[field2]) && value[field2] >= 0 ? value[field2] : 0;
|
|
1549
|
+
return {
|
|
1550
|
+
costUsd: amount("costUsd"),
|
|
1551
|
+
unknown: Math.floor(amount("unknown")),
|
|
1552
|
+
subscriptionUsd: amount("subscriptionUsd"),
|
|
1553
|
+
subscriptionRuns: Math.floor(amount("subscriptionRuns"))
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
function sanitizeArchivedSpending(value) {
|
|
1557
|
+
const periods = (entries, pattern, limit) => Object.fromEntries(Object.entries(entries && typeof entries === "object" && !Array.isArray(entries) ? entries : {}).filter(([key, entry]) => pattern.test(key) && entry && typeof entry === "object" && !Array.isArray(entry)).sort(([left], [right]) => left.localeCompare(right)).slice(-limit).map(([key, entry]) => [key, periodSpending(entry)]));
|
|
1558
|
+
return {
|
|
1559
|
+
days: periods(value?.days, /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/, MAX_SPENDING_DAYS),
|
|
1560
|
+
months: periods(value?.months, /^\d{4}-(?:0[1-9]|1[0-2])$/, MAX_SPENDING_MONTHS)
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1467
1563
|
function formatUsd(value) {
|
|
1468
1564
|
return typeof value === "number" && Number.isFinite(value) ? `$${value.toFixed(4)}` : "\u2014";
|
|
1469
1565
|
}
|
|
@@ -1491,32 +1587,88 @@ function applyQualityBiases(routes, biases) {
|
|
|
1491
1587
|
});
|
|
1492
1588
|
}
|
|
1493
1589
|
|
|
1494
|
-
// .dsh-plugin/
|
|
1590
|
+
// .dsh-plugin/shared/adaptive-feedback.mjs
|
|
1591
|
+
var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
1495
1592
|
var clean3 = (value) => typeof value === "string" ? value.trim() : "";
|
|
1593
|
+
var routeKey3 = (provider, model) => `${provider}\0${model}`;
|
|
1594
|
+
function applyFeedbackProfile(routes, profile) {
|
|
1595
|
+
if (!Array.isArray(routes) || profile?.enabled !== true || !profile.adjustments || typeof profile.adjustments !== "object" || Array.isArray(profile.adjustments)) return routes;
|
|
1596
|
+
return routes.map((route) => {
|
|
1597
|
+
if (!route || typeof route !== "object") return route;
|
|
1598
|
+
const key = routeKey3(clean3(route.provider), clean3(route.model));
|
|
1599
|
+
if (!Object.hasOwn(profile.adjustments, key)) return route;
|
|
1600
|
+
const value = profile.adjustments[key];
|
|
1601
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return route;
|
|
1602
|
+
const adjustments = Object.fromEntries(Object.entries(value).filter(([, bias]) => finite2(bias) && Math.abs(bias) <= 0.1));
|
|
1603
|
+
if (!Object.keys(adjustments).length) return route;
|
|
1604
|
+
return {
|
|
1605
|
+
...route,
|
|
1606
|
+
preferenceAdjustments: adjustments,
|
|
1607
|
+
preferenceAdjustmentMeta: {
|
|
1608
|
+
policyVersion: profile.policyVersion,
|
|
1609
|
+
revision: profile.revision,
|
|
1610
|
+
scope: profile.scope,
|
|
1611
|
+
feedbackCount: profile.feedbackCount,
|
|
1612
|
+
effectiveWeight: profile.effectiveWeight,
|
|
1613
|
+
updatedAt: profile.updatedAt,
|
|
1614
|
+
halfLifeDays: profile.halfLifeDays,
|
|
1615
|
+
maxAdjustment: profile.maxAdjustment,
|
|
1616
|
+
window: profile.window
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
// .dsh-plugin/shared/dynamic-data-view.mjs
|
|
1623
|
+
var exactRouteKey = (route) => `${String(route?.provider ?? "")}\0${String(route?.model ?? "")}`;
|
|
1624
|
+
function applyPricingSnapshot(routes, snapshot) {
|
|
1625
|
+
if (snapshot?.kind !== "pricing" || !snapshot.prices || typeof snapshot.prices !== "object") return routes;
|
|
1626
|
+
return (Array.isArray(routes) ? routes : []).map((route) => {
|
|
1627
|
+
if (route?.pricingSource === "user") return route;
|
|
1628
|
+
const entry = snapshot.prices[exactRouteKey(route)];
|
|
1629
|
+
if (!entry) return route;
|
|
1630
|
+
return {
|
|
1631
|
+
...route,
|
|
1632
|
+
pricing: {
|
|
1633
|
+
input: entry.input,
|
|
1634
|
+
output: entry.output,
|
|
1635
|
+
currency: "USD",
|
|
1636
|
+
...entry.cacheRead === void 0 ? {} : { cacheRead: entry.cacheRead },
|
|
1637
|
+
...entry.cacheWrite === void 0 ? {} : { cacheWrite: entry.cacheWrite }
|
|
1638
|
+
},
|
|
1639
|
+
pricingSource: "dynamic",
|
|
1640
|
+
pricingVersion: snapshot.version,
|
|
1641
|
+
snapshotAsOf: entry.asOf
|
|
1642
|
+
};
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// .dsh-plugin/client/catalog.mjs
|
|
1647
|
+
var clean4 = (value) => typeof value === "string" ? value.trim() : "";
|
|
1496
1648
|
function routesFromModelCatalog(catalog) {
|
|
1497
1649
|
const groups = Array.isArray(catalog?.groups) ? catalog.groups : [];
|
|
1498
1650
|
const routable = new Set(Array.isArray(catalog?.routableProviders) ? catalog.routableProviders : []);
|
|
1499
1651
|
const routes = [];
|
|
1500
1652
|
const seen = /* @__PURE__ */ new Set();
|
|
1501
1653
|
for (const group of groups) {
|
|
1502
|
-
const provider =
|
|
1654
|
+
const provider = clean4(group?.id);
|
|
1503
1655
|
if (!provider || !routable.has(provider)) continue;
|
|
1504
1656
|
for (const entry of Array.isArray(group.models) ? group.models : []) {
|
|
1505
|
-
const model =
|
|
1657
|
+
const model = clean4(entry?.id);
|
|
1506
1658
|
if (!model) continue;
|
|
1507
1659
|
const key = `${provider}\0${model}`;
|
|
1508
1660
|
if (seen.has(key)) continue;
|
|
1509
1661
|
seen.add(key);
|
|
1510
1662
|
const reasoning = entry?.reasoning;
|
|
1511
|
-
const efforts = Array.isArray(reasoning?.efforts) ? [...new Set(reasoning.efforts.map((item) =>
|
|
1663
|
+
const efforts = Array.isArray(reasoning?.efforts) ? [...new Set(reasoning.efforts.map((item) => clean4(item?.id ?? item)).filter(Boolean))] : [];
|
|
1512
1664
|
routes.push({
|
|
1513
1665
|
provider,
|
|
1514
|
-
providerName:
|
|
1666
|
+
providerName: clean4(group.name) || provider,
|
|
1515
1667
|
model,
|
|
1516
|
-
name:
|
|
1668
|
+
name: clean4(entry.name) || model,
|
|
1517
1669
|
reasoningKnown: reasoning !== void 0 && reasoning !== null,
|
|
1518
1670
|
reasoningEfforts: efforts,
|
|
1519
|
-
...
|
|
1671
|
+
...clean4(reasoning?.defaultEffort) ? { defaultReasoningEffort: clean4(reasoning.defaultEffort) } : {},
|
|
1520
1672
|
// modelCatalog deliberately omits modalities; unknown means the Host
|
|
1521
1673
|
// must still validate image capability before a real request.
|
|
1522
1674
|
inputModalities: []
|
|
@@ -1527,10 +1679,9 @@ function routesFromModelCatalog(catalog) {
|
|
|
1527
1679
|
return routes;
|
|
1528
1680
|
}
|
|
1529
1681
|
function createWorkspacePlan(task, catalog, options = {}) {
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
), options.qualityBiases ?? null);
|
|
1682
|
+
const profiled = applyModelProfiles(routesFromModelCatalog(catalog), parseModelProfilesJson(options.modelProfilesJson ?? "[]"));
|
|
1683
|
+
const priced = applyPricingSnapshot(profiled, options.pricingSnapshot ?? null);
|
|
1684
|
+
const routes = options.learning ? applyFeedbackProfile(priced, options.learning) : applyQualityBiases(priced, options.qualityBiases ?? null);
|
|
1534
1685
|
return createPlanFromRoutes(task, routes, options);
|
|
1535
1686
|
}
|
|
1536
1687
|
|
|
@@ -1557,6 +1708,7 @@ function profileDraft(profile) {
|
|
|
1557
1708
|
cacheWrite: profile?.pricing?.cacheWrite === void 0 ? "" : String(profile.pricing.cacheWrite),
|
|
1558
1709
|
specialties: Array.isArray(profile?.specialties) ? profile.specialties.join(", ") : "",
|
|
1559
1710
|
cliModel: profile?.cliModel ?? "",
|
|
1711
|
+
benchmarkModel: profile?.benchmarkModel ?? "",
|
|
1560
1712
|
execution: profile?.execution === "official" || profile?.execution === "api" ? profile.execution : "auto",
|
|
1561
1713
|
billing: BILLING_MODES.includes(profile?.billing) ? profile.billing : DEFAULT_BILLING_MODE,
|
|
1562
1714
|
subscription: ["plan-key", "cli-login", "none"].includes(profile?.subscription) ? profile.subscription : "auto",
|
|
@@ -1568,6 +1720,8 @@ function profileFromDraft(route, draft) {
|
|
|
1568
1720
|
const model = field(route?.model);
|
|
1569
1721
|
if (!provider || !model) throw new Error("\u8BF7\u5148\u4ECE\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u9009\u62E9\u4E00\u6761\u51C6\u786E\u7684\u6A21\u578B\u8DEF\u7EBF\u3002");
|
|
1570
1722
|
const profile = { provider, model };
|
|
1723
|
+
const benchmarkModel = field(draft?.benchmarkModel);
|
|
1724
|
+
if (benchmarkModel) profile.benchmarkModel = benchmarkModel;
|
|
1571
1725
|
const quality = nonnegativeField(draft?.quality, "\u8D28\u91CF\u8BC4\u5206", 100);
|
|
1572
1726
|
if (quality !== null) profile.quality = quality;
|
|
1573
1727
|
const input = nonnegativeField(draft?.input, "\u8F93\u5165\u5355\u4EF7");
|
|
@@ -1637,7 +1791,7 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
|
|
|
1637
1791
|
const [notice, setNotice] = import_react.default.useState(null);
|
|
1638
1792
|
import_react.default.useEffect(() => settingsScope.subscribe(() => setSnapshot(settingsScope.getSnapshot())), [settingsScope]);
|
|
1639
1793
|
const route = routes.find((item) => profileRouteKey(item) === selected) ?? routes[0];
|
|
1640
|
-
const
|
|
1794
|
+
const routeKey4 = route ? profileRouteKey(route) : "";
|
|
1641
1795
|
const rawJson = snapshot.value?.modelProfilesJson ?? "[]";
|
|
1642
1796
|
let profiles = [];
|
|
1643
1797
|
let loadError = "";
|
|
@@ -1646,16 +1800,16 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
|
|
|
1646
1800
|
} catch (error) {
|
|
1647
1801
|
loadError = messageOf(error);
|
|
1648
1802
|
}
|
|
1649
|
-
const saved = profiles.find((item) => profileRouteKey(item) ===
|
|
1650
|
-
const pending = drafts[
|
|
1803
|
+
const saved = profiles.find((item) => profileRouteKey(item) === routeKey4);
|
|
1804
|
+
const pending = drafts[routeKey4];
|
|
1651
1805
|
const draft = pending?.fields ?? profileDraft(saved);
|
|
1652
1806
|
const writable = snapshot.status === "ready" && snapshot.writable === true && !saving && !loadError;
|
|
1653
1807
|
const unmatched = profiles.filter((item) => !routes.some((route2) => profileRouteKey(route2) === profileRouteKey(item))).length;
|
|
1654
1808
|
const edit = (name, value) => {
|
|
1655
1809
|
if (!route || !writable) return;
|
|
1656
1810
|
setDrafts((previous) => {
|
|
1657
|
-
const previousEntry = previous[
|
|
1658
|
-
return { ...previous, [
|
|
1811
|
+
const previousEntry = previous[routeKey4] ?? { fields: profileDraft(saved), baseRevision: snapshot.revision };
|
|
1812
|
+
return { ...previous, [routeKey4]: { ...previousEntry, fields: { ...previousEntry.fields, [name]: value } } };
|
|
1659
1813
|
});
|
|
1660
1814
|
setNotice(null);
|
|
1661
1815
|
};
|
|
@@ -1680,7 +1834,7 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
|
|
|
1680
1834
|
if (!accepted) throw new Error("\u8BBE\u7F6E\u672A\u88AB\u4FDD\u5B58\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u9875\u9762\u4FEE\u6539\u3002\u8F93\u5165\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D\u540E\u6838\u5BF9\u3002");
|
|
1681
1835
|
setDrafts((previous) => {
|
|
1682
1836
|
const next = { ...previous };
|
|
1683
|
-
delete next[
|
|
1837
|
+
delete next[routeKey4];
|
|
1684
1838
|
return next;
|
|
1685
1839
|
});
|
|
1686
1840
|
setNotice({ tone: "success", text: remove ? "\u5DF2\u5220\u9664\u8BE5\u6A21\u578B\u7684\u81EA\u62A5\u914D\u7F6E\u3002" : "\u8BE5\u6A21\u578B\u914D\u7F6E\u5DF2\u4FDD\u5B58\uFF1B\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\u5373\u53EF\u4F7F\u7528\u3002" });
|
|
@@ -1694,15 +1848,15 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
|
|
|
1694
1848
|
const reload = () => {
|
|
1695
1849
|
setDrafts((previous) => {
|
|
1696
1850
|
const next = { ...previous };
|
|
1697
|
-
delete next[
|
|
1851
|
+
delete next[routeKey4];
|
|
1698
1852
|
return next;
|
|
1699
1853
|
});
|
|
1700
1854
|
setNotice(null);
|
|
1701
1855
|
};
|
|
1702
|
-
return /* @__PURE__ */ import_react.default.createElement("section", { className: "mr-card mr-profile-card", "aria-label": "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("h2", { className: "mr-card-title" }, "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B"), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-card-copy" }, "\u9009\u62E9\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E\u8DEF\u7EBF\uFF0C\u586B\u5199\u4F60\u638C\u63E1\u7684\u8D28\u91CF\u8BC4\u5206\u4E0E\u5355\u4EF7\u3002\u914D\u7F6E\u7531\u4F60\u63D0\u4F9B\uFF0C\u63D2\u4EF6\u4E0D\u4F1A\u8BFB\u53D6\u8D26\u53F7\u5BC6\u94A5\u3002"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-body" }, loadError && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "alert" }, "\u5DF2\u6709\u914D\u7F6E\u65E0\u6CD5\u89E3\u6790\uFF1A", loadError, "\u3002\u8BF7\u5148\u5728\u63D2\u4EF6\u8BBE\u7F6E\u9875\u4FEE\u6B63 JSON\u3002"), snapshot.status !== "ready" && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption" }, "\u8BBE\u7F6E\u72B6\u6001\uFF1A", snapshot.status === "loading" ? "\u6B63\u5728\u52A0\u8F7D" : "\u5F53\u524D\u4E0D\u53EF\u7528"), snapshot.status === "ready" && !snapshot.writable && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "status" }, "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u8BF7\u5728\u53EF\u5199\u7684\u672C\u673A\u73AF\u5883\u914D\u7F6E\u3002"), routes.length === 0 ? /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-empty" }, "\u8BF7\u5148\u5728 DeepSeek Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\uFF0C\u518D\u8FD4\u56DE\u8FD9\u91CC\u586B\u5199\u4EF7\u683C\u4E0E\u80FD\u529B\u3002") : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-label", htmlFor: "mr-profile-route" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", id: "mr-profile-route", value:
|
|
1856
|
+
return /* @__PURE__ */ import_react.default.createElement("section", { className: "mr-card mr-profile-card", "aria-label": "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("h2", { className: "mr-card-title" }, "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B"), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-card-copy" }, "\u9009\u62E9\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E\u8DEF\u7EBF\uFF0C\u586B\u5199\u4F60\u638C\u63E1\u7684\u8D28\u91CF\u8BC4\u5206\u4E0E\u5355\u4EF7\u3002\u914D\u7F6E\u7531\u4F60\u63D0\u4F9B\uFF0C\u63D2\u4EF6\u4E0D\u4F1A\u8BFB\u53D6\u8D26\u53F7\u5BC6\u94A5\u3002"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-body" }, loadError && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "alert" }, "\u5DF2\u6709\u914D\u7F6E\u65E0\u6CD5\u89E3\u6790\uFF1A", loadError, "\u3002\u8BF7\u5148\u5728\u63D2\u4EF6\u8BBE\u7F6E\u9875\u4FEE\u6B63 JSON\u3002"), snapshot.status !== "ready" && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption" }, "\u8BBE\u7F6E\u72B6\u6001\uFF1A", snapshot.status === "loading" ? "\u6B63\u5728\u52A0\u8F7D" : "\u5F53\u524D\u4E0D\u53EF\u7528"), snapshot.status === "ready" && !snapshot.writable && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "status" }, "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u8BF7\u5728\u53EF\u5199\u7684\u672C\u673A\u73AF\u5883\u914D\u7F6E\u3002"), routes.length === 0 ? /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-empty" }, "\u8BF7\u5148\u5728 DeepSeek Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\uFF0C\u518D\u8FD4\u56DE\u8FD9\u91CC\u586B\u5199\u4EF7\u683C\u4E0E\u80FD\u529B\u3002") : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-label", htmlFor: "mr-profile-route" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", id: "mr-profile-route", value: routeKey4, onChange: (event) => {
|
|
1703
1857
|
setSelected(event.target.value);
|
|
1704
1858
|
setNotice(null);
|
|
1705
|
-
} }, routes.map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: profileRouteKey(item), value: profileRouteKey(item) }, item.provider, "/", item.model))), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption mr-profile-state" }, saved ? `\u5DF2\u914D\u7F6E${saved.pricing ? "\u5355\u4EF7" : "\u80FD\u529B\uFF0C\u4EF7\u683C\u672A\u77E5"}` : "\u672A\u914D\u7F6E\uFF0C\u4EF7\u683C\u4E0E\u8D28\u91CF\u6765\u6E90\u672A\u77E5", pending ? " \xB7 \u5F53\u524D\u6709\u672A\u4FDD\u5B58\u8F93\u5165" : "", unmatched > 0 ? ` \xB7 \u53E6\u6709 ${unmatched} \u6761\u914D\u7F6E\u4E0D\u5728\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u4E2D\uFF0C\u4FDD\u5B58\u65F6\u4F1A\u4FDD\u7559` : ""), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8D28\u91CF\u8BC4\u5206\uFF080\u2013100\uFF0C\u81EA\u62A5\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", max: "100", step: "any", value: draft.quality, disabled: !writable, onChange: (event) => edit("quality", event.target.value), placeholder: "\u4F8B\u5982 85\uFF1B\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u5165\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.input, disabled: !writable, onChange: (event) => edit("input", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u51FA\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.output, disabled: !writable, onChange: (event) => edit("output", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u64C5\u957F\u65B9\u5411\uFF08\u82F1\u6587\u6807\u7B7E\uFF0C\u9017\u53F7\u5206\u9694\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.specialties, disabled: !writable, onChange: (event) => edit("specialties", event.target.value), placeholder: PROFILE_SPECIALTY_HINT })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u5B98\u65B9 CLI \u6A21\u578B\u540D\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.cliModel, disabled: !writable, onChange: (event) => edit("cliModel", event.target.value), placeholder: "\u4EC5\u5728\u5382\u5546 CLI \u652F\u6301\u8BE5\u51C6\u786E\u540D\u79F0\u65F6\u586B\u5199" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u6267\u884C\u65B9\u5F0F"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.execution || "auto", disabled: !writable, onChange: (event) => edit("execution", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "auto" }, "\u81EA\u52A8\uFF1A\u5DF2\u5B89\u88C5\u5219\u7528\u5B98\u65B9\u5DE5\u5177\uFF0C\u5931\u8D25\u56DE\u9000 API"), /* @__PURE__ */ import_react.default.createElement("option", { value: "official" }, "\u5B98\u65B9\u5DE5\u5177\uFF1A\u5931\u8D25\u6216\u672A\u5B89\u88C5\u65F6\u56DE\u9000 API"), /* @__PURE__ */ import_react.default.createElement("option", { value: "api" }, "\u4EC5\u6A21\u578B\u76EE\u5F55 API"))), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8BA1\u8D39\u65B9\u5F0F"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.billing, disabled: !writable, onChange: (event) => edit("billing", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "subscription-first" }, "\u8BA2\u9605\u4F18\u5148\uFF1A\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\u5207\u6362 API Key"), /* @__PURE__ */ import_react.default.createElement("option", { value: "api-only" }, "\u53EA\u7528 API Key"), /* @__PURE__ */ import_react.default.createElement("option", { value: "subscription-only" }, "\u53EA\u7528\u8BA2\u9605\uFF1A\u989D\u5EA6\u7528\u5C3D\u65F6\u4E0D\u5207\u6362"))), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8BA2\u9605\u6765\u6E90"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.subscription, disabled: !writable, onChange: (event) => edit("subscription", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "auto" }, "\u81EA\u52A8\uFF1A\u6709\u5B98\u65B9 CLI \u65F6\u7528 CLI \u8D26\u53F7\u767B\u5F55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "plan-key" }, "\u7F16\u7A0B\u5957\u9910 Key\uFF1A\u8BE5\u8DEF\u7EBF\u672C\u8EAB\u662F\u5957\u9910\u7AEF\u70B9"), /* @__PURE__ */ import_react.default.createElement("option", { value: "cli-login" }, "\u5B98\u65B9 CLI \u8D26\u53F7\u767B\u5F55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "none" }, "\u65E0\u8BA2\u9605\uFF1A\u59CB\u7EC8\u6309 API \u8BA1\u8D39"))), draft.subscription === "plan-key" && /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u989D\u5EA6\u7528\u5C3D\u65F6\u56DE\u9000\u7684 API \u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.apiRoute, disabled: !writable, onChange: (event) => edit("apiRoute", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, "\u4E0D\u56DE\u9000\uFF08\u672A\u914D\u7F6E API \u8DEF\u7EBF\uFF09"), routes.filter((item) => profileRouteKey(item) !==
|
|
1859
|
+
} }, routes.map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: profileRouteKey(item), value: profileRouteKey(item) }, item.provider, "/", item.model))), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption mr-profile-state" }, saved ? `\u5DF2\u914D\u7F6E${saved.pricing ? "\u5355\u4EF7" : "\u80FD\u529B\uFF0C\u4EF7\u683C\u672A\u77E5"}` : "\u672A\u914D\u7F6E\uFF0C\u4EF7\u683C\u4E0E\u8D28\u91CF\u6765\u6E90\u672A\u77E5", pending ? " \xB7 \u5F53\u524D\u6709\u672A\u4FDD\u5B58\u8F93\u5165" : "", unmatched > 0 ? ` \xB7 \u53E6\u6709 ${unmatched} \u6761\u914D\u7F6E\u4E0D\u5728\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u4E2D\uFF0C\u4FDD\u5B58\u65F6\u4F1A\u4FDD\u7559` : ""), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8D28\u91CF\u8BC4\u5206\uFF080\u2013100\uFF0C\u81EA\u62A5\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", max: "100", step: "any", value: draft.quality, disabled: !writable, onChange: (event) => edit("quality", event.target.value), placeholder: "\u4F8B\u5982 85\uFF1B\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u5165\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.input, disabled: !writable, onChange: (event) => edit("input", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u51FA\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.output, disabled: !writable, onChange: (event) => edit("output", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u64C5\u957F\u65B9\u5411\uFF08\u82F1\u6587\u6807\u7B7E\uFF0C\u9017\u53F7\u5206\u9694\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.specialties, disabled: !writable, onChange: (event) => edit("specialties", event.target.value), placeholder: PROFILE_SPECIALTY_HINT })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u5B98\u65B9 CLI \u6A21\u578B\u540D\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.cliModel, disabled: !writable, onChange: (event) => edit("cliModel", event.target.value), placeholder: "\u4EC5\u5728\u5382\u5546 CLI \u652F\u6301\u8BE5\u51C6\u786E\u540D\u79F0\u65F6\u586B\u5199" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "LiveBench \u51C6\u786E\u6A21\u578B\u540D\u79F0\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.benchmarkModel ?? "", disabled: !writable, onChange: (event) => edit("benchmarkModel", event.target.value), placeholder: "\u786E\u8BA4\u7248\u672C\u4E0E\u63A8\u7406\u6863\u4F4D\u4E00\u81F4\uFF1B\u4E0D\u81EA\u52A8\u731C\u6D4B\u522B\u540D" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u6267\u884C\u65B9\u5F0F"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.execution || "auto", disabled: !writable, onChange: (event) => edit("execution", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "auto" }, "\u81EA\u52A8\uFF1A\u5DF2\u5B89\u88C5\u5219\u7528\u5B98\u65B9\u5DE5\u5177\uFF0C\u5931\u8D25\u56DE\u9000 API"), /* @__PURE__ */ import_react.default.createElement("option", { value: "official" }, "\u5B98\u65B9\u5DE5\u5177\uFF1A\u5931\u8D25\u6216\u672A\u5B89\u88C5\u65F6\u56DE\u9000 API"), /* @__PURE__ */ import_react.default.createElement("option", { value: "api" }, "\u4EC5\u6A21\u578B\u76EE\u5F55 API"))), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8BA1\u8D39\u65B9\u5F0F"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.billing, disabled: !writable, onChange: (event) => edit("billing", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "subscription-first" }, "\u8BA2\u9605\u4F18\u5148\uFF1A\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\u5207\u6362 API Key"), /* @__PURE__ */ import_react.default.createElement("option", { value: "api-only" }, "\u53EA\u7528 API Key"), /* @__PURE__ */ import_react.default.createElement("option", { value: "subscription-only" }, "\u53EA\u7528\u8BA2\u9605\uFF1A\u989D\u5EA6\u7528\u5C3D\u65F6\u4E0D\u5207\u6362"))), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8BA2\u9605\u6765\u6E90"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.subscription, disabled: !writable, onChange: (event) => edit("subscription", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "auto" }, "\u81EA\u52A8\uFF1A\u6709\u5B98\u65B9 CLI \u65F6\u7528 CLI \u8D26\u53F7\u767B\u5F55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "plan-key" }, "\u7F16\u7A0B\u5957\u9910 Key\uFF1A\u8BE5\u8DEF\u7EBF\u672C\u8EAB\u662F\u5957\u9910\u7AEF\u70B9"), /* @__PURE__ */ import_react.default.createElement("option", { value: "cli-login" }, "\u5B98\u65B9 CLI \u8D26\u53F7\u767B\u5F55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "none" }, "\u65E0\u8BA2\u9605\uFF1A\u59CB\u7EC8\u6309 API \u8BA1\u8D39"))), draft.subscription === "plan-key" && /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u989D\u5EA6\u7528\u5C3D\u65F6\u56DE\u9000\u7684 API \u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.apiRoute, disabled: !writable, onChange: (event) => edit("apiRoute", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, "\u4E0D\u56DE\u9000\uFF08\u672A\u914D\u7F6E API \u8DEF\u7EBF\uFF09"), routes.filter((item) => profileRouteKey(item) !== routeKey4).map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: profileRouteKey(item), value: profileRouteKey(item) }, item.provider, "/", item.model))))), /* @__PURE__ */ import_react.default.createElement("details", { className: "mr-profile-advanced" }, /* @__PURE__ */ import_react.default.createElement("summary", null, "\u7F13\u5B58\u5355\u4EF7\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u7F13\u5B58\u8BFB\u53D6\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.cacheRead, disabled: !writable, onChange: (event) => edit("cacheRead", event.target.value), placeholder: "\u7559\u7A7A\u6309\u666E\u901A\u8F93\u5165\u4EF7\u683C\u4F30\u7B97" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u7F13\u5B58\u5199\u5165\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.cacheWrite, disabled: !writable, onChange: (event) => edit("cacheWrite", event.target.value), placeholder: "\u7559\u7A7A\u6309\u666E\u901A\u8F93\u5165\u4EF7\u683C\u4F30\u7B97" })))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button", type: "button", disabled: !writable || !pending, onClick: () => {
|
|
1706
1860
|
void write(false);
|
|
1707
1861
|
} }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u6B64\u6A21\u578B"), /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !pending || saving, onClick: reload }, "\u91CD\u65B0\u52A0\u8F7D\u6B64\u8DEF\u7EBF"), saved && /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !writable, onClick: () => {
|
|
1708
1862
|
void write(true);
|
|
@@ -1846,11 +2000,23 @@ function packageCost(item) {
|
|
|
1846
2000
|
}
|
|
1847
2001
|
return { budget: item?.ran ? "\u8D39\u7528\u672A\u77E5" : "\u2014", reference: null };
|
|
1848
2002
|
}
|
|
2003
|
+
function priorAttemptTotals(run) {
|
|
2004
|
+
const months = sanitizeArchivedSpending(run?.priorAttemptSpending).months;
|
|
2005
|
+
const totals = { budgetUsd: 0, referenceUsd: 0, unknownCalls: 0, subscriptionRuns: 0 };
|
|
2006
|
+
for (const period of Object.values(months)) {
|
|
2007
|
+
totals.budgetUsd += period.costUsd;
|
|
2008
|
+
totals.referenceUsd += period.subscriptionUsd;
|
|
2009
|
+
totals.unknownCalls += period.unknown;
|
|
2010
|
+
totals.subscriptionRuns += period.subscriptionRuns;
|
|
2011
|
+
}
|
|
2012
|
+
return totals;
|
|
2013
|
+
}
|
|
1849
2014
|
function runTotals(run) {
|
|
1850
2015
|
const items = [...run?.packages ?? [], ...run?.reviews ?? []];
|
|
1851
|
-
|
|
1852
|
-
let
|
|
1853
|
-
let
|
|
2016
|
+
const prior = priorAttemptTotals(run);
|
|
2017
|
+
let budgetUsd = prior.budgetUsd;
|
|
2018
|
+
let referenceUsd = prior.referenceUsd;
|
|
2019
|
+
let subscription = prior.subscriptionRuns > 0;
|
|
1854
2020
|
for (const item of items) {
|
|
1855
2021
|
if (item.billing === "subscription") {
|
|
1856
2022
|
subscription = true;
|
|
@@ -1948,6 +2114,92 @@ function rerunConfirmations({ run, item, override = null, choice = null, ledger
|
|
|
1948
2114
|
return reasons;
|
|
1949
2115
|
}
|
|
1950
2116
|
|
|
2117
|
+
// .dsh-plugin/client/adaptive-state.mjs
|
|
2118
|
+
var ADAPTIVE_DEFAULTS = Object.freeze({
|
|
2119
|
+
feedbackLearningEnabled: true,
|
|
2120
|
+
feedbackHalfLifeDays: 30,
|
|
2121
|
+
feedbackPriorWeight: 3,
|
|
2122
|
+
feedbackMaxAdjustment: 0.04,
|
|
2123
|
+
feedbackResetAt: 0,
|
|
2124
|
+
dynamicDataEnabled: false,
|
|
2125
|
+
liveBenchEndpoint: "https://livebench.ai",
|
|
2126
|
+
dynamicDataTtlMinutes: 1440,
|
|
2127
|
+
pricingSnapshotEndpoint: ""
|
|
2128
|
+
});
|
|
2129
|
+
var ADAPTIVE_NUMBER_FIELDS = Object.freeze([
|
|
2130
|
+
Object.freeze({ key: "feedbackHalfLifeDays", min: 1, max: 3650, step: 1 }),
|
|
2131
|
+
Object.freeze({ key: "feedbackPriorWeight", min: 1, max: 1e6, step: 1 }),
|
|
2132
|
+
Object.freeze({ key: "feedbackMaxAdjustment", min: 0, max: 0.1, step: 0.01 }),
|
|
2133
|
+
Object.freeze({ key: "dynamicDataTtlMinutes", min: 1, max: 10080, step: 1 })
|
|
2134
|
+
]);
|
|
2135
|
+
function adaptiveSettingValue(settings, key) {
|
|
2136
|
+
return settings?.[key] ?? ADAPTIVE_DEFAULTS[key];
|
|
2137
|
+
}
|
|
2138
|
+
function parseAdaptiveNumber(key, draft) {
|
|
2139
|
+
const field2 = ADAPTIVE_NUMBER_FIELDS.find((item) => item.key === key);
|
|
2140
|
+
if (!field2) throw new TypeError("Unknown numeric setting");
|
|
2141
|
+
if (typeof draft !== "string" && typeof draft !== "number" || String(draft).trim() === "") throw new TypeError("Enter a number");
|
|
2142
|
+
const value = Number(draft);
|
|
2143
|
+
if (!Number.isFinite(value) || value < field2.min || value > field2.max) throw new RangeError(`Expected ${field2.min}..${field2.max}`);
|
|
2144
|
+
return value;
|
|
2145
|
+
}
|
|
2146
|
+
function parsePublicEndpoint(key, draft) {
|
|
2147
|
+
if (!["liveBenchEndpoint", "pricingSnapshotEndpoint"].includes(key)) throw new TypeError("Unknown endpoint setting");
|
|
2148
|
+
if (typeof draft !== "string") throw new TypeError("Enter a public HTTPS URL");
|
|
2149
|
+
const value = draft.trim();
|
|
2150
|
+
if (key === "pricingSnapshotEndpoint" && value === "") return "";
|
|
2151
|
+
if (!value || value.length > 2048) throw new TypeError("Enter a public HTTPS URL");
|
|
2152
|
+
let parsed;
|
|
2153
|
+
try {
|
|
2154
|
+
parsed = new URL(value);
|
|
2155
|
+
} catch {
|
|
2156
|
+
throw new TypeError("Enter a public HTTPS URL");
|
|
2157
|
+
}
|
|
2158
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.search || parsed.hash || parsed.port && parsed.port !== "443") {
|
|
2159
|
+
throw new TypeError("Use a public HTTPS URL without credentials, query or fragment");
|
|
2160
|
+
}
|
|
2161
|
+
if (!/^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/iu.test(parsed.hostname) || /(?:^|\.)(?:localhost|local|internal|lan|home|test|invalid)$/iu.test(parsed.hostname)) throw new TypeError("Use a public hostname");
|
|
2162
|
+
return value;
|
|
2163
|
+
}
|
|
2164
|
+
function publicEndpointDraft(key, value) {
|
|
2165
|
+
try {
|
|
2166
|
+
return parsePublicEndpoint(key, value);
|
|
2167
|
+
} catch {
|
|
2168
|
+
return "";
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
function feedbackRatingArguments(run, item, direction) {
|
|
2172
|
+
if (!["up", "down"].includes(direction)) throw new TypeError("Unknown rating direction");
|
|
2173
|
+
const active = direction === "up" ? item?.rating === 1 : item?.rating === -1;
|
|
2174
|
+
return [run?.id, item?.id, active ? "clear" : direction, item?.finishedAt];
|
|
2175
|
+
}
|
|
2176
|
+
var nonnegative2 = (value) => Number.isFinite(value) && value >= 0 ? value : 0;
|
|
2177
|
+
function learningView(learning, settings = {}) {
|
|
2178
|
+
return {
|
|
2179
|
+
available: Boolean(learning && typeof learning === "object"),
|
|
2180
|
+
enabled: typeof learning?.enabled === "boolean" ? learning.enabled : adaptiveSettingValue(settings, "feedbackLearningEnabled") !== false,
|
|
2181
|
+
feedbackCount: nonnegative2(learning?.feedbackCount),
|
|
2182
|
+
ignoredCount: nonnegative2(learning?.ignoredCount),
|
|
2183
|
+
effectiveWeight: nonnegative2(learning?.effectiveWeight),
|
|
2184
|
+
policyVersion: typeof learning?.policyVersion === "string" ? learning.policyVersion.slice(0, 100) : null,
|
|
2185
|
+
resetAt: nonnegative2(adaptiveSettingValue(settings, "feedbackResetAt"))
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
var STATUS_LABEL = Object.freeze({ disabled: "\u672A\u542F\u7528", missing: "\u5C1A\u65E0\u5FEB\u7167", fresh: "\u5FEB\u7167\u6709\u6548", stale: "\u5FEB\u7167\u8FC7\u671F", error: "\u66F4\u65B0\u5931\u8D25" });
|
|
2189
|
+
function dynamicSourceView(source) {
|
|
2190
|
+
const status = Object.hasOwn(STATUS_LABEL, source?.status ?? "") ? source.status : "missing";
|
|
2191
|
+
let publicSource = "";
|
|
2192
|
+
if (typeof source?.source === "string") publicSource = publicEndpointDraft("pricingSnapshotEndpoint", source.source);
|
|
2193
|
+
return {
|
|
2194
|
+
status,
|
|
2195
|
+
label: STATUS_LABEL[status],
|
|
2196
|
+
source: publicSource,
|
|
2197
|
+
version: typeof source?.version === "string" ? source.version.slice(0, 160) : null,
|
|
2198
|
+
verifiedAt: Number.isFinite(source?.verifiedAt) && source.verifiedAt > 0 ? source.verifiedAt : null,
|
|
2199
|
+
count: nonnegative2(source?.modelCount ?? source?.rowCount)
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
|
|
1951
2203
|
// .dsh-plugin/client/router-insights.jsx
|
|
1952
2204
|
var text = (value) => typeof value === "string" ? value.trim() : "";
|
|
1953
2205
|
var BAND = { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u56F0\u96BE" };
|
|
@@ -1998,6 +2250,134 @@ function useSettingsWriter(settingsScope) {
|
|
|
1998
2250
|
};
|
|
1999
2251
|
return { value: snapshot.value ?? {}, writable, write, notice };
|
|
2000
2252
|
}
|
|
2253
|
+
var ADAPTIVE_FIELD_LABEL = {
|
|
2254
|
+
feedbackHalfLifeDays: "\u53CD\u9988\u534A\u8870\u671F\uFF08\u5929\uFF09",
|
|
2255
|
+
feedbackPriorWeight: "\u6536\u7F29\u5F3A\u5EA6",
|
|
2256
|
+
feedbackMaxAdjustment: "\u6700\u5927\u504F\u597D\u6548\u7528\u8C03\u6574",
|
|
2257
|
+
dynamicDataTtlMinutes: "\u516C\u5171\u5FEB\u7167\u68C0\u67E5\u95F4\u9694\uFF08\u5206\u949F\uFF09"
|
|
2258
|
+
};
|
|
2259
|
+
function AdaptiveNumberControl({ field: field2, value, writable, onSave }) {
|
|
2260
|
+
const [draft, setDraft] = import_react2.default.useState("");
|
|
2261
|
+
const [notice, setNotice] = import_react2.default.useState("");
|
|
2262
|
+
const save = async () => {
|
|
2263
|
+
try {
|
|
2264
|
+
const next = parseAdaptiveNumber(field2.key, draft);
|
|
2265
|
+
setNotice("");
|
|
2266
|
+
if (await onSave(field2.key, next)) setDraft("");
|
|
2267
|
+
} catch {
|
|
2268
|
+
setNotice(`\u8BF7\u8F93\u5165 ${field2.min} \u5230 ${field2.max} \u7684\u6570\u5B57\u3002`);
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: `mr-${field2.key}` }, ADAPTIVE_FIELD_LABEL[field2.key]), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
2272
|
+
"input",
|
|
2273
|
+
{
|
|
2274
|
+
className: "mr-input mr-budget",
|
|
2275
|
+
id: `mr-${field2.key}`,
|
|
2276
|
+
type: "number",
|
|
2277
|
+
min: field2.min,
|
|
2278
|
+
max: field2.max,
|
|
2279
|
+
step: field2.step,
|
|
2280
|
+
placeholder: String(value),
|
|
2281
|
+
value: draft,
|
|
2282
|
+
disabled: !writable,
|
|
2283
|
+
onChange: (event) => setDraft(event.target.value)
|
|
2284
|
+
}
|
|
2285
|
+
), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !writable || draft === "", onClick: () => {
|
|
2286
|
+
void save();
|
|
2287
|
+
} }, "\u4FDD\u5B58")), notice && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-error", role: "alert" }, notice));
|
|
2288
|
+
}
|
|
2289
|
+
function PublicEndpointControl({ name, label, value, writable, onSave }) {
|
|
2290
|
+
const [draft, setDraft] = import_react2.default.useState(null);
|
|
2291
|
+
const [notice, setNotice] = import_react2.default.useState("");
|
|
2292
|
+
const current = publicEndpointDraft(name, value);
|
|
2293
|
+
const save = async () => {
|
|
2294
|
+
try {
|
|
2295
|
+
const next = parsePublicEndpoint(name, draft ?? current);
|
|
2296
|
+
setNotice("");
|
|
2297
|
+
if (await onSave(name, next)) setDraft(null);
|
|
2298
|
+
} catch {
|
|
2299
|
+
setNotice("\u8BF7\u8F93\u5165\u4E0D\u542B\u8BA4\u8BC1\u3001\u67E5\u8BE2\u53C2\u6570\u6216\u7247\u6BB5\u7684\u516C\u5F00 HTTPS \u5730\u5740\uFF1B\u4EF7\u683C\u5FEB\u7167\u53EF\u7559\u7A7A\u3002");
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: `mr-${name}` }, label), /* @__PURE__ */ import_react2.default.createElement(
|
|
2303
|
+
"input",
|
|
2304
|
+
{
|
|
2305
|
+
className: "mr-input",
|
|
2306
|
+
id: `mr-${name}`,
|
|
2307
|
+
type: "url",
|
|
2308
|
+
maxLength: 2048,
|
|
2309
|
+
value: draft ?? current,
|
|
2310
|
+
disabled: !writable,
|
|
2311
|
+
placeholder: name === "liveBenchEndpoint" ? "https://livebench.ai" : "\u7559\u7A7A\uFF1A\u4E0D\u8BFB\u53D6\u8FDC\u7A0B\u4EF7\u683C\u5FEB\u7167",
|
|
2312
|
+
onChange: (event) => setDraft(event.target.value)
|
|
2313
|
+
}
|
|
2314
|
+
), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !writable || draft === null, onClick: () => {
|
|
2315
|
+
void save();
|
|
2316
|
+
} }, "\u4FDD\u5B58\u5730\u5740"), notice && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-error", role: "alert" }, notice));
|
|
2317
|
+
}
|
|
2318
|
+
function PublicSourceStatus({ label, source }) {
|
|
2319
|
+
const view = dynamicSourceView(source);
|
|
2320
|
+
return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, label, "\uFF1A", view.label), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, view.version ? `\u7248\u672C ${view.version} \xB7 ` : "", view.count, " \u6761\u8BB0\u5F55", view.verifiedAt ? ` \xB7 \u6700\u8FD1\u6821\u9A8C ${new Date(view.verifiedAt).toLocaleString()}` : ""), view.source && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u516C\u5F00\u6765\u6E90\uFF1A", view.source), view.status === "error" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u66F4\u65B0\u5931\u8D25\uFF1B\u662F\u5426\u53EF\u7528\u7531 Host \u6821\u9A8C\uFF0C\u4E0D\u5C06\u7F3A\u5931\u6570\u636E\u5F53\u4F5C\u96F6\u6210\u672C\u6216\u6EE1\u5206\u3002"));
|
|
2321
|
+
}
|
|
2322
|
+
function AdaptiveControls({ ledger, settings, onChanged }) {
|
|
2323
|
+
const value = settings.value;
|
|
2324
|
+
const learning = learningView(ledger?.learning, value);
|
|
2325
|
+
const [resetBusy, setResetBusy] = import_react2.default.useState(false);
|
|
2326
|
+
const save = async (key, next) => {
|
|
2327
|
+
const accepted = await settings.write(key, next);
|
|
2328
|
+
if (accepted) onChanged?.();
|
|
2329
|
+
return accepted;
|
|
2330
|
+
};
|
|
2331
|
+
const reset = async () => {
|
|
2332
|
+
if (!window.confirm("\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60\u4F60\u7684\u504F\u597D\uFF1F\u6B64\u524D\u53CD\u9988\u5C06\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\uFF0C\u4F46\u6267\u884C\u8BB0\u5F55\u3001\u8D39\u7528\u5386\u53F2\u548C\u539F\u8BC4\u4EF7\u4E0D\u4F1A\u5220\u9664\u3002")) return;
|
|
2333
|
+
setResetBusy(true);
|
|
2334
|
+
try {
|
|
2335
|
+
await save("feedbackResetAt", Date.now());
|
|
2336
|
+
} finally {
|
|
2337
|
+
setResetBusy(false);
|
|
2338
|
+
}
|
|
2339
|
+
};
|
|
2340
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("h3", { className: "mr-section-title" }, "\u6301\u7EED\u53CD\u9988\u4E0E\u672C\u5730\u504F\u597D"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u53EA\u4F7F\u7528\u4F60\u5BF9\u5DF2\u8BB0\u5F55\u7ED3\u679C\u7684\u70B9\u8D5E / \u4E0D\u597D / \u64A4\u56DE\uFF0C\u6309\u4EFB\u52A1\u7C7B\u578B\u548C\u65F6\u95F4\u8870\u51CF\u8C03\u6574\u504F\u597D\u6548\u7528\uFF1B\u4E0D\u62AC\u9AD8\u8D28\u91CF\u786C\u95E8\u69DB\u3002\u7CFB\u7EDF\u6267\u884C\u6210\u529F\u4E0D\u7B49\u4E8E\u4F60\u6EE1\u610F\uFF0C\u6A21\u578B\u590D\u6838\u4E5F\u4E0D\u4F5C\u4E3A\u4EBA\u5DE5\u8BC4\u5206\u3002\u4E0D\u4F1A\u4E3A\u4E86\u5B66\u4E60\u53D1\u8D77\u4ED8\u8D39\u63A2\u7D22\u3002"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8303\u56F4\uFF1A\u672C\u5730 DSH_HOME \u5DE5\u4F5C\u5BA4\u5171\u4EAB\uFF0C\u4E0D\u662F\u6309\u8D26\u53F7\u9694\u79BB\uFF1B\u6700\u591A\u6700\u8FD1 200 \u6B21\u8FD0\u884C\u7684\u6ED1\u52A8\u7A97\u53E3\uFF0C\u4E0D\u4E0A\u4F20\u53CD\u9988\u6216\u4EFB\u52A1\u5185\u5BB9\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
2341
|
+
"input",
|
|
2342
|
+
{
|
|
2343
|
+
type: "checkbox",
|
|
2344
|
+
checked: adaptiveSettingValue(value, "feedbackLearningEnabled") !== false,
|
|
2345
|
+
disabled: !settings.writable,
|
|
2346
|
+
onChange: (event) => {
|
|
2347
|
+
void save("feedbackLearningEnabled", event.target.checked);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
), "\u542F\u7528\u7528\u6237\u53CD\u9988\u5B66\u4E60"), ADAPTIVE_NUMBER_FIELDS.filter((field2) => field2.key !== "dynamicDataTtlMinutes").map((field2) => /* @__PURE__ */ import_react2.default.createElement(
|
|
2351
|
+
AdaptiveNumberControl,
|
|
2352
|
+
{
|
|
2353
|
+
key: field2.key,
|
|
2354
|
+
field: field2,
|
|
2355
|
+
value: adaptiveSettingValue(value, field2.key),
|
|
2356
|
+
writable: settings.writable,
|
|
2357
|
+
onSave: save
|
|
2358
|
+
}
|
|
2359
|
+
))), learning.available ? /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, learning.enabled ? "\u5B66\u4E60\u5DF2\u542F\u7528" : "\u5B66\u4E60\u5DF2\u505C\u7528", " \xB7 \u6709\u6548\u53CD\u9988 ", learning.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", learning.effectiveWeight.toFixed(2), " \xB7 \u5FFD\u7565 ", learning.ignoredCount, learning.policyVersion ? ` \xB7 \u7B56\u7565 ${learning.policyVersion}` : "") : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B66\u4E60\u6458\u8981\u5C1A\u672A\u8BFB\u53D6\uFF1B\u4FDD\u5B58\u540E\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u67E5\u770B\u3002"), learning.resetAt > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5B66\u4E60\u8D77\u70B9\uFF1A", new Date(learning.resetAt).toLocaleString(), "\uFF0C\u6B64\u524D\u53CD\u9988\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\u3002"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || resetBusy, onClick: () => {
|
|
2360
|
+
void reset();
|
|
2361
|
+
} }, resetBusy ? "\u6B63\u5728\u8BBE\u7F6E\u2026" : "\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60"), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "mr-section-title" }, "\u52A8\u6001\u516C\u5171\u6570\u636E"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u9ED8\u8BA4\u5173\u95ED\u3002\u660E\u786E\u542F\u7528\u540E\uFF0C\u5728\u6253\u5F00 / \u5237\u65B0\u8D26\u672C\u53CA\u6267\u884C\u524D\u6309\u68C0\u67E5\u95F4\u9694\u8BFB\u53D6\u516C\u5F00 LiveBench \u548C\u53EF\u9009\u4EF7\u683C\u5FEB\u7167\uFF1B\u4EF7\u683C\u4E0E\u80FD\u529B\u5148\u9A8C\u4FDD\u7559\u7248\u672C\uFF0C\u4E0D\u4EE3\u8868\u771F\u5B9E\u4EFB\u52A1\u6536\u76CA\u3002\u53EA\u6709\u6253\u5F00\u516C\u5171\u6E90\u5F00\u5173\u624D\u4F1A\u8BFB\u53D6\u8FDC\u7A0B\u6570\u636E\uFF0C\u4E0D\u53D1\u9001\u4EFB\u52A1\u6216\u53CD\u9988\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
2362
|
+
"input",
|
|
2363
|
+
{
|
|
2364
|
+
type: "checkbox",
|
|
2365
|
+
checked: adaptiveSettingValue(value, "dynamicDataEnabled") === true,
|
|
2366
|
+
disabled: !settings.writable,
|
|
2367
|
+
onChange: (event) => {
|
|
2368
|
+
void save("dynamicDataEnabled", event.target.checked);
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
), "\u542F\u7528\u52A8\u6001\u516C\u5171\u6570\u636E"), /* @__PURE__ */ import_react2.default.createElement(
|
|
2372
|
+
AdaptiveNumberControl,
|
|
2373
|
+
{
|
|
2374
|
+
field: ADAPTIVE_NUMBER_FIELDS.find((field2) => field2.key === "dynamicDataTtlMinutes"),
|
|
2375
|
+
value: adaptiveSettingValue(value, "dynamicDataTtlMinutes"),
|
|
2376
|
+
writable: settings.writable,
|
|
2377
|
+
onSave: save
|
|
2378
|
+
}
|
|
2379
|
+
), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "liveBenchEndpoint", label: "LiveBench \u516C\u5F00\u6E90", value: adaptiveSettingValue(value, "liveBenchEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "pricingSnapshotEndpoint", label: "\u4EF7\u683C\u5FEB\u7167\u516C\u5F00\u6E90\uFF08\u53EF\u9009\uFF09", value: adaptiveSettingValue(value, "pricingSnapshotEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "LiveBench", source: ledger?.dynamicData?.liveBench }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "\u4EF7\u683C", source: ledger?.dynamicData?.pricing })));
|
|
2380
|
+
}
|
|
2001
2381
|
function CostControlCard({ ledger, settingsScope, onChanged, error }) {
|
|
2002
2382
|
const settings = useSettingsWriter(settingsScope);
|
|
2003
2383
|
const [dailyDraft, setDailyDraft] = import_react2.default.useState("");
|
|
@@ -2036,7 +2416,7 @@ function CostControlCard({ ledger, settingsScope, onChanged, error }) {
|
|
|
2036
2416
|
void set("allowManualReassign", event.target.checked);
|
|
2037
2417
|
} }), "\u5141\u8BB8\u624B\u52A8\u6539\u6D3E\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: value.confirmUnsandboxedCli !== false, disabled: !settings.writable, onChange: (event) => {
|
|
2038
2418
|
void set("confirmUnsandboxedCli", event.target.checked);
|
|
2039
|
-
} }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
|
|
2419
|
+
} }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), /* @__PURE__ */ import_react2.default.createElement(AdaptiveControls, { ledger, settings, onChanged }), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
|
|
2040
2420
|
}
|
|
2041
2421
|
function DagView({ packages, renderNode, label = "\u5B50\u4EFB\u52A1\u4F9D\u8D56\u56FE" }) {
|
|
2042
2422
|
const layers = dagLayers(packages);
|
|
@@ -2058,7 +2438,7 @@ function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
|
|
|
2058
2438
|
const rerun = rerunSupport(run);
|
|
2059
2439
|
const canRerun = rerun.supported && !item.ok && !busy;
|
|
2060
2440
|
const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
|
|
2061
|
-
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(run
|
|
2441
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && item.ran && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
|
|
2062
2442
|
const [provider, model] = target.split("\0");
|
|
2063
2443
|
onRerun(run.id, item.id, { provider, model });
|
|
2064
2444
|
} }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
|
|
@@ -2081,7 +2461,10 @@ function RunHistoryCard({ ledger, routes, onRefresh, onRate, onRerun, busy, erro
|
|
|
2081
2461
|
const runs = ledger?.runs ?? [];
|
|
2082
2462
|
const [openId, setOpenId] = import_react2.default.useState(null);
|
|
2083
2463
|
const current = runs.find((run) => run.id === openId) ?? runs[0];
|
|
2084
|
-
|
|
2464
|
+
const totals = runTotals(current);
|
|
2465
|
+
const prior = priorAttemptTotals(current);
|
|
2466
|
+
const unknownCalls = prior.unknownCalls + [...current?.packages ?? [], ...current?.reviews ?? []].filter((item) => item.ran && item.billing !== "subscription" && !Number.isFinite(item.costUsd)).length;
|
|
2467
|
+
return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u6267\u884C\u8BB0\u5F55" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u67E5\u770B\u6A21\u578B\u5206\u914D\u3001\u9010\u6B65\u7ED3\u679C\u4E0E\u8D39\u7528\u3002\u5931\u8D25\u6B65\u9AA4\u53EF\u91CD\u8DD1\u6216\u6539\u6D3E\uFF1B\u5DF2\u5B8C\u6210\u7684\u4E0A\u6E38\u4FDD\u6301\u539F\u7ED3\u679C\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: busy, onClick: onRefresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), !ledger && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6267\u884C\u8BB0\u5F55\u2026"), ledger && runs.length === 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty" }, "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55\u3002\u53EF\u5728\u4E0A\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u9884\u89C8\u5E76\u6267\u884C\uFF0C\u6216\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_execute\u3001model_router_team_execute\u3001model_router_tool_run\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u51B3\u7B56\u548C\u7ED3\u679C\u3002"), runs.length > 0 && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-label", htmlFor: "mr-run-select" }, "\u9009\u62E9\u8BB0\u5F55"), /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input", id: "mr-run-select", value: current?.id ?? "", onChange: (event) => setOpenId(event.target.value) }, runs.map((run) => /* @__PURE__ */ import_react2.default.createElement("option", { key: run.id, value: run.id }, new Date(run.createdAt).toLocaleString(), " \xB7 ", RUN_KIND_LABEL[run.kind ?? "assign"] ?? run.kind, " \xB7 ", RUN_STATUS_LABEL[run.status] ?? run.status, " \xB7 ", run.task.slice(0, 40)))), current && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-run" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[current.preset]?.label ?? current.preset, current.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u96BE\u5EA6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, BAND[current.decision?.complexity?.band] ?? "\u2014", current.decision?.complexity?.value !== null && current.decision?.complexity?.value !== void 0 ? ` \xB7 ${current.decision.complexity.value}` : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30 / ", unknownCalls ? "\u5DF2\u77E5\u5B9E\u9645" : "\u5B9E\u9645", "\uFF08\u8BA1\u5165\u9884\u7B97\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, money(current.decision?.estimatedCost), " / ", money(totals.budgetUsd))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u7C7B\u578B"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, RUN_KIND_LABEL[current.kind ?? "assign"] ?? current.kind, current.kind === "team" || current.kind === "tool" ? ` \xB7 ${current.executionMode === "workspace-write" ? "\u53EF\u7F16\u8F91" : "\u53EA\u8BFB"}` : ""))), totals.subscription && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A", money(totals.referenceUsd)), unknownCalls > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u53E6\u6709 ", unknownCalls, " \u6B21\u8C03\u7528\u8D39\u7528\u672A\u77E5\uFF0C\u672A\u8BA1\u5165\u4E0A\u65B9\u91D1\u989D\u3002"), (prior.budgetUsd > 0 || prior.subscriptionRuns > 0 || prior.unknownCalls > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u7D2F\u8BA1\u5305\u542B\u6B64\u524D\u91CD\u8DD1\u5C1D\u8BD5\uFF1AAPI ", money(prior.budgetUsd), " \xB7 \u8BA2\u9605\u53C2\u8003 ", money(prior.referenceUsd), prior.unknownCalls > 0 ? ` \xB7 \u8D39\u7528\u672A\u77E5 ${prior.unknownCalls} \u6B21` : "", "\u3002\u4E0B\u65B9\u8282\u70B9\u663E\u793A\u6700\u8FD1\u4E00\u6B21\u7ED3\u679C\u3002"), current.isolatedWorkspace && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u72EC\u7ACB\u5DE5\u4F5C\u533A\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, current.isolatedWorkspace)), current.rerunOf && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u91CD\u65B0\u6267\u884C\u81EA\u8FD0\u884C ", current.rerunOf.slice(0, 8), "\u3002"), current.decision?.reason && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8DEF\u7531\u539F\u56E0\uFF1A", current.decision.reason), /* @__PURE__ */ import_react2.default.createElement(DagView, { packages: current.packages, renderNode: (item) => /* @__PURE__ */ import_react2.default.createElement(RunNode, { run: current, item, routes, allowReassign: ledger?.settings?.allowManualReassign !== false, busy, onRate, onRerun }) })))));
|
|
2085
2468
|
}
|
|
2086
2469
|
function BillingCard({ billing, error, onRefresh, refreshing }) {
|
|
2087
2470
|
const rows = billingRows(billing);
|
|
@@ -2104,22 +2487,31 @@ var STATUS_TEXT = Object.freeze({
|
|
|
2104
2487
|
"paused-budget": "\u5DF2\u56E0\u9884\u7B97\u6682\u505C\uFF0C\u672A\u542F\u52A8\u6A21\u578B",
|
|
2105
2488
|
"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"
|
|
2106
2489
|
});
|
|
2107
|
-
function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger, previewRun, startRun, onStarted, disabledReason }) {
|
|
2490
|
+
function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger, previewRun, startRun, onStarted, disabledReason, planningRevision }) {
|
|
2108
2491
|
const [preset, setPreset] = import_react3.default.useState(defaultPreset || "balanced");
|
|
2109
2492
|
const lastWorkspace = [...ledger?.runs ?? []].map((run) => run.workspace).find(Boolean) ?? "";
|
|
2110
2493
|
const [workspace, setWorkspace] = import_react3.default.useState("");
|
|
2111
2494
|
const [phase, setPhase] = import_react3.default.useState({ kind: "idle" });
|
|
2112
2495
|
const mounted = import_react3.default.useRef(true);
|
|
2113
2496
|
const confirmRef = import_react3.default.useRef(null);
|
|
2114
|
-
import_react3.default.
|
|
2115
|
-
|
|
2497
|
+
const pendingRequest = import_react3.default.useRef(0);
|
|
2498
|
+
const inputSignature = JSON.stringify([task, mode, directRoute?.provider, directRoute?.model, budgetUsd, preset, workspace, lastWorkspace, planningRevision, disabledReason]);
|
|
2499
|
+
const latestSignature = import_react3.default.useRef(inputSignature);
|
|
2500
|
+
latestSignature.current = inputSignature;
|
|
2501
|
+
import_react3.default.useEffect(() => {
|
|
2502
|
+
mounted.current = true;
|
|
2503
|
+
return () => {
|
|
2504
|
+
mounted.current = false;
|
|
2505
|
+
pendingRequest.current += 1;
|
|
2506
|
+
};
|
|
2116
2507
|
}, []);
|
|
2117
2508
|
import_react3.default.useEffect(() => {
|
|
2118
2509
|
setPreset(defaultPreset || "balanced");
|
|
2119
2510
|
}, [defaultPreset]);
|
|
2120
2511
|
import_react3.default.useEffect(() => {
|
|
2121
|
-
|
|
2122
|
-
|
|
2512
|
+
pendingRequest.current += 1;
|
|
2513
|
+
setPhase((previous) => ["previewing", "preview", "error"].includes(previous.kind) ? { kind: "idle" } : previous);
|
|
2514
|
+
}, [inputSignature]);
|
|
2123
2515
|
import_react3.default.useEffect(() => {
|
|
2124
2516
|
if (phase.kind === "preview") confirmRef.current?.focus();
|
|
2125
2517
|
}, [phase.kind]);
|
|
@@ -2128,22 +2520,29 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
2128
2520
|
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" : "");
|
|
2129
2521
|
const busy = phase.kind === "previewing" || phase.kind === "running";
|
|
2130
2522
|
const preview = async () => {
|
|
2523
|
+
if (blocked || busy) return;
|
|
2524
|
+
const current = ++pendingRequest.current;
|
|
2525
|
+
const snapshot = request();
|
|
2526
|
+
const signature2 = inputSignature;
|
|
2131
2527
|
setPhase({ kind: "previewing" });
|
|
2132
2528
|
try {
|
|
2133
|
-
const value = unwrapRemote(await previewRun(
|
|
2134
|
-
if (mounted.current) setPhase({ kind: "preview", value });
|
|
2529
|
+
const value = unwrapRemote(await previewRun(snapshot), "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002");
|
|
2530
|
+
if (mounted.current && current === pendingRequest.current && signature2 === latestSignature.current) setPhase({ kind: "preview", value, request: snapshot, signature: signature2 });
|
|
2135
2531
|
} catch (error) {
|
|
2136
|
-
if (mounted.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002" });
|
|
2532
|
+
if (mounted.current && current === pendingRequest.current && signature2 === latestSignature.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002" });
|
|
2137
2533
|
}
|
|
2138
2534
|
};
|
|
2139
2535
|
const confirm2 = async () => {
|
|
2536
|
+
if (phase.kind !== "preview" || phase.signature !== latestSignature.current) return;
|
|
2140
2537
|
const shown = phase.value;
|
|
2141
|
-
|
|
2538
|
+
const snapshot = phase.request;
|
|
2539
|
+
const signature2 = phase.signature;
|
|
2540
|
+
setPhase({ kind: "running", value: shown, request: snapshot, signature: signature2 });
|
|
2142
2541
|
try {
|
|
2143
|
-
const value = unwrapRemote(await startRun({ ...
|
|
2542
|
+
const value = unwrapRemote(await startRun({ ...snapshot, confirmedReasons: (shown.reasons ?? []).map((item) => item.code) }), "\u6267\u884C\u5931\u8D25\u3002");
|
|
2144
2543
|
if (!mounted.current) return;
|
|
2145
2544
|
if (value.status === "needs-confirmation") {
|
|
2146
|
-
setPhase({ kind: "preview", value, changed: true });
|
|
2545
|
+
setPhase(signature2 === latestSignature.current ? { kind: "preview", value, request: snapshot, signature: signature2, changed: true } : { kind: "idle" });
|
|
2147
2546
|
return;
|
|
2148
2547
|
}
|
|
2149
2548
|
setPhase({ kind: "done", value });
|
|
@@ -2166,7 +2565,7 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
|
|
|
2166
2565
|
},
|
|
2167
2566
|
onCancel: () => setPhase({ kind: "idle" })
|
|
2168
2567
|
}
|
|
2169
|
-
), phase.kind === "done" && /* @__PURE__ */ import_react3.default.createElement("div", { className: phase.value.status === "failed" || phase.value.status?.startsWith("paused") ? "mr-error" : "mr-empty", role: "status" }, STATUS_TEXT[phase.value.status] ?? `\u72B6\u6001\uFF1A${phase.value.status}`, phase.value.runId ? `\uFF1B\u7ED3\u679C\u5DF2\u8BB0\u5F55\uFF08\u8FD0\u884C ${phase.value.runId.slice(0, 8)}\uFF09\uFF0C\u89C1\u4E0B\u65B9\u201C\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1\u201D\u3002` : "\u3002", phase.value.budget?.message ? ` ${phase.value.budget.exceeded && phase.value.status !== "paused-budget" ? "\u5DF2\u6309\u4F60\u7684\u786E\u8BA4\u8D85\u9884\u7B97\u6267\u884C\uFF1A" : ""}${phase.value.budget.message}` : "")));
|
|
2568
|
+
), phase.kind === "done" && /* @__PURE__ */ import_react3.default.createElement("div", { className: phase.value.status === "failed" || phase.value.status === "partial" || phase.value.status?.startsWith("paused") ? "mr-error" : "mr-empty", role: "status" }, STATUS_TEXT[phase.value.status] ?? `\u72B6\u6001\uFF1A${phase.value.status}`, phase.value.runId ? `\uFF1B\u7ED3\u679C\u5DF2\u8BB0\u5F55\uFF08\u8FD0\u884C ${phase.value.runId.slice(0, 8)}\uFF09\uFF0C\u89C1\u4E0B\u65B9\u201C\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1\u201D\u3002` : "\u3002", phase.value.budget?.message ? ` ${phase.value.budget.exceeded && phase.value.status !== "paused-budget" ? "\u5DF2\u6309\u4F60\u7684\u786E\u8BA4\u8D85\u9884\u7B97\u6267\u884C\uFF1A" : ""}${phase.value.budget.message}` : "")));
|
|
2170
2569
|
}
|
|
2171
2570
|
function LaunchPreview({ value, changed, running, confirmRef, onConfirm, onCancel }) {
|
|
2172
2571
|
const packages = value.decision?.packages ?? [];
|
|
@@ -11604,7 +12003,7 @@ var xterm_default = `/**
|
|
|
11604
12003
|
`;
|
|
11605
12004
|
|
|
11606
12005
|
// .dsh-plugin/client/host-version.mjs
|
|
11607
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
12006
|
+
var ROUTER_CLIENT_VERSION = true ? "0.16.0" : "";
|
|
11608
12007
|
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";
|
|
11609
12008
|
function isMissingRemoteMethod(message) {
|
|
11610
12009
|
const value = String(message ?? "");
|
|
@@ -12101,62 +12500,64 @@ function CliTerminalCard({ api, health }) {
|
|
|
12101
12500
|
|
|
12102
12501
|
// .dsh-plugin/client/router-main.css
|
|
12103
12502
|
var router_main_default = `.mr-workspace {
|
|
12104
|
-
--mr-card:
|
|
12105
|
-
--mr-ink: #
|
|
12106
|
-
--mr-muted: #
|
|
12107
|
-
--mr-line:
|
|
12108
|
-
--mr-accent: #
|
|
12503
|
+
--mr-card: #fff;
|
|
12504
|
+
--mr-ink: #1e2c3e;
|
|
12505
|
+
--mr-muted: #586b80;
|
|
12506
|
+
--mr-line: #dce4ed;
|
|
12507
|
+
--mr-accent: #2859c5;
|
|
12109
12508
|
--mr-soft: #edf3ff;
|
|
12509
|
+
--mr-surface: #f3f6fa;
|
|
12510
|
+
--mr-button-ink: #fff;
|
|
12511
|
+
container: mr-workspace / inline-size;
|
|
12110
12512
|
box-sizing: border-box;
|
|
12111
12513
|
width: 100%;
|
|
12112
12514
|
height: 100%;
|
|
12113
12515
|
min-height: 0;
|
|
12114
12516
|
overflow-y: auto;
|
|
12115
|
-
background:
|
|
12116
|
-
backdrop-filter: blur(18px);
|
|
12517
|
+
background: var(--mr-surface);
|
|
12117
12518
|
color: var(--mr-ink);
|
|
12118
12519
|
font-family: inherit;
|
|
12119
12520
|
}
|
|
12120
12521
|
.mr-workspace *, .mr-workspace *::before, .mr-workspace *::after { box-sizing: border-box; }
|
|
12121
|
-
.mr-shell { width: min(
|
|
12122
|
-
.mr-header { display: flex; flex-wrap: wrap; gap: 20px; align-items:
|
|
12522
|
+
.mr-shell { width: min(1320px, 100%); margin: 0 auto; padding: 24px 32px 48px; }
|
|
12523
|
+
.mr-header { display: flex; flex-wrap: wrap; gap: 20px; align-items: center; justify-content: space-between; margin-bottom: 18px; }
|
|
12123
12524
|
.mr-eyebrow { margin: 0 0 8px; color: var(--mr-accent); font-size: 11px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase; }
|
|
12124
|
-
.mr-title { margin: 0; font-size: clamp(25px, 3vw,
|
|
12525
|
+
.mr-title { margin: 0; font-size: clamp(25px, 3vw, 30px); letter-spacing: -.035em; line-height: 1.3; }
|
|
12125
12526
|
.mr-subtitle { margin: 10px 0 0; color: var(--mr-muted); font-size: 14px; line-height: 1.65; }
|
|
12126
12527
|
.mr-status { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid var(--mr-line); border-radius: 999px; background: var(--mr-card); color: var(--mr-muted); font-size: 12px; white-space: nowrap; }
|
|
12127
12528
|
.mr-status-dot { width: 7px; height: 7px; border-radius: 50%; background: #2cba83; }
|
|
12128
12529
|
.mr-status-dot.loading { background: #e9a640; }
|
|
12129
12530
|
.mr-status-dot.error { background: #d95360; }
|
|
12130
|
-
.mr-grid { display: grid; grid-template-columns: minmax(0, 1.
|
|
12131
|
-
.mr-card { min-width: 0; border: 1px solid var(--mr-line); border-radius:
|
|
12531
|
+
.mr-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(280px, .85fr); gap: 20px; align-items: start; }
|
|
12532
|
+
.mr-card { min-width: 0; border: 1px solid var(--mr-line); border-radius: 14px; background: var(--mr-card); box-shadow: 0 3px 12px rgba(25, 45, 76, .025); }
|
|
12132
12533
|
.mr-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 20px 22px 0; }
|
|
12133
|
-
.mr-card-title { margin: 0; font-size:
|
|
12534
|
+
.mr-card-title { margin: 0; font-size: 17px; font-weight: 700; line-height: 1.5; }
|
|
12134
12535
|
.mr-card-copy { margin: 5px 0 0; color: var(--mr-muted); font-size: 12px; line-height: 1.55; }
|
|
12135
12536
|
.mr-card-body { padding: 18px 22px 22px; }
|
|
12136
12537
|
.mr-label { display: block; margin: 0 0 8px; font-size: 12px; font-weight: 700; }
|
|
12137
12538
|
.mr-textarea, .mr-input { width: 100%; border: 1px solid var(--mr-line); border-radius: 11px; background: #fff; color: var(--mr-ink); font: inherit; outline: none; }
|
|
12138
|
-
.mr-textarea { min-height:
|
|
12539
|
+
.mr-textarea { min-height: 150px; padding: 13px 14px; resize: vertical; line-height: 1.7; font-size: 14px; }
|
|
12139
12540
|
.mr-input { min-height: 38px; padding: 8px 11px; font-size: 13px; }
|
|
12140
12541
|
.mr-textarea:focus, .mr-input:focus { border-color: var(--mr-accent); box-shadow: 0 0 0 3px rgba(49, 92, 200, .13); }
|
|
12141
12542
|
.mr-controls { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 14px; margin-top: 17px; }
|
|
12142
|
-
.mr-control-group { display: flex; flex-direction: column; gap: 7px; }
|
|
12143
|
-
.mr-control-label { color: var(--mr-muted); font-size:
|
|
12543
|
+
.mr-control-group { display: flex; flex-direction: column; gap: 7px; min-width: 0; max-width: 100%; }
|
|
12544
|
+
.mr-control-label { color: var(--mr-muted); font-size: 12px; font-weight: 650; }
|
|
12144
12545
|
.mr-segment { display: inline-flex; padding: 3px; border-radius: 10px; background: #edf1f7; }
|
|
12145
12546
|
.mr-segment button { border: 0; border-radius: 8px; padding: 8px 12px; background: transparent; color: var(--mr-muted); font: inherit; font-size: 12px; cursor: pointer; }
|
|
12146
12547
|
.mr-segment button[aria-pressed='true'] { background: #fff; color: var(--mr-ink); box-shadow: 0 2px 8px rgba(20, 35, 56, .1); font-weight: 700; }
|
|
12147
12548
|
.mr-budget { width: 140px; }
|
|
12148
12549
|
.mr-direct { min-width: min(100%, 280px); }
|
|
12149
12550
|
.mr-actions { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; margin-top: 18px; }
|
|
12150
|
-
.mr-button { border: 1px solid transparent; border-radius:
|
|
12551
|
+
.mr-button { border: 1px solid transparent; border-radius: 9px; min-height: 38px; padding: 8px 14px; background: var(--mr-accent); color: var(--mr-button-ink); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }
|
|
12151
12552
|
.mr-button:hover:not(:disabled) { filter: brightness(.94); }
|
|
12152
12553
|
.mr-button:disabled { cursor: not-allowed; opacity: .5; }
|
|
12153
12554
|
.mr-button-secondary { border-color: var(--mr-line); background: #fff; color: var(--mr-ink); }
|
|
12154
|
-
.mr-caption { color: var(--mr-muted); font-size:
|
|
12155
|
-
.mr-search { margin-top:
|
|
12555
|
+
.mr-caption { color: var(--mr-muted); font-size: 12px; line-height: 1.65; overflow-wrap: anywhere; }
|
|
12556
|
+
.mr-search { margin-top: 0; }
|
|
12156
12557
|
.mr-list { display: grid; gap: 8px; margin-top: 13px; max-height: 395px; overflow-y: auto; }
|
|
12157
12558
|
.mr-route { display: flex; justify-content: space-between; gap: 10px; padding: 10px 11px; border: 1px solid var(--mr-line); border-radius: 10px; background: #f9fbfe; }
|
|
12158
|
-
.mr-route-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size:
|
|
12159
|
-
.mr-route-provider { margin-top:
|
|
12559
|
+
.mr-route-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 700; }
|
|
12560
|
+
.mr-route-provider { margin-top: 4px; color: var(--mr-muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
12160
12561
|
.mr-pill { align-self: start; flex: none; padding: 3px 7px; border-radius: 7px; background: var(--mr-soft); color: var(--mr-accent); font-size: 10px; font-weight: 700; }
|
|
12161
12562
|
.mr-empty, .mr-error { padding: 14px; border-radius: 10px; background: #f4f6fa; color: var(--mr-muted); font-size: 12px; line-height: 1.6; }
|
|
12162
12563
|
.mr-error { background: #fff0f1; color: #a52d3c; }
|
|
@@ -12171,12 +12572,12 @@ var router_main_default = `.mr-workspace {
|
|
|
12171
12572
|
.mr-package-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; align-items: center; }
|
|
12172
12573
|
.mr-package-name { font-size: 12px; font-weight: 750; }
|
|
12173
12574
|
.mr-package-route { color: var(--mr-accent); font-size: 11px; font-weight: 700; }
|
|
12174
|
-
.mr-package-copy { margin: 7px 0 0; color: var(--mr-muted); font-size:
|
|
12575
|
+
.mr-package-copy { margin: 7px 0 0; color: var(--mr-muted); font-size: 12px; line-height: 1.65; overflow-wrap: anywhere; }
|
|
12175
12576
|
.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; }
|
|
12176
12577
|
.mr-notice code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; }
|
|
12177
12578
|
@media (max-width: 850px) { .mr-grid { grid-template-columns: 1fr; } .mr-shell { padding: 24px 18px 48px; } }
|
|
12178
12579
|
@media (prefers-color-scheme: dark) {
|
|
12179
|
-
.mr-workspace { --mr-card:
|
|
12580
|
+
.mr-workspace { --mr-card: #1e2633; --mr-ink: #ecf2ff; --mr-muted: #aebbd0; --mr-line: #354154; --mr-accent: #a1baff; --mr-soft: #2b3959; --mr-surface: #141b26; --mr-button-ink: #17243b; color-scheme: dark; }
|
|
12180
12581
|
.mr-textarea, .mr-input, .mr-segment button[aria-pressed='true'], .mr-button-secondary { background: #273245; color: var(--mr-ink); }
|
|
12181
12582
|
.mr-segment, .mr-empty, .mr-metric { background: #222d3e; }
|
|
12182
12583
|
.mr-route, .mr-package { background: #222d3e; }
|
|
@@ -12295,11 +12696,96 @@ var router_main_default = `.mr-workspace {
|
|
|
12295
12696
|
.mr-term-history { margin-top: 14px; font-size: 12px; }
|
|
12296
12697
|
.mr-term-table { width: 100%; border-collapse: collapse; margin-top: 6px; }
|
|
12297
12698
|
.mr-term-table th, .mr-term-table td { padding: 4px 6px; border-bottom: 1px solid rgba(127, 127, 127, .25); text-align: left; vertical-align: top; max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
12699
|
+
|
|
12700
|
+
/* Workspace navigation keeps every panel mounted, including running terminals. */
|
|
12701
|
+
.mr-view[hidden] { display: none !important; }
|
|
12702
|
+
.mr-view { min-width: 0; }
|
|
12703
|
+
.mr-stack { display: grid; gap: 20px; }
|
|
12704
|
+
.mr-stack > .mr-card, .mr-model-grid > .mr-card { margin: 0; }
|
|
12705
|
+
.mr-overview { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--mr-line); background: var(--mr-card); border-radius: 14px; overflow: hidden; margin-bottom: 16px; }
|
|
12706
|
+
.mr-overview-item { display: grid; align-content: start; gap: 4px; min-width: 0; padding: 12px 22px; border: 0; text-align: left; background: transparent; color: var(--mr-ink); font: inherit; cursor: pointer; }
|
|
12707
|
+
.mr-overview-item + .mr-overview-item { border-left: 1px solid var(--mr-line); }
|
|
12708
|
+
.mr-overview-item:hover { background: var(--mr-soft); }
|
|
12709
|
+
.mr-overview-label { color: var(--mr-muted); font-size: 12px; }
|
|
12710
|
+
.mr-overview-item strong { font-size: 25px; font-weight: 650; line-height: 1.3; font-variant-numeric: tabular-nums; }
|
|
12711
|
+
.mr-overview-item small { color: var(--mr-muted); font-size: 14px; font-weight: 400; }
|
|
12712
|
+
.mr-overview-detail { color: var(--mr-muted); font-size: 11px; line-height: 1.5; }
|
|
12713
|
+
.mr-workspace-tabs { display: flex; gap: 6px; position: sticky; top: 0; z-index: 5; background: var(--mr-surface); padding: 10px 0; margin-bottom: 14px; border-bottom: 1px solid var(--mr-line); }
|
|
12714
|
+
.mr-workspace-tabs button { display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 44px; padding: 10px 18px; border: 1px solid transparent; border-radius: 9px; color: var(--mr-muted); background: transparent; font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
|
|
12715
|
+
.mr-workspace-tabs button:hover { background: var(--mr-card); color: var(--mr-ink); }
|
|
12716
|
+
.mr-workspace-tabs button[aria-selected='true'] { background: var(--mr-card); border-color: var(--mr-line); color: var(--mr-accent); box-shadow: 0 2px 4px rgba(25, 45, 76, .04); }
|
|
12717
|
+
.mr-tab-number { font-size: 10px; font-weight: 500; opacity: .7; font-variant-numeric: tabular-nums; }
|
|
12718
|
+
.mr-view-heading { margin: 4px 0 20px; }
|
|
12719
|
+
.mr-stack > .mr-view-heading { margin-bottom: 0; }
|
|
12720
|
+
.mr-view-heading h2 { margin: 0; font-size: 20px; }
|
|
12721
|
+
.mr-view-heading p { margin: 7px 0 0; color: var(--mr-muted); font-size: 13px; line-height: 1.6; }
|
|
12722
|
+
.mr-planning-grid { grid-template-columns: minmax(0, 1fr) 290px; }
|
|
12723
|
+
.mr-planning-guide { min-width: 0; padding: 20px 4px 4px 8px; }
|
|
12724
|
+
.mr-workflow { display: grid; gap: 24px; margin: 20px 0 24px; padding: 0; list-style: none; }
|
|
12725
|
+
.mr-workflow li { display: flex; align-items: start; gap: 12px; }
|
|
12726
|
+
.mr-workflow li > span { display: grid; place-items: center; flex: 0 0 30px; height: 30px; border: 1px solid var(--mr-line); border-radius: 50%; background: var(--mr-card); color: var(--mr-accent); font-size: 10px; font-weight: 650; }
|
|
12727
|
+
.mr-workflow strong { font-size: 13px; line-height: 30px; }
|
|
12728
|
+
.mr-workflow p { margin: 2px 0 0; color: var(--mr-muted); font-size: 12px; line-height: 1.65; }
|
|
12729
|
+
.mr-guide-links { display: grid; gap: 8px; }
|
|
12730
|
+
.mr-guide-links .mr-button { text-align: left; font-weight: 500; font-size: 12px; }
|
|
12731
|
+
.mr-task-hint { margin: 8px 0 0; }
|
|
12732
|
+
.mr-plan-explanation { margin: 12px 0; padding: 10px 12px; border: 1px solid var(--mr-line); border-radius: 9px; color: var(--mr-muted); font-size: 12px; line-height: 1.65; }
|
|
12733
|
+
.mr-plan-explanation summary, .mr-package-details summary { cursor: pointer; }
|
|
12734
|
+
.mr-package-details summary { line-height: 1.8; }
|
|
12735
|
+
.mr-package-details summary .mr-package-route { display: block; margin-left: 16px; overflow-wrap: anywhere; }
|
|
12736
|
+
.mr-package-details[open] { border-color: var(--mr-accent); }
|
|
12737
|
+
.mr-footer { margin-top: 28px; padding-top: 18px; border-top: 1px solid var(--mr-line); color: var(--mr-muted); font-size: 11px; line-height: 1.8; overflow-wrap: anywhere; }
|
|
12738
|
+
.mr-footer code { font-size: 11px; }
|
|
12739
|
+
.mr-tool-status { flex-wrap: wrap; line-height: 1.6; }
|
|
12740
|
+
.mr-table td { overflow-wrap: anywhere; }
|
|
12741
|
+
.mr-term-cwd { min-width: min(100%, 240px); }
|
|
12742
|
+
|
|
12743
|
+
/* Respond to the Harness panel width, even when a wide window has a sidebar. */
|
|
12744
|
+
@container mr-workspace (max-width: 960px) {
|
|
12745
|
+
.mr-shell { padding: 24px 22px 40px; }
|
|
12746
|
+
.mr-planning-grid { grid-template-columns: minmax(0, 1fr) 240px; }
|
|
12747
|
+
.mr-model-grid { grid-template-columns: 1fr; }
|
|
12748
|
+
.mr-planning-grid .mr-card-head { flex-wrap: wrap; }
|
|
12749
|
+
.mr-profile-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
12750
|
+
}
|
|
12751
|
+
@container mr-workspace (max-width: 680px) {
|
|
12752
|
+
.mr-shell { padding: 20px 14px 32px; }
|
|
12753
|
+
.mr-header { gap: 14px; margin-bottom: 18px; }
|
|
12754
|
+
.mr-subtitle { font-size: 13px; }
|
|
12755
|
+
.mr-overview { margin-bottom: 12px; }
|
|
12756
|
+
.mr-overview-item { padding: 13px 10px; gap: 6px; }
|
|
12757
|
+
.mr-overview-item strong { font-size: 20px; }
|
|
12758
|
+
.mr-overview-detail { font-size: 10px; }
|
|
12759
|
+
.mr-overview-item small { font-size: 11px; }
|
|
12760
|
+
.mr-workspace-tabs { gap: 2px; }
|
|
12761
|
+
.mr-workspace-tabs button { flex: 1; min-width: 0; padding: 9px 4px; font-size: 12px; }
|
|
12762
|
+
.mr-tab-number { display: none; }
|
|
12763
|
+
.mr-grid { grid-template-columns: 1fr; }
|
|
12764
|
+
.mr-planning-guide { padding: 12px 4px 0; }
|
|
12765
|
+
.mr-workflow { gap: 12px; margin: 14px 0; }
|
|
12766
|
+
.mr-guide-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
12767
|
+
.mr-guide-links .mr-button { font-size: 11px; }
|
|
12768
|
+
.mr-card-head { padding: 18px 16px 0; align-items: start; flex-wrap: wrap; }
|
|
12769
|
+
.mr-card-body { padding: 14px 16px 18px; }
|
|
12770
|
+
.mr-profile-grid { grid-template-columns: 1fr; }
|
|
12771
|
+
.mr-tool { align-items: stretch; flex-direction: column; gap: 10px; }
|
|
12772
|
+
.mr-tool-actions { justify-content: flex-start; }
|
|
12773
|
+
.mr-segment { flex-wrap: wrap; max-width: 100%; }
|
|
12774
|
+
.mr-launch-workspace { min-width: 0; }
|
|
12775
|
+
.mr-result-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
12776
|
+
.mr-meters { grid-template-columns: 1fr; }
|
|
12777
|
+
}
|
|
12778
|
+
@media (prefers-reduced-motion: reduce) { .mr-workspace { scroll-behavior: auto; } }
|
|
12298
12779
|
`;
|
|
12299
12780
|
|
|
12300
12781
|
// .dsh-plugin/client/router-main.jsx
|
|
12301
12782
|
var money2 = (value) => value === null || value === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : `$${Number(value).toFixed(4)}`;
|
|
12302
12783
|
var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
12784
|
+
var routingSettingsSignature = (value) => JSON.stringify([
|
|
12785
|
+
value.modelProfilesJson,
|
|
12786
|
+
value.routingPreset,
|
|
12787
|
+
...Object.keys(ADAPTIVE_DEFAULTS).map((key) => value[key] ?? ADAPTIVE_DEFAULTS[key])
|
|
12788
|
+
]);
|
|
12303
12789
|
function RouterPanelIcon({ size = 20, active = false }) {
|
|
12304
12790
|
return /* @__PURE__ */ import_react5.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ import_react5.default.createElement("path", { d: "M7 6.5h7M7 17.5h7M15 6.5v11", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }), /* @__PURE__ */ import_react5.default.createElement("circle", { cx: "5", cy: "6.5", r: "2", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react5.default.createElement("circle", { cx: "5", cy: "17.5", r: "2", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react5.default.createElement("circle", { cx: "17", cy: "12", r: "3", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.7" }));
|
|
12305
12791
|
}
|
|
@@ -12316,10 +12802,12 @@ function ChannelBadge({ item }) {
|
|
|
12316
12802
|
const official = item.executionChannel === "official-cli";
|
|
12317
12803
|
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");
|
|
12318
12804
|
}
|
|
12319
|
-
function PlanResults({ plan, ledger }) {
|
|
12805
|
+
function PlanResults({ plan, ledger, headingRef }) {
|
|
12320
12806
|
const selected = plan.selected;
|
|
12321
12807
|
const budget = planBudget(ledger, plan.estimatedCost);
|
|
12322
|
-
|
|
12808
|
+
const packageNames = new Map((plan.team?.workPackages ?? []).map((item) => [item.id, item.name]));
|
|
12809
|
+
const purposeLabel = { analysis: "\u4EFB\u52A1\u5206\u6790", execution: "\u4EFB\u52A1\u5B9E\u65BD", verification: "\u72EC\u7ACB\u9A8C\u8BC1", synthesis: "\u7ED3\u679C\u6574\u5408" };
|
|
12810
|
+
return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u8DEF\u7531\u5EFA\u8BAE" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title", ref: headingRef, tabIndex: -1 }, "\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u672C\u5730\u8BA1\u7B97\u5B8C\u6210\uFF0C\u672A\u5411\u6A21\u578B\u53D1\u9001\u4EFB\u52A1\u5185\u5BB9\u3002"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u63A8\u8350\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, selected ? `${selected.provider}/${selected.model}` : "\u6682\u65E0\u8DEF\u7EBF")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u4EFB\u52A1\u590D\u6742\u5EA6 \xB7 \u5206\u503C\uFF080\u20131\uFF09"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u590D\u6742" }[plan.complexity.band] || plan.complexity.band, " \xB7 ", plan.complexity.value)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u4F30\u7B97\u603B\u6210\u672C"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, money2(plan.estimatedCost))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[plan.preset]?.label ?? "\u5747\u8861"))), budget?.exceeded && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A", budget.message, " \u5B9E\u9645\u6267\u884C\u65F6\u5C06\u6309\u8BBE\u7F6E\u81EA\u52A8\u964D\u7EA7\u6216\u6682\u505C\u8BE2\u95EE\u3002"), budget?.limited && !budget.exceeded && budget.estimateKnown && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A\u672C\u6B21\u9884\u4F30 ", money2(plan.estimatedCost), "\uFF0C\u5269\u4F59\u989D\u5EA6 ", money2(budget.remainingUsd), "\u3002"), plan.loginRequired && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u63A8\u8350\u6A21\u578B\u7684\u5B98\u65B9 CLI \u672A\u767B\u5F55\uFF0C\u6267\u884C\u65F6\u76F4\u63A5\u8D70\u6A21\u578B\u76EE\u5F55 API\uFF1B\u53EF\u5728\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u5361\u7247\u70B9\u201C\u53BB\u767B\u5F55\u201D\u3002"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-control-label" }, "\u6267\u884C\u6E20\u9053"), /* @__PURE__ */ import_react5.default.createElement(ChannelBadge, { item: plan })), /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-plan-explanation" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u67E5\u770B\u89C4\u5212\u4F9D\u636E\u4E0E\u4F30\u7B97\u8BF4\u660E"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.reason), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.pricingNotice, " ", plan.qualityNotice, " ", plan.availabilityNotice, " ", plan.modalityNotice || "")), plan.optimization.budgetExceeded && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error" }, "\u6309\u5DF2\u63D0\u4F9B\u5355\u4EF7\u4F30\u7B97\uFF0C\u4EFB\u52A1\u53EF\u80FD\u8D85\u8FC7\u672C\u6B21\u9884\u7B97\u3002\u9884\u7B97\u53EA\u5F71\u54CD\u5EFA\u8BAE\uFF0C\u4E0D\u4F1A\u963B\u6B62\u5B9E\u9645\u6263\u8D39\u3002"), plan.mode === "team" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("h3", { className: "mr-section-title" }, "\u56E2\u961F\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u4E0B\u65B9\u6A21\u578B\u662F\u89C4\u5212\u5EFA\u8BAE\uFF1B\u6258\u7BA1\u6267\u884C\u4F1A\u6309\u5382\u5546 CLI \u7684\u6A21\u578B\u540D\u89C4\u5219\u9009\u7528\uFF0C\u672A\u6838\u9A8C\u6620\u5C04\u65F6\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B\u3002"), plan.team.workPackages.length > 1 && /* @__PURE__ */ import_react5.default.createElement(DagView, { packages: plan.team.workPackages, label: "\u5DE5\u4F5C\u5305\u4F9D\u8D56\u56FE", renderNode: (item) => /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel) }), plan.team.workPackages.length === 0 ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-empty" }, "\u5F53\u524D\u76EE\u5F55\u6CA1\u6709\u53EF\u5206\u914D\u7684\u6A21\u578B\u8DEF\u7EBF\u3002") : plan.team.workPackages.map((item, index) => /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-package mr-package-details", key: item.id }, /* @__PURE__ */ import_react5.default.createElement("summary", null, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-package-name" }, index + 1, ". ", item.name), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel)), item.objective && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u5177\u4F53\u76EE\u6807\uFF1A", item.objective), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, purposeLabel[item.purpose] ?? item.purpose, item.dependsOn.length > 0 ? ` \xB7 \u4F9D\u8D56\uFF1A${item.dependsOn.map((id2) => packageNames.get(id2) ?? id2).join("\u3001")}` : ""), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u96BE\u5EA6\uFF1A", { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u56F0\u96BE" }[item.difficulty] || item.difficulty || "\u5F85\u8BC4\u4F30", " \xB7 \u8D39\u7528\uFF1A", money2(item.estimatedCost)), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u9A8C\u6536\uFF1A", item.verificationChecklist.join("\uFF1B")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react5.default.createElement(ChannelBadge, { item }), item.loginRequired && /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-pill" }, "CLI \u672A\u767B\u5F55")), item.channelDetail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u6E20\u9053\u8BF4\u660E\uFF1A", item.channelDetail)))), plan.routingBypassed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u5DF2\u6307\u5B9A\u5355\u4E00\u6A21\u578B\uFF0C\u672A\u4E0E\u5176\u4ED6\u8DEF\u7EBF\u6BD4\u8F83\u3002\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_execute"), " \u5E76\u4F20\u5165\u8BE5 provider \u4E0E model \u5373\u53EF\u76F4\u63A5\u6267\u884C\uFF1B\u82E5\u8BE5\u6A21\u578B\u5141\u8BB8\u5B98\u65B9\u5DE5\u5177\uFF0C\u4F1A\u4F18\u5148\u4F7F\u7528\u5BF9\u5E94 CLI\u3002"), plan.mode === "team" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.team.handoff)));
|
|
12323
12811
|
}
|
|
12324
12812
|
var remoteError = (response, fallback) => text5(response?.error?.message) || text5(response?.value?.error) || fallback;
|
|
12325
12813
|
function probeLabel(probe) {
|
|
@@ -12466,12 +12954,19 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
12466
12954
|
})), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 12 } }, "\u5B89\u88C5\u7531 Host \u6309\u6CE8\u518C\u8868\u56FA\u5B9A\u6765\u6E90\u6267\u884C\uFF0C\u4E0D\u63A5\u53D7\u81EA\u5B9A\u4E49\u5305\u540D\uFF1B\u53EF\u70B9\u201C\u53D6\u6D88\u5B89\u88C5\u201D\u7EC8\u6B62\u4E0B\u8F7D\u4EFB\u52A1\uFF0C\u968F\u540E\u91CD\u65B0\u68C0\u6D4B\u5B9E\u9645\u7248\u672C\u3002ZCode \u5B89\u88C5\u5668\u542F\u52A8\u540E\u4ECD\u9700\u5728\u539F\u5382\u7A97\u53E3\u9009\u62E9\u76EE\u5F55\u5E76\u5B8C\u6210\u5B89\u88C5\u3002Agent \u4E5F\u53EF\u8C03\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_install"), "\uFF0C\u6216\u5728\u4F1A\u8BDD\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "/tools"), "\u3002")));
|
|
12467
12955
|
}
|
|
12468
12956
|
var HEADLESS_TOOLS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini"]);
|
|
12957
|
+
var WORKSPACE_VIEWS = [
|
|
12958
|
+
{ id: "plan", label: "\u4EFB\u52A1\u4E0E\u6267\u884C", number: "01" },
|
|
12959
|
+
{ id: "models", label: "\u6A21\u578B\u914D\u7F6E", number: "02" },
|
|
12960
|
+
{ id: "tools", label: "\u5B98\u65B9\u5DE5\u5177", number: "03" },
|
|
12961
|
+
{ id: "controls", label: "\u9884\u7B97\u4E0E\u5B89\u5168", number: "04" }
|
|
12962
|
+
];
|
|
12469
12963
|
function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries }) {
|
|
12470
12964
|
const [health, setHealth] = import_react5.default.useState({ report: null, error: "", refreshing: false });
|
|
12471
12965
|
const [ledger, setLedger] = import_react5.default.useState({ value: null, error: "" });
|
|
12472
12966
|
const [boundaries, setBoundaries] = import_react5.default.useState({ value: null, error: "" });
|
|
12473
12967
|
const [busy, setBusy] = import_react5.default.useState(false);
|
|
12474
12968
|
const mounted = import_react5.default.useRef(true);
|
|
12969
|
+
const ledgerRequest = import_react5.default.useRef(0);
|
|
12475
12970
|
import_react5.default.useEffect(() => () => {
|
|
12476
12971
|
mounted.current = false;
|
|
12477
12972
|
}, []);
|
|
@@ -12489,11 +12984,15 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
|
|
|
12489
12984
|
}
|
|
12490
12985
|
};
|
|
12491
12986
|
const refreshLedger = async () => {
|
|
12987
|
+
const request = ++ledgerRequest.current;
|
|
12492
12988
|
try {
|
|
12493
12989
|
const value = await call(loadLedger, "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002");
|
|
12494
|
-
if (mounted.current) setLedger({ value, error: "" });
|
|
12990
|
+
if (mounted.current && request === ledgerRequest.current) setLedger({ value, error: "" });
|
|
12991
|
+
if (request !== ledgerRequest.current) return null;
|
|
12992
|
+
return value;
|
|
12495
12993
|
} catch (error) {
|
|
12496
|
-
if (mounted.current) setLedger((previous) => ({ ...previous, error: text5(error?.message) || "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002" }));
|
|
12994
|
+
if (mounted.current && request === ledgerRequest.current) setLedger((previous) => ({ ...previous, error: text5(error?.message) || "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002" }));
|
|
12995
|
+
return null;
|
|
12497
12996
|
}
|
|
12498
12997
|
};
|
|
12499
12998
|
const refreshBoundaries = async () => {
|
|
@@ -12512,10 +13011,10 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
|
|
|
12512
13011
|
if (mounted.current) setHealth((previous) => ({ ...previous, error: text5(error?.message) || "\u65E0\u6CD5\u4FDD\u5B58\u4F53\u68C0\u72B6\u6001\u3002" }));
|
|
12513
13012
|
}
|
|
12514
13013
|
};
|
|
12515
|
-
const rate = async (runId, packageId, rating) => {
|
|
13014
|
+
const rate = async (runId, packageId, rating, expectedFinishedAt) => {
|
|
12516
13015
|
setBusy(true);
|
|
12517
13016
|
try {
|
|
12518
|
-
await call(() => rateResult({ runId, packageId, rating }), "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
13017
|
+
await call(() => rateResult({ runId, packageId, rating, ...expectedFinishedAt === void 0 ? {} : { expectedFinishedAt } }), "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
12519
13018
|
await refreshLedger();
|
|
12520
13019
|
} catch (error) {
|
|
12521
13020
|
if (mounted.current) setLedger((previous) => ({ ...previous, error: text5(error?.message) || "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002" }));
|
|
@@ -12573,14 +13072,43 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12573
13072
|
const [plan, setPlan] = import_react5.default.useState(null);
|
|
12574
13073
|
const [planError, setPlanError] = import_react5.default.useState("");
|
|
12575
13074
|
const [toolProbes, setToolProbes] = import_react5.default.useState(null);
|
|
13075
|
+
const [routingSettings, setRoutingSettings] = import_react5.default.useState(() => {
|
|
13076
|
+
const value = settingsScope.getSnapshot().value ?? {};
|
|
13077
|
+
return routingSettingsSignature(value);
|
|
13078
|
+
});
|
|
13079
|
+
const [view, setView] = import_react5.default.useState("plan");
|
|
13080
|
+
const tabRefs = import_react5.default.useRef({});
|
|
13081
|
+
const resultHeading = import_react5.default.useRef(null);
|
|
12576
13082
|
const budgetEdited = import_react5.default.useRef(false);
|
|
12577
13083
|
const budgetValue = import_react5.default.useRef(budget);
|
|
12578
13084
|
const mounted = import_react5.default.useRef(false);
|
|
12579
13085
|
const catalogRequest = import_react5.default.useRef(0);
|
|
13086
|
+
const generationRequest = import_react5.default.useRef(0);
|
|
13087
|
+
const generationInputs = import_react5.default.useRef("");
|
|
13088
|
+
generationInputs.current = JSON.stringify([task, budget, mode, directKey, routingSettings, catalogState.catalog, toolProbes, workbench.health.report?.tools]);
|
|
13089
|
+
import_react5.default.useEffect(() => {
|
|
13090
|
+
if (plan) resultHeading.current?.focus({ preventScroll: true });
|
|
13091
|
+
}, [plan]);
|
|
13092
|
+
const selectView = (id2) => {
|
|
13093
|
+
setView(id2);
|
|
13094
|
+
tabRefs.current[id2]?.focus({ preventScroll: true });
|
|
13095
|
+
};
|
|
13096
|
+
const navigateTabs = (event, index) => {
|
|
13097
|
+
const next = event.key === "ArrowRight" ? (index + 1) % WORKSPACE_VIEWS.length : event.key === "ArrowLeft" ? (index + WORKSPACE_VIEWS.length - 1) % WORKSPACE_VIEWS.length : event.key === "Home" ? 0 : event.key === "End" ? WORKSPACE_VIEWS.length - 1 : null;
|
|
13098
|
+
if (next === null) return;
|
|
13099
|
+
event.preventDefault();
|
|
13100
|
+
selectView(WORKSPACE_VIEWS[next].id);
|
|
13101
|
+
};
|
|
12580
13102
|
import_react5.default.useEffect(() => {
|
|
12581
13103
|
const syncBudget = () => {
|
|
13104
|
+
const value = settingsScope.getSnapshot().value ?? {};
|
|
13105
|
+
const signature2 = routingSettingsSignature(value);
|
|
13106
|
+
setRoutingSettings((previous) => {
|
|
13107
|
+
if (previous === signature2) return previous;
|
|
13108
|
+
return signature2;
|
|
13109
|
+
});
|
|
12582
13110
|
if (budgetEdited.current) return;
|
|
12583
|
-
const next = String(
|
|
13111
|
+
const next = String(value.budgetUsd ?? 0);
|
|
12584
13112
|
if (next !== budgetValue.current) {
|
|
12585
13113
|
budgetValue.current = next;
|
|
12586
13114
|
setBudget(next);
|
|
@@ -12591,6 +13119,18 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12591
13119
|
syncBudget();
|
|
12592
13120
|
return settingsScope.subscribe(syncBudget);
|
|
12593
13121
|
}, [settingsScope]);
|
|
13122
|
+
import_react5.default.useEffect(() => {
|
|
13123
|
+
setPlan(null);
|
|
13124
|
+
setPlanError("");
|
|
13125
|
+
}, [routingSettings]);
|
|
13126
|
+
const dataRevision = workbench.ledger.value?.dynamicData?.revision ?? "";
|
|
13127
|
+
const feedbackRevision = workbench.ledger.value?.learning?.revision ?? "";
|
|
13128
|
+
import_react5.default.useEffect(() => {
|
|
13129
|
+
if (plan && plan.workbenchRevision !== `${dataRevision}/${feedbackRevision}`) {
|
|
13130
|
+
setPlan(null);
|
|
13131
|
+
setPlanError("");
|
|
13132
|
+
}
|
|
13133
|
+
}, [dataRevision, feedbackRevision, plan]);
|
|
12594
13134
|
import_react5.default.useEffect(() => {
|
|
12595
13135
|
mounted.current = true;
|
|
12596
13136
|
const request = ++catalogRequest.current;
|
|
@@ -12622,15 +13162,19 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12622
13162
|
}
|
|
12623
13163
|
};
|
|
12624
13164
|
const invalidatePlan = () => {
|
|
13165
|
+
generationRequest.current += 1;
|
|
12625
13166
|
setPlan(null);
|
|
12626
13167
|
setPlanError("");
|
|
12627
13168
|
};
|
|
12628
13169
|
const handleToolProbes = import_react5.default.useCallback((snapshot) => {
|
|
13170
|
+
generationRequest.current += 1;
|
|
12629
13171
|
setToolProbes(snapshot);
|
|
12630
13172
|
setPlan(null);
|
|
12631
13173
|
setPlanError("");
|
|
12632
13174
|
}, []);
|
|
12633
|
-
const generate = () => {
|
|
13175
|
+
const generate = async () => {
|
|
13176
|
+
const request = ++generationRequest.current;
|
|
13177
|
+
const inputs = generationInputs.current;
|
|
12634
13178
|
setPlanError("");
|
|
12635
13179
|
try {
|
|
12636
13180
|
if (!text5(task)) throw new Error("\u8BF7\u5148\u63CF\u8FF0\u4EFB\u52A1\u3002");
|
|
@@ -12639,7 +13183,14 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12639
13183
|
if (!Number.isFinite(parsedBudget) || parsedBudget < 0) throw new Error("\u9884\u7B97\u5FC5\u987B\u662F\u4E0D\u5C0F\u4E8E 0 \u7684\u6570\u5B57\u3002");
|
|
12640
13184
|
const direct = mode === "direct" ? routes.find((route) => `${route.provider}/${route.model}` === directKey) ?? routes[0] : null;
|
|
12641
13185
|
if (mode === "direct" && !direct) throw new Error("\u8BF7\u9009\u62E9\u8981\u76F4\u63A5\u4F7F\u7528\u7684\u6A21\u578B\u3002");
|
|
12642
|
-
|
|
13186
|
+
const signature2 = routingSettingsSignature(settingsScope.getSnapshot().value ?? {});
|
|
13187
|
+
const ledger = await workbench.refreshLedger();
|
|
13188
|
+
if (request !== generationRequest.current || inputs !== generationInputs.current || !mounted.current) return;
|
|
13189
|
+
if (!ledger) throw new Error("\u8BF7\u5148\u6062\u590D\u6267\u884C\u8BB0\u5F55\u8FDE\u63A5\uFF1B\u65E0\u6CD5\u6838\u5BF9\u6700\u65B0\u6570\u636E\u4E0E\u5B66\u4E60\u72B6\u6001\u3002");
|
|
13190
|
+
if (signature2 !== routingSettingsSignature(settingsScope.getSnapshot().value ?? {})) throw new Error("\u89C4\u5212\u8BBE\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\u3002");
|
|
13191
|
+
const next = createWorkspacePlan(task, catalogState.catalog, {
|
|
13192
|
+
...ledger.routingData,
|
|
13193
|
+
learning: ledger.learning,
|
|
12643
13194
|
mode,
|
|
12644
13195
|
...direct ? { directProvider: direct.provider, directModel: direct.model } : {},
|
|
12645
13196
|
budgetUsd: parsedBudget,
|
|
@@ -12647,42 +13198,22 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12647
13198
|
installedToolIds: (toolProbes?.probes ?? []).filter((probe) => probe.installed).map((probe) => probe.id),
|
|
12648
13199
|
runnableToolIds: (toolProbes?.readiness ?? []).filter((item) => item.ready).map((item) => item.id),
|
|
12649
13200
|
preset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
|
|
12650
|
-
qualityBiases: workbench.ledger.value?.biases ?? null,
|
|
12651
13201
|
loggedOutToolIds: (workbench.health.report?.tools ?? []).filter((item) => item.installed && item.login?.state === "logged-out").map((item) => item.id)
|
|
12652
|
-
})
|
|
13202
|
+
});
|
|
13203
|
+
setPlan({ ...next, workbenchRevision: `${ledger.dynamicData?.revision ?? ""}/${ledger.learning?.revision ?? ""}` });
|
|
12653
13204
|
} catch (error) {
|
|
13205
|
+
if (request !== generationRequest.current || inputs !== generationInputs.current || !mounted.current) return;
|
|
12654
13206
|
setPlan(null);
|
|
12655
13207
|
setPlanError(text5(error?.message) || "\u65E0\u6CD5\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE\u3002");
|
|
12656
13208
|
}
|
|
12657
13209
|
};
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
error: workbench.health.error,
|
|
12663
|
-
refreshing: workbench.health.refreshing,
|
|
12664
|
-
onRefresh: () => {
|
|
12665
|
-
void workbench.refreshHealth(true);
|
|
12666
|
-
},
|
|
12667
|
-
onDone: () => {
|
|
12668
|
-
void workbench.finishOnboarding();
|
|
12669
|
-
}
|
|
12670
|
-
}
|
|
12671
|
-
), /* @__PURE__ */ import_react5.default.createElement(
|
|
12672
|
-
CostControlCard,
|
|
12673
|
-
{
|
|
12674
|
-
ledger: workbench.ledger.value,
|
|
12675
|
-
error: workbench.ledger.error && !workbench.ledger.value ? workbench.ledger.error : "",
|
|
12676
|
-
settingsScope,
|
|
12677
|
-
onChanged: () => {
|
|
12678
|
-
invalidatePlan();
|
|
12679
|
-
void workbench.refreshLedger();
|
|
12680
|
-
}
|
|
12681
|
-
}
|
|
12682
|
-
), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-grid" }, /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u4EFB\u52A1\u89C4\u5212" }, /* @__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" }, "\u4EFB\u52A1\u89C4\u5212"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u201C\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE\u201D\u5728\u672C\u673A\u5B8C\u6210\uFF0C\u4E0D\u4F1A\u542F\u52A8\u6A21\u578B\uFF1B\u8981\u5B9E\u9645\u6267\u884C\uFF0C\u8BF7\u5728\u4E0B\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u9884\u89C8\u5E76\u786E\u8BA4\u3002"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-label", htmlFor: "mr-task" }, "\u4EFB\u52A1\u63CF\u8FF0"), /* @__PURE__ */ import_react5.default.createElement("textarea", { className: "mr-textarea", id: "mr-task", value: task, onChange: (event) => {
|
|
13210
|
+
const summary = healthSummary(workbench.health.report?.tools);
|
|
13211
|
+
return /* @__PURE__ */ import_react5.default.createElement("main", { className: "mr-workspace" }, /* @__PURE__ */ import_react5.default.createElement("style", null, router_main_default), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-shell" }, /* @__PURE__ */ import_react5.default.createElement("header", { className: "mr-header" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-eyebrow" }, "Model Router \xB7 DeepSeek Harness"), /* @__PURE__ */ import_react5.default.createElement("h1", { className: "mr-title" }, "\u6A21\u578B\u8DEF\u7531\u5DE5\u4F5C\u53F0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-subtitle" }, "\u628A\u4EFB\u52A1\u4EA4\u7ED9\u5408\u9002\u7684\u6A21\u578B\u3002\u4ECE\u672C\u5730\u89C4\u5212\uFF0C\u5230\u53EF\u786E\u8BA4\u7684\u6267\u884C\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-status-dot ${catalogState.status === "loading" ? "loading" : catalogState.status === "error" ? "error" : ""}` }), catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 ${routes.length} \u6761\u8DEF\u7EBF` : catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55" : "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-overview", "aria-label": "\u5DE5\u4F5C\u53F0\u6982\u89C8" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("models") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("strong", null, catalogState.status === "ready" ? routes.length : "\u2014"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 \u914D\u7F6E\u4EF7\u683C\u4E0E\u80FD\u529B \u2192` : "\u7B49\u5F85\u76EE\u5F55\u52A0\u8F7D")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("tools") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("strong", null, workbench.health.report ? summary.installed : "\u2014", /* @__PURE__ */ import_react5.default.createElement("small", null, " / ", OFFICIAL_TOOLS.length)), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, workbench.health.report ? `${summary.ready} \u4E2A\u5DF2\u767B\u5F55 \xB7 \u67E5\u770B\u4F53\u68C0 \u2192` : "\u67E5\u770B\u5B89\u88C5\u4E0E\u767B\u5F55\u72B6\u6001 \u2192")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("controls") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u4ECA\u65E5 API \u8D39\u7528"), /* @__PURE__ */ import_react5.default.createElement("strong", null, workbench.ledger.value ? money2(workbench.ledger.value.spent?.today ?? 0) : "\u2014"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, "\u672C\u673A\u8BB0\u5F55\u4F30\u7B97 \xB7 \u67E5\u770B\u9884\u7B97 \u2192"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-workspace-tabs", role: "tablist", "aria-label": "\u5DE5\u4F5C\u53F0\u529F\u80FD" }, WORKSPACE_VIEWS.map((item, index) => /* @__PURE__ */ import_react5.default.createElement("button", { key: item.id, ref: (element) => {
|
|
13212
|
+
tabRefs.current[item.id] = element;
|
|
13213
|
+
}, type: "button", role: "tab", id: `mr-tab-${item.id}`, "aria-selected": view === item.id, "aria-controls": `mr-panel-${item.id}`, tabIndex: view === item.id ? 0 : -1, onKeyDown: (event) => navigateTabs(event, index), onClick: () => setView(item.id) }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-tab-number", "aria-hidden": "true" }, item.number), item.label))), staleHostNotice({ hostVersion: toolProbes?.hostVersion, loaded: Boolean(toolProbes?.probes?.length) }) && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-error", role: "alert" }, staleHostNotice({ hostVersion: toolProbes?.hostVersion })), (workbench.health.report?.notices ?? []).map((notice) => /* @__PURE__ */ import_react5.default.createElement("div", { key: `${notice.kind}-${notice.at}`, className: "mr-error", role: "alert" }, notice.message)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-plan", "aria-labelledby": "mr-tab-plan", hidden: view !== "plan" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-grid mr-planning-grid" }, /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u4EFB\u52A1\u89C4\u5212" }, /* @__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" }, "\u4EFB\u52A1\u89C4\u5212"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u5199\u6E05\u76EE\u6807\u4E0E\u9A8C\u6536\u6807\u51C6\uFF0C\u5148\u751F\u6210\u672C\u5730\u5EFA\u8BAE\uFF0C\u518D\u9884\u89C8\u6267\u884C\u3002")), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-pill" }, "\u672C\u5730\u89C4\u5212 \xB7 \u4E0D\u6D88\u8017 token")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-label", htmlFor: "mr-task" }, "\u4EFB\u52A1\u63CF\u8FF0"), /* @__PURE__ */ import_react5.default.createElement("textarea", { className: "mr-textarea", id: "mr-task", value: task, onChange: (event) => {
|
|
12683
13214
|
setTask(event.target.value);
|
|
12684
13215
|
invalidatePlan();
|
|
12685
|
-
}, placeholder: "\u4F8B\u5982\uFF1A\u5206\u6790\u9879\u76EE\u67B6\u6784\uFF0C\u5206\u5DE5\u4FEE\u590D\u5173\u952E\u95EE\u9898\uFF0C\u5E76\u7ED9\u51FA\u9A8C\u6536\u6E05\u5355" }), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-control-label" }, "\u89C4\u5212\u6A21\u5F0F"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u89C4\u5212\u6A21\u5F0F" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-pressed": mode === "single", onClick: () => {
|
|
13216
|
+
}, placeholder: "\u4F8B\u5982\uFF1A\u5206\u6790\u9879\u76EE\u67B6\u6784\uFF0C\u5206\u5DE5\u4FEE\u590D\u5173\u952E\u95EE\u9898\uFF0C\u5E76\u7ED9\u51FA\u9A8C\u6536\u6E05\u5355", "aria-describedby": "mr-task-hint" }), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-task-hint", id: "mr-task-hint" }, "\u56E2\u961F\u4EFB\u52A1\u53EF\u6309\u7F16\u53F7\u5199\u51FA\u6B65\u9AA4\u3001\u4EA4\u4ED8\u7269\u548C\u4F9D\u8D56\uFF1B\u89C4\u5212\u4E0D\u4F1A\u66F4\u6539\u4E3B\u4F1A\u8BDD\u6A21\u578B\u3002"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-control-label" }, "\u89C4\u5212\u6A21\u5F0F"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u89C4\u5212\u6A21\u5F0F" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-pressed": mode === "single", onClick: () => {
|
|
12686
13217
|
setMode("single");
|
|
12687
13218
|
invalidatePlan();
|
|
12688
13219
|
} }, "\u5355\u4EFB\u52A1"), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-pressed": mode === "team", onClick: () => {
|
|
@@ -12699,7 +13230,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12699
13230
|
budgetValue.current = event.target.value;
|
|
12700
13231
|
setBudget(event.target.value);
|
|
12701
13232
|
invalidatePlan();
|
|
12702
|
-
} }))), /* @__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" },
|
|
13233
|
+
} }))), /* @__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\u6267\u884C\u53EF\u5728\u6B64\u5B8C\u6210\uFF1B\u4FEE\u6539\u6587\u4EF6\u7684\u4EFB\u52A1\u9700\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u5BA1\u6279\u3002"))), plan && /* @__PURE__ */ import_react5.default.createElement(PlanResults, { plan, ledger: workbench.ledger.value, headingRef: resultHeading }), /* @__PURE__ */ import_react5.default.createElement(
|
|
12703
13234
|
RunLauncher,
|
|
12704
13235
|
{
|
|
12705
13236
|
task,
|
|
@@ -12708,9 +13239,10 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12708
13239
|
ledger: workbench.ledger.value,
|
|
12709
13240
|
previewRun,
|
|
12710
13241
|
startRun,
|
|
13242
|
+
planningRevision: `${routingSettings}/${dataRevision}/${feedbackRevision}`,
|
|
12711
13243
|
directRoute: mode === "direct" ? routes.find((route) => `${route.provider}/${route.model}` === directKey) ?? routes[0] ?? null : null,
|
|
12712
13244
|
defaultPreset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
|
|
12713
|
-
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\
|
|
13245
|
+
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" : "",
|
|
12714
13246
|
onStarted: () => {
|
|
12715
13247
|
void workbench.refreshLedger();
|
|
12716
13248
|
}
|
|
@@ -12725,13 +13257,26 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12725
13257
|
onRefresh: () => {
|
|
12726
13258
|
void workbench.refreshLedger();
|
|
12727
13259
|
},
|
|
12728
|
-
onRate: (runId, packageId, rating) => {
|
|
12729
|
-
void workbench.rate(runId, packageId, rating);
|
|
13260
|
+
onRate: (runId, packageId, rating, expectedFinishedAt) => {
|
|
13261
|
+
void workbench.rate(runId, packageId, rating, expectedFinishedAt);
|
|
12730
13262
|
},
|
|
12731
13263
|
onRerun: (runId, packageId, override, choice) => {
|
|
12732
13264
|
void workbench.rerun(runId, packageId, override, choice);
|
|
12733
13265
|
}
|
|
12734
13266
|
}
|
|
13267
|
+
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view", role: "tabpanel", id: "mr-panel-models", "aria-labelledby": "mr-tab-models", hidden: view !== "models" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u6A21\u578B\u914D\u7F6E"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u4ECE\u5B98\u65B9\u76EE\u5F55\u9009\u62E9\u8DEF\u7EBF\uFF0C\u8865\u9F50\u6BD4\u8F83\u6240\u9700\u7684\u4EF7\u683C\u3001\u80FD\u529B\u4E0E\u6267\u884C\u65B9\u5F0F\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-grid mr-model-grid" }, /* @__PURE__ */ import_react5.default.createElement(ModelProfileEditor, { routes, settingsScope, onSaved: invalidatePlan }), /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u6A21\u578B\u76EE\u5F55" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title" }, "\u6A21\u578B\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, routes.length, " \u6761\u8DEF\u7EBF \xB7 \u53EA\u8BFB\u53D6\u5B98\u65B9\u76EE\u5F55\uFF0C\u4E0D\u8BFB\u53D6 API Key\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: catalogState.status === "loading", onClick: refresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, catalogState.status === "error" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-error", role: "alert" }, catalogState.error), catalogState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-empty" }, "\u6B63\u5728\u52A0\u8F7D\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u2026"), catalogState.status === "ready" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-label", htmlFor: "mr-model-search" }, "\u641C\u7D22\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("input", { className: "mr-input mr-search", id: "mr-model-search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: "\u6A21\u578B\u6216\u4F9B\u5E94\u5546" }), /* @__PURE__ */ import_react5.default.createElement(RouteList, { routes, query }), catalogState.catalog?.failures?.length > 0 && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, catalogState.catalog.failures.length, " \u4E2A\u4F9B\u5E94\u5546\u7684\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u9875\u68C0\u67E5\u914D\u7F6E\u3002")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 13 } }, "\u76EE\u5F55\u767B\u8BB0\u4E0D\u4EE3\u8868\u51ED\u636E\u6216\u7F51\u7EDC\u5F53\u524D\u53EF\u7528\uFF1B\u56FE\u50CF\u80FD\u529B\u9700\u8981\u5728\u5B9E\u9645\u4F7F\u7528\u524D\u6838\u5BF9\u3002"))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-tools", "aria-labelledby": "mr-tab-tools", hidden: view !== "tools" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u7BA1\u7406\u672C\u673A CLI\u3001\u68C0\u67E5\u767B\u5F55\u72B6\u6001\uFF0C\u6216\u6253\u5F00\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\u3002")), workbench.health.report && !workbench.health.report.onboarding?.completedAt && /* @__PURE__ */ import_react5.default.createElement(
|
|
13268
|
+
OnboardingBanner,
|
|
13269
|
+
{
|
|
13270
|
+
health: workbench.health.report,
|
|
13271
|
+
error: workbench.health.error,
|
|
13272
|
+
refreshing: workbench.health.refreshing,
|
|
13273
|
+
onRefresh: () => {
|
|
13274
|
+
void workbench.refreshHealth(true);
|
|
13275
|
+
},
|
|
13276
|
+
onDone: () => {
|
|
13277
|
+
void workbench.finishOnboarding();
|
|
13278
|
+
}
|
|
13279
|
+
}
|
|
12735
13280
|
), /* @__PURE__ */ import_react5.default.createElement(
|
|
12736
13281
|
OfficialToolsCard,
|
|
12737
13282
|
{
|
|
@@ -12745,7 +13290,18 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12745
13290
|
void workbench.refreshHealth(true);
|
|
12746
13291
|
}
|
|
12747
13292
|
}
|
|
12748
|
-
), terminalApi && /* @__PURE__ */ import_react5.default.createElement(CliTerminalCard, { api: terminalApi, health: workbench.health.report }), /* @__PURE__ */ import_react5.default.createElement(
|
|
13293
|
+
), terminalApi && /* @__PURE__ */ import_react5.default.createElement(CliTerminalCard, { api: terminalApi, health: workbench.health.report })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-controls", "aria-labelledby": "mr-tab-controls", hidden: view !== "controls" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u9884\u7B97\u4E0E\u5B89\u5168"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u8BBE\u7F6E\u6210\u672C\u4E0E\u8D28\u91CF\u7B56\u7565\uFF0C\u6838\u5BF9\u8BA2\u9605\u8BA1\u8D39\u548C\u6267\u884C\u8FB9\u754C\u3002")), /* @__PURE__ */ import_react5.default.createElement(
|
|
13294
|
+
CostControlCard,
|
|
13295
|
+
{
|
|
13296
|
+
ledger: workbench.ledger.value,
|
|
13297
|
+
error: workbench.ledger.error && !workbench.ledger.value ? workbench.ledger.error : "",
|
|
13298
|
+
settingsScope,
|
|
13299
|
+
onChanged: () => {
|
|
13300
|
+
invalidatePlan();
|
|
13301
|
+
void workbench.refreshLedger();
|
|
13302
|
+
}
|
|
13303
|
+
}
|
|
13304
|
+
), /* @__PURE__ */ import_react5.default.createElement(
|
|
12749
13305
|
BillingCard,
|
|
12750
13306
|
{
|
|
12751
13307
|
billing: workbench.health.report?.billing ?? null,
|
|
@@ -12757,7 +13313,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
12757
13313
|
}
|
|
12758
13314
|
), /* @__PURE__ */ import_react5.default.createElement(SecurityCard, { data: workbench.boundaries.value, error: workbench.boundaries.error, onRefresh: () => {
|
|
12759
13315
|
void workbench.refreshBoundaries();
|
|
12760
|
-
} }), /* @__PURE__ */ import_react5.default.createElement("
|
|
13316
|
+
} })), /* @__PURE__ */ import_react5.default.createElement("footer", { className: "mr-footer" }, "\u4E3B\u4F1A\u8BDD\u6A21\u578B\u7531 Harness \u7BA1\u7406\u3002\u66F4\u591A\u8BBE\u7F6E\uFF1A\u63D2\u4EF6 \u2192 \u5DF2\u5B89\u88C5 \u2192 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "@ljwei-stak/dsh-model-router"), "\u3002")));
|
|
12761
13317
|
}
|
|
12762
13318
|
|
|
12763
13319
|
// .dsh-plugin/shared/official-tools-remote.mjs
|
|
@@ -12814,7 +13370,13 @@ var optionalRouteText = (value, subject) => {
|
|
|
12814
13370
|
var rateRequestCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#RateRequest`, (value) => {
|
|
12815
13371
|
const request = plainObject2(value, "rate request");
|
|
12816
13372
|
if (!["up", "down", "clear"].includes(request.rating)) throw new TypeError("rating must be up, down or clear");
|
|
12817
|
-
|
|
13373
|
+
if (request.expectedFinishedAt !== void 0 && (!Number.isFinite(request.expectedFinishedAt) || request.expectedFinishedAt < 0)) throw new TypeError("expectedFinishedAt must be a non-negative timestamp");
|
|
13374
|
+
return {
|
|
13375
|
+
runId: idText(request.runId, "runId"),
|
|
13376
|
+
packageId: idText(request.packageId, "packageId"),
|
|
13377
|
+
rating: request.rating,
|
|
13378
|
+
...request.expectedFinishedAt === void 0 ? {} : { expectedFinishedAt: request.expectedFinishedAt }
|
|
13379
|
+
};
|
|
12818
13380
|
});
|
|
12819
13381
|
var rerunRequestCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#RerunRequest`, (value) => {
|
|
12820
13382
|
const request = plainObject2(value, "rerun request");
|