dsh-hypatia-auto-memory 1.1.1 → 2.0.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/README.md +53 -14
- package/README.zh-CN.md +39 -12
- package/lib/client.js +289 -10
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/src/cascade.js +39 -19
- package/src/client/SettingsCard.module.css +83 -0
- package/src/client/SettingsCard.tsx +160 -15
- package/src/client/consolidation-models.ts +151 -1
- package/src/client/locales.ts +26 -4
- package/src/config.js +20 -3
- package/src/consolidator.js +130 -86
- package/src/index.js +14 -6
- package/src/model-log.js +64 -15
- package/src/reasoning.js +209 -0
- package/src/writer.js +7 -3
package/lib/client.js
CHANGED
|
@@ -13,6 +13,108 @@ window.__ModuleLoader__.load({
|
|
|
13
13
|
return `${route.provider}\0${route.model}`;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
+
* Move one entry of the priority list, returning a new array.
|
|
17
|
+
*
|
|
18
|
+
* The stored `consolidation.models` array IS the priority order, so this is the
|
|
19
|
+
* only thing a reorder has to do: reorder the array. `to` is clamped instead of
|
|
20
|
+
* rejected, so a click that cannot move anything (the first row's "up") is a
|
|
21
|
+
* no-op rather than an error. A no-op returns the ORIGINAL reference, which lets
|
|
22
|
+
* a caller use identity to skip the state update.
|
|
23
|
+
*
|
|
24
|
+
* @param models - Priority-ordered routes; not mutated.
|
|
25
|
+
* @param from - Index to move.
|
|
26
|
+
* @param to - Target index, clamped into `models`.
|
|
27
|
+
*/
|
|
28
|
+
function moveConsolidationModel(models, from, to) {
|
|
29
|
+
if (!Number.isInteger(from) || from < 0 || from >= models.length) return models;
|
|
30
|
+
if (!Number.isFinite(to)) return models;
|
|
31
|
+
const target = Math.min(Math.max(0, Math.trunc(to)), models.length - 1);
|
|
32
|
+
if (target === from) return models;
|
|
33
|
+
const next = [...models];
|
|
34
|
+
const [moved] = next.splice(from, 1);
|
|
35
|
+
next.splice(target, 0, moved);
|
|
36
|
+
return next;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The stored routes in their configured (priority) order, each resolved to its
|
|
40
|
+
* catalog entry for a display name, an availability flag and the reasoning
|
|
41
|
+
* levels the route declares.
|
|
42
|
+
*
|
|
43
|
+
* `consolidationModelCandidates` already guarantees every stored route appears —
|
|
44
|
+
* taken from the catalog, or appended as unavailable — so the candidate list is
|
|
45
|
+
* a lookup table for this. A route that somehow is not in it is still shown,
|
|
46
|
+
* named by its raw ids and marked unavailable, because dropping it from the
|
|
47
|
+
* priority list would hide a configured route from the only UI that can remove
|
|
48
|
+
* it.
|
|
49
|
+
*
|
|
50
|
+
* `reasoningEffort` is taken from the STORED route, never from the catalog: the
|
|
51
|
+
* catalog describes what a model can do, the stored route is what the user chose.
|
|
52
|
+
*/
|
|
53
|
+
function orderedConsolidationModels(stored, candidates) {
|
|
54
|
+
const byKey = new Map(candidates.map((candidate) => [candidate.key, candidate]));
|
|
55
|
+
return stored.map((route) => {
|
|
56
|
+
const key = consolidationModelKey(route);
|
|
57
|
+
return {
|
|
58
|
+
...byKey.get(key) ?? {
|
|
59
|
+
...route,
|
|
60
|
+
key,
|
|
61
|
+
providerName: route.provider,
|
|
62
|
+
modelName: route.model,
|
|
63
|
+
available: false,
|
|
64
|
+
selected: true
|
|
65
|
+
},
|
|
66
|
+
reasoningEffort: route.reasoningEffort
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The thinking-level options for one route, in the order they are offered.
|
|
72
|
+
*
|
|
73
|
+
* Two rules, both about not inventing a vocabulary this plugin does not own:
|
|
74
|
+
*
|
|
75
|
+
* - The list comes from the route's own declared `efforts`, in the adapter's
|
|
76
|
+
* preferred order, labelled with the adapter's own names. Nothing is
|
|
77
|
+
* hard-coded — the ids are opaque, and a level one adapter accepts is not one
|
|
78
|
+
* another does.
|
|
79
|
+
* - "Follow the purpose policy" (`undefined`) is always first and is what an
|
|
80
|
+
* absent field stores. It is NOT the same as the adapter's `defaultEffort`:
|
|
81
|
+
* omitting the field lets the plugin's own per-purpose policy apply, which for
|
|
82
|
+
* extraction and adjudication means asking for no reasoning at all.
|
|
83
|
+
*
|
|
84
|
+
* A stored value the route no longer declares is appended and flagged rather
|
|
85
|
+
* than dropped, so the card can show what is actually configured instead of
|
|
86
|
+
* silently rewriting it — and so a route whose catalog entry disappeared still
|
|
87
|
+
* displays its setting.
|
|
88
|
+
*
|
|
89
|
+
* @param reasoning - The route's catalog metadata; absent when the catalog does
|
|
90
|
+
* not advertise the route, or the model declares no reasoning control.
|
|
91
|
+
* @param stored - The configured value, if any.
|
|
92
|
+
*/
|
|
93
|
+
function reasoningEffortChoices(reasoning, stored) {
|
|
94
|
+
const efforts = Array.isArray(reasoning?.efforts) ? reasoning.efforts : [];
|
|
95
|
+
const choices = [{
|
|
96
|
+
key: "purpose",
|
|
97
|
+
effort: void 0
|
|
98
|
+
}];
|
|
99
|
+
for (const effort of efforts) {
|
|
100
|
+
const id = typeof effort?.id === "string" ? effort.id : "";
|
|
101
|
+
if (id === "") continue;
|
|
102
|
+
const name = typeof effort.name === "string" && effort.name !== "" ? effort.name : id;
|
|
103
|
+
choices.push({
|
|
104
|
+
key: `effort:${id}`,
|
|
105
|
+
effort: id,
|
|
106
|
+
name
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const value = typeof stored === "string" ? stored.trim() : "";
|
|
110
|
+
if (value !== "" && !efforts.some((effort) => effort?.id === value)) choices.push({
|
|
111
|
+
key: `stale:${value}`,
|
|
112
|
+
effort: value,
|
|
113
|
+
stale: true
|
|
114
|
+
});
|
|
115
|
+
return choices;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
16
118
|
* Join the live model directory with selected routes that disappeared from it.
|
|
17
119
|
* Disappeared routes remain visible so users can remove them deliberately.
|
|
18
120
|
*/
|
|
@@ -31,7 +133,8 @@ window.__ModuleLoader__.load({
|
|
|
31
133
|
providerName: group.name,
|
|
32
134
|
modelName: model.name,
|
|
33
135
|
available: true,
|
|
34
|
-
selected: selected.has(key)
|
|
136
|
+
selected: selected.has(key),
|
|
137
|
+
...model.reasoning === void 0 ? {} : { reasoning: model.reasoning }
|
|
35
138
|
};
|
|
36
139
|
}));
|
|
37
140
|
for (const route of storedByKey.values()) {
|
|
@@ -73,7 +176,7 @@ window.__ModuleLoader__.load({
|
|
|
73
176
|
}
|
|
74
177
|
//#endregion
|
|
75
178
|
//#region \0dsh-hypatia-css:/home/runner/work/dsh-hypatia-auto-memory/dsh-hypatia-auto-memory/src/client/SettingsCard.module.css.mjs
|
|
76
|
-
const css$1 = ".YVNYya_card{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-2);border-radius:16px}.YVNYya_header{align-items:center;gap:12px;padding:14px 16px;display:flex}.YVNYya_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.YVNYya_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.YVNYya_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.YVNYya_pending{corner-shape:round;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.YVNYya_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint,.YVNYya_error{margin:0;font-size:12px;line-height:1.5}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint{color:var(--dsw-alias-label-tertiary)}.YVNYya_status{padding:12px 16px}.YVNYya_readOnly{padding-top:12px}.YVNYya_field{gap:6px;padding:12px 0;display:grid}.YVNYya_body>.YVNYya_field+.YVNYya_group,.YVNYya_body>.YVNYya_group+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_group{padding:12px 0}.YVNYya_groupTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle{border-top:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);margin:16px 0 0;padding-top:12px;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle+.YVNYya_hint{margin-top:4px}.YVNYya_group>.YVNYya_field:first-of-type{padding-top:12px}.YVNYya_group>.YVNYya_field+.YVNYya_field,.YVNYya_pairedFields{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_fieldHead{align-items:center;gap:8px;display:flex}.YVNYya_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_reset{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:1.5}.YVNYya_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.YVNYya_reset:disabled{cursor:default}.YVNYya_input{box-sizing:border-box;width:100%;min-width:0;display:flex}.YVNYya_select{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);width:100%;min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;background:0 0;border-radius:8px;padding:0 8px;font-size:13px}.YVNYya_select:disabled{opacity:.5}.YVNYya_select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_warning{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.YVNYya_pairedFields{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:4px 0;padding:4px 0;display:grid}.YVNYya_pairedFields .YVNYya_field{min-width:0}.YVNYya_switch{box-sizing:border-box;background:var(--dsw-alias-border-l3);cursor:pointer;border:0;border-radius:10px;width:36px;height:20px;padding:2px;position:relative}.YVNYya_switchOn{background:var(--dsw-alias-brand-primary)}.YVNYya_switch:disabled{cursor:default;opacity:.5}.YVNYya_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_switchThumb{corner-shape:round;background:var(--dsw-alias-label-primary-foreground);border-radius:50%;width:16px;height:16px;transition:transform .12s;display:block}.YVNYya_switchOn .YVNYya_switchThumb{transform:translate(16px)}.YVNYya_modelSelection{gap:10px;padding:12px 0;display:grid}.YVNYya_notice{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.YVNYya_catalogError{color:var(--dsw-alias-label-error);justify-content:space-between;align-items:center;gap:12px;font-size:12px;line-height:1.5;display:flex}.YVNYya_catalogError button{color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0}.YVNYya_models{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.YVNYya_models legend{color:var(--dsw-alias-label-secondary);padding:0 4px;font-size:12px}.YVNYya_modelGroup{gap:6px;display:grid}.YVNYya_modelGroup+.YVNYya_modelGroup{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}.YVNYya_providerName{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.YVNYya_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.YVNYya_model:hover{background:var(--dsw-alias-bg-layer-4)}.YVNYya_modelName,.YVNYya_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.YVNYya_modelName{color:var(--dsw-alias-label-primary);font-size:13px}.YVNYya_route{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px}.YVNYya_unavailable{color:var(--dsw-alias-label-tertiary);font-size:11px}.YVNYya_error{color:var(--dsw-alias-label-error)}.YVNYya_advancedHint{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.YVNYya_footer{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}@media (width<=480px){.YVNYya_pairedFields{grid-template-columns:minmax(0,1fr);gap:0}.YVNYya_pairedFields .YVNYya_field+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}}";
|
|
179
|
+
const css$1 = ".YVNYya_card{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-2);border-radius:16px}.YVNYya_header{align-items:center;gap:12px;padding:14px 16px;display:flex}.YVNYya_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.YVNYya_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.YVNYya_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.YVNYya_pending{corner-shape:round;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.YVNYya_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint,.YVNYya_error{margin:0;font-size:12px;line-height:1.5}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint{color:var(--dsw-alias-label-tertiary)}.YVNYya_status{padding:12px 16px}.YVNYya_readOnly{padding-top:12px}.YVNYya_field{gap:6px;padding:12px 0;display:grid}.YVNYya_body>.YVNYya_field+.YVNYya_group,.YVNYya_body>.YVNYya_group+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_group{padding:12px 0}.YVNYya_groupTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle{border-top:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);margin:16px 0 0;padding-top:12px;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle+.YVNYya_hint{margin-top:4px}.YVNYya_group>.YVNYya_field:first-of-type{padding-top:12px}.YVNYya_group>.YVNYya_field+.YVNYya_field,.YVNYya_pairedFields{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_fieldHead{align-items:center;gap:8px;display:flex}.YVNYya_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_reset{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:1.5}.YVNYya_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.YVNYya_reset:disabled{cursor:default}.YVNYya_input{box-sizing:border-box;width:100%;min-width:0;display:flex}.YVNYya_select{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);width:100%;min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;background:0 0;border-radius:8px;padding:0 8px;font-size:13px}.YVNYya_select:disabled{opacity:.5}.YVNYya_select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_warning{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.YVNYya_pairedFields{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:4px 0;padding:4px 0;display:grid}.YVNYya_pairedFields .YVNYya_field{min-width:0}.YVNYya_switch{box-sizing:border-box;background:var(--dsw-alias-border-l3);cursor:pointer;border:0;border-radius:10px;width:36px;height:20px;padding:2px;position:relative}.YVNYya_switchOn{background:var(--dsw-alias-brand-primary)}.YVNYya_switch:disabled{cursor:default;opacity:.5}.YVNYya_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_switchThumb{corner-shape:round;background:var(--dsw-alias-label-primary-foreground);border-radius:50%;width:16px;height:16px;transition:transform .12s;display:block}.YVNYya_switchOn .YVNYya_switchThumb{transform:translate(16px)}.YVNYya_modelSelection{gap:10px;padding:12px 0;display:grid}.YVNYya_notice{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.YVNYya_catalogError{color:var(--dsw-alias-label-error);justify-content:space-between;align-items:center;gap:12px;font-size:12px;line-height:1.5;display:flex}.YVNYya_catalogError button{color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0}.YVNYya_models{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.YVNYya_models legend{color:var(--dsw-alias-label-secondary);padding:0 4px;font-size:12px}.YVNYya_modelGroup{gap:6px;display:grid}.YVNYya_modelGroup+.YVNYya_modelGroup{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}.YVNYya_providerName{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.YVNYya_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.YVNYya_model:hover{background:var(--dsw-alias-bg-layer-4)}.YVNYya_selectedRow{border-radius:6px;align-items:center;gap:8px;min-width:0;padding:6px;display:flex}.YVNYya_selectedRow:hover{background:var(--dsw-alias-bg-layer-4)}.YVNYya_order{min-width:16px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;text-align:right;font-size:11px}.YVNYya_selectedText{flex:auto;min-width:0}.YVNYya_effort{border:.5px solid var(--dsw-alias-border-l4);max-width:132px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border-radius:5px;flex:none;padding:2px 4px;font-size:12px}.YVNYya_effort:disabled{cursor:default;opacity:.5}.YVNYya_effort:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.YVNYya_rowActions{align-items:center;gap:2px;display:flex}.YVNYya_move{border:.5px solid var(--dsw-alias-border-l4);width:22px;height:22px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border-radius:5px;padding:0;font-size:12px;line-height:1}.YVNYya_move:hover:not(:disabled){background:var(--dsw-alias-bg-layer-4);color:var(--dsw-alias-label-primary)}.YVNYya_move:disabled{cursor:default;opacity:.4}.YVNYya_modelName,.YVNYya_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.YVNYya_modelName{color:var(--dsw-alias-label-primary);font-size:13px}.YVNYya_route{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px}.YVNYya_unavailable{color:var(--dsw-alias-label-tertiary);font-size:11px}.YVNYya_error{color:var(--dsw-alias-label-error)}.YVNYya_advancedHint{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.YVNYya_footer{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}@media (width<=480px){.YVNYya_pairedFields{grid-template-columns:minmax(0,1fr);gap:0}.YVNYya_pairedFields .YVNYya_field+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}}";
|
|
77
180
|
const tagId$1 = "dsh-hypatia-auto-memory/SettingsCard.module.css";
|
|
78
181
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
79
182
|
const tag = document.createElement("style");
|
|
@@ -88,6 +191,7 @@ window.__ModuleLoader__.load({
|
|
|
88
191
|
"card": "YVNYya_card",
|
|
89
192
|
"catalogError": "YVNYya_catalogError",
|
|
90
193
|
"description": "YVNYya_description",
|
|
194
|
+
"effort": "YVNYya_effort",
|
|
91
195
|
"error": "YVNYya_error",
|
|
92
196
|
"field": "YVNYya_field",
|
|
93
197
|
"fieldHead": "YVNYya_fieldHead",
|
|
@@ -105,15 +209,20 @@ window.__ModuleLoader__.load({
|
|
|
105
209
|
"modelName": "YVNYya_modelName",
|
|
106
210
|
"modelSelection": "YVNYya_modelSelection",
|
|
107
211
|
"models": "YVNYya_models",
|
|
212
|
+
"move": "YVNYya_move",
|
|
108
213
|
"name": "YVNYya_name",
|
|
109
214
|
"notice": "YVNYya_notice",
|
|
215
|
+
"order": "YVNYya_order",
|
|
110
216
|
"pairedFields": "YVNYya_pairedFields",
|
|
111
217
|
"pending": "YVNYya_pending",
|
|
112
218
|
"providerName": "YVNYya_providerName",
|
|
113
219
|
"readOnly": "YVNYya_readOnly",
|
|
114
220
|
"reset": "YVNYya_reset",
|
|
115
221
|
"route": "YVNYya_route",
|
|
222
|
+
"rowActions": "YVNYya_rowActions",
|
|
116
223
|
"select": "YVNYya_select",
|
|
224
|
+
"selectedRow": "YVNYya_selectedRow",
|
|
225
|
+
"selectedText": "YVNYya_selectedText",
|
|
117
226
|
"status": "YVNYya_status",
|
|
118
227
|
"switch": "YVNYya_switch",
|
|
119
228
|
"switchOn": "YVNYya_switchOn",
|
|
@@ -146,14 +255,25 @@ window.__ModuleLoader__.load({
|
|
|
146
255
|
shelfDisconnectedWarning: "shelf {shelf} 已注册但未连接,写入会失败。",
|
|
147
256
|
shelfNotListedWarning: "hypatia 没有注册 shelf {shelf},写入会失败;请先执行 hypatia connect <目录> --name {shelf}。",
|
|
148
257
|
consolidationTitle: "整合候选模型",
|
|
149
|
-
modelSelectionHint: "
|
|
258
|
+
modelSelectionHint: "选择一个或多个模型并决定优先级。列表自上而下即优先级:每次整合先用最上面那条,该次尝试失败时,重试会依次降级到下一条(可用的备选条数受队列重试次数限制)。未选择时只记录对话,不执行整合。",
|
|
150
259
|
modelCatalogLoading: "正在读取可用模型…",
|
|
151
260
|
modelCatalogFailed: "无法读取可用模型。",
|
|
152
261
|
modelCatalogPartial: "部分提供方未能返回模型目录。",
|
|
153
262
|
modelCatalogEmpty: "当前没有可选择的模型。",
|
|
154
|
-
selectedModels: "
|
|
263
|
+
selectedModels: "优先级顺序(自上而下)",
|
|
264
|
+
selectedModelsEmpty: "还没有选择模型。",
|
|
265
|
+
availableModels: "可选模型",
|
|
155
266
|
unavailableModels: "不可用或未再声明的模型",
|
|
156
267
|
modelUnavailable: "当前不可用",
|
|
268
|
+
moveUp: "上移",
|
|
269
|
+
moveDown: "下移",
|
|
270
|
+
remove: "移除",
|
|
271
|
+
reasoningEffort: "思考程度",
|
|
272
|
+
reasoningFollowPurpose: "跟随用途策略",
|
|
273
|
+
reasoningUnavailable: "该路由未声明思考档位,无法设置",
|
|
274
|
+
reasoningStale: "该路由已不再声明",
|
|
275
|
+
reasoningDefault: "未指定时该路由默认为:{effort}",
|
|
276
|
+
reasoningBudgetHint: "思考程度决定该模型思考多久。选「跟随用途策略」时,摘要与裁决会尽量关闭思考(两者都是机械变换,思考只花掉输出预算),归档则沿用模型自己的默认档位。显式选了档位就会覆盖上述策略;非关闭档位与正文共用输出预算,插件会自动追加余量,但高强度档位仍建议同步调大输出预算。档位由模型自己声明,未声明的值会在调用时被忽略并记一条警告。",
|
|
157
277
|
retry: "重试",
|
|
158
278
|
checkEveryTurns: "两次整合至少间隔 N 轮",
|
|
159
279
|
minNewTokens: "最小新增 token 数",
|
|
@@ -235,14 +355,25 @@ window.__ModuleLoader__.load({
|
|
|
235
355
|
shelfDisconnectedWarning: "Shelf {shelf} is registered but not connected; writes will fail.",
|
|
236
356
|
shelfNotListedWarning: "hypatia has no shelf named {shelf}; writes will fail until you run hypatia connect <dir> --name {shelf}.",
|
|
237
357
|
consolidationTitle: "Consolidation candidate models",
|
|
238
|
-
modelSelectionHint: "Choose one or more models.
|
|
358
|
+
modelSelectionHint: "Choose one or more models and set their priority. The list is read top-down: every consolidation starts on the first route, and each failed attempt degrades to the next one (how many fallbacks a task can reach is bounded by the queue's retry limit). Without a selection, conversations continue logging but consolidation stays idle.",
|
|
239
359
|
modelCatalogLoading: "Loading available models…",
|
|
240
360
|
modelCatalogFailed: "Unable to load available models.",
|
|
241
361
|
modelCatalogPartial: "Some providers did not return a model catalog.",
|
|
242
362
|
modelCatalogEmpty: "No models are currently available.",
|
|
243
|
-
selectedModels: "
|
|
363
|
+
selectedModels: "Priority order (top first)",
|
|
364
|
+
selectedModelsEmpty: "No model selected yet.",
|
|
365
|
+
availableModels: "Available models",
|
|
244
366
|
unavailableModels: "Unavailable or no longer advertised",
|
|
245
367
|
modelUnavailable: "Unavailable",
|
|
368
|
+
moveUp: "Move up",
|
|
369
|
+
moveDown: "Move down",
|
|
370
|
+
remove: "Remove",
|
|
371
|
+
reasoningEffort: "Reasoning effort",
|
|
372
|
+
reasoningFollowPurpose: "Follow the purpose policy",
|
|
373
|
+
reasoningUnavailable: "This route declares no reasoning levels",
|
|
374
|
+
reasoningStale: "no longer declared by this route",
|
|
375
|
+
reasoningDefault: "Without one, this route defaults to: {effort}",
|
|
376
|
+
reasoningBudgetHint: "Reasoning effort is how long the model may think. On \"follow the purpose policy\", summaries and adjudication ask for no reasoning where the route allows it — both are mechanical transforms, so thinking only spends the output budget — while the archive call keeps the model's own default. Choosing a level explicitly overrides that policy; any level other than off shares the output budget with the answer, so the plugin adds its thinking allowance, and a high level is still worth pairing with a larger output budget. Levels are declared by the model itself, and one it does not declare is dropped at call time with a warning.",
|
|
246
377
|
retry: "Retry",
|
|
247
378
|
checkEveryTurns: "Minimum turns between consolidations",
|
|
248
379
|
minNewTokens: "Min new tokens",
|
|
@@ -447,6 +578,7 @@ window.__ModuleLoader__.load({
|
|
|
447
578
|
const models = consolidation.models ?? [];
|
|
448
579
|
return consolidationModelCandidates(catalogGroups, models, new Set(models.map(consolidationModelKey)));
|
|
449
580
|
}, [catalogGroups, consolidation.models]);
|
|
581
|
+
const selectedModels = (0, react.useMemo)(() => orderedConsolidationModels(consolidation.models ?? [], candidates), [consolidation.models, candidates]);
|
|
450
582
|
const toggleModel = (0, react.useCallback)((candidate) => {
|
|
451
583
|
if (disabled || saving) return;
|
|
452
584
|
setDraft((current) => {
|
|
@@ -466,6 +598,77 @@ window.__ModuleLoader__.load({
|
|
|
466
598
|
};
|
|
467
599
|
});
|
|
468
600
|
}, [disabled, saving]);
|
|
601
|
+
/**
|
|
602
|
+
* Reorder one entry of the priority list. A no-op move leaves the draft
|
|
603
|
+
* untouched (the mover returns the original array), so the "unsaved" badge
|
|
604
|
+
* does not light up for a click that changed nothing.
|
|
605
|
+
*/
|
|
606
|
+
const moveModel = (0, react.useCallback)((from, to) => {
|
|
607
|
+
if (disabled || saving) return;
|
|
608
|
+
setDraft((current) => {
|
|
609
|
+
const currentConsolidation = current.consolidation ?? DEFAULT_CONSOLIDATION;
|
|
610
|
+
const currentModels = currentConsolidation.models ?? [];
|
|
611
|
+
const models = moveConsolidationModel(currentModels, from, to);
|
|
612
|
+
if (models === currentModels) return current;
|
|
613
|
+
return {
|
|
614
|
+
...current,
|
|
615
|
+
consolidation: {
|
|
616
|
+
...currentConsolidation,
|
|
617
|
+
models
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
});
|
|
621
|
+
}, [disabled, saving]);
|
|
622
|
+
/**
|
|
623
|
+
* Set or clear one route's thinking level. Clearing REMOVES the key rather
|
|
624
|
+
* than storing `undefined`, so the saved patch carries only what the user
|
|
625
|
+
* chose and nothing reading the profile can confuse "not configured" with
|
|
626
|
+
* "configured as nothing".
|
|
627
|
+
*/
|
|
628
|
+
const setModelEffort = (0, react.useCallback)((index, effort) => {
|
|
629
|
+
if (disabled || saving) return;
|
|
630
|
+
setDraft((current) => {
|
|
631
|
+
const currentConsolidation = current.consolidation ?? DEFAULT_CONSOLIDATION;
|
|
632
|
+
const currentModels = currentConsolidation.models ?? [];
|
|
633
|
+
if (index < 0 || index >= currentModels.length) return current;
|
|
634
|
+
const models = currentModels.map((route, at) => {
|
|
635
|
+
if (at !== index) return route;
|
|
636
|
+
if (effort === void 0) {
|
|
637
|
+
const cleared = { ...route };
|
|
638
|
+
delete cleared.reasoningEffort;
|
|
639
|
+
return cleared;
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
...route,
|
|
643
|
+
reasoningEffort: effort
|
|
644
|
+
};
|
|
645
|
+
});
|
|
646
|
+
return {
|
|
647
|
+
...current,
|
|
648
|
+
consolidation: {
|
|
649
|
+
...currentConsolidation,
|
|
650
|
+
models
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
}, [disabled, saving]);
|
|
655
|
+
/** Display label for one thinking-level option, in the card's own words. */
|
|
656
|
+
const effortChoiceLabel = (0, react.useCallback)((choice) => {
|
|
657
|
+
if (choice.effort === void 0) return t("reasoningFollowPurpose");
|
|
658
|
+
const name = choice.name ?? choice.effort;
|
|
659
|
+
return choice.stale === true ? `${name} · ${t("reasoningStale")}` : name;
|
|
660
|
+
}, [t]);
|
|
661
|
+
/**
|
|
662
|
+
* What the adapter does when no effort is sent. Only a hint: this plugin
|
|
663
|
+
* cannot pin it, because omitting the field is what lets its own per-purpose
|
|
664
|
+
* policy apply.
|
|
665
|
+
*/
|
|
666
|
+
const routeDefaultLabel = (0, react.useCallback)((candidate) => {
|
|
667
|
+
const reasoning = candidate.reasoning;
|
|
668
|
+
const fallback = reasoning?.defaultEffort;
|
|
669
|
+
if (reasoning === void 0 || fallback === void 0) return void 0;
|
|
670
|
+
return t("reasoningDefault", { effort: reasoning.efforts.find((effort) => effort.id === fallback)?.name ?? fallback });
|
|
671
|
+
}, [t]);
|
|
469
672
|
const discard = (0, react.useCallback)(() => {
|
|
470
673
|
setDraft(resolved);
|
|
471
674
|
setError(null);
|
|
@@ -756,10 +959,82 @@ window.__ModuleLoader__.load({
|
|
|
756
959
|
className: SettingsCard_module_css_default.notice,
|
|
757
960
|
children: t("modelCatalogPartial")
|
|
758
961
|
}) : null,
|
|
759
|
-
candidates.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
962
|
+
candidates.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
963
|
+
className: SettingsCard_module_css_default.models,
|
|
964
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("selectedModels") }), selectedModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
965
|
+
className: SettingsCard_module_css_default.notice,
|
|
966
|
+
children: t("selectedModelsEmpty")
|
|
967
|
+
}) : selectedModels.map((candidate, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
968
|
+
className: SettingsCard_module_css_default.selectedRow,
|
|
969
|
+
children: [
|
|
970
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
971
|
+
className: SettingsCard_module_css_default.order,
|
|
972
|
+
children: index + 1
|
|
973
|
+
}),
|
|
974
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
975
|
+
className: SettingsCard_module_css_default.selectedText,
|
|
976
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
977
|
+
className: SettingsCard_module_css_default.modelName,
|
|
978
|
+
children: candidate.modelName
|
|
979
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
980
|
+
className: SettingsCard_module_css_default.route,
|
|
981
|
+
children: `${candidate.providerName} · ${candidate.provider}/${candidate.model}`
|
|
982
|
+
})]
|
|
983
|
+
}),
|
|
984
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
985
|
+
className: SettingsCard_module_css_default.effort,
|
|
986
|
+
"aria-label": `${t("reasoningEffort")}: ${candidate.modelName}`,
|
|
987
|
+
title: candidate.reasoning === void 0 ? t("reasoningUnavailable") : routeDefaultLabel(candidate) ?? t("reasoningFollowPurpose"),
|
|
988
|
+
value: candidate.reasoningEffort ?? "",
|
|
989
|
+
disabled: disabled || saving || candidate.reasoning === void 0,
|
|
990
|
+
onChange: (event) => setModelEffort(index, event.target.value === "" ? void 0 : event.target.value),
|
|
991
|
+
children: reasoningEffortChoices(candidate.reasoning, candidate.reasoningEffort).map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
992
|
+
value: choice.effort ?? "",
|
|
993
|
+
children: effortChoiceLabel(choice)
|
|
994
|
+
}, choice.key))
|
|
995
|
+
}),
|
|
996
|
+
!candidate.available ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
997
|
+
className: SettingsCard_module_css_default.unavailable,
|
|
998
|
+
children: t("modelUnavailable")
|
|
999
|
+
}) : null,
|
|
1000
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1001
|
+
className: SettingsCard_module_css_default.rowActions,
|
|
1002
|
+
children: [
|
|
1003
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1004
|
+
type: "button",
|
|
1005
|
+
className: SettingsCard_module_css_default.move,
|
|
1006
|
+
title: t("moveUp"),
|
|
1007
|
+
"aria-label": `${t("moveUp")}: ${candidate.modelName}`,
|
|
1008
|
+
disabled: disabled || saving || index === 0,
|
|
1009
|
+
onClick: () => moveModel(index, index - 1),
|
|
1010
|
+
children: "↑"
|
|
1011
|
+
}),
|
|
1012
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1013
|
+
type: "button",
|
|
1014
|
+
className: SettingsCard_module_css_default.move,
|
|
1015
|
+
title: t("moveDown"),
|
|
1016
|
+
"aria-label": `${t("moveDown")}: ${candidate.modelName}`,
|
|
1017
|
+
disabled: disabled || saving || index === selectedModels.length - 1,
|
|
1018
|
+
onClick: () => moveModel(index, index + 1),
|
|
1019
|
+
children: "↓"
|
|
1020
|
+
}),
|
|
1021
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1022
|
+
type: "button",
|
|
1023
|
+
className: SettingsCard_module_css_default.move,
|
|
1024
|
+
title: t("remove"),
|
|
1025
|
+
"aria-label": `${t("remove")}: ${candidate.modelName}`,
|
|
1026
|
+
disabled: disabled || saving,
|
|
1027
|
+
onClick: () => toggleModel(candidate),
|
|
1028
|
+
children: "×"
|
|
1029
|
+
})
|
|
1030
|
+
]
|
|
1031
|
+
})
|
|
1032
|
+
]
|
|
1033
|
+
}, candidate.key))]
|
|
1034
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
760
1035
|
className: SettingsCard_module_css_default.models,
|
|
761
1036
|
children: [
|
|
762
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("
|
|
1037
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("availableModels") }),
|
|
763
1038
|
[...availableGroups].map(([provider, group]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
764
1039
|
className: SettingsCard_module_css_default.modelGroup,
|
|
765
1040
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -775,10 +1050,14 @@ window.__ModuleLoader__.load({
|
|
|
775
1050
|
}), unavailable.map(renderCandidate)]
|
|
776
1051
|
}) : null
|
|
777
1052
|
]
|
|
778
|
-
}) : catalogStatus === "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1053
|
+
})] }) : catalogStatus === "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
779
1054
|
className: SettingsCard_module_css_default.notice,
|
|
780
1055
|
children: t("modelCatalogEmpty")
|
|
781
|
-
}) : null
|
|
1056
|
+
}) : null,
|
|
1057
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1058
|
+
className: SettingsCard_module_css_default.hint,
|
|
1059
|
+
children: t("reasoningBudgetHint")
|
|
1060
|
+
})
|
|
782
1061
|
]
|
|
783
1062
|
}),
|
|
784
1063
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|