@litfamily/lithermes 1.0.4 → 1.0.6
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 +100 -85
- package/README_Ko-KR.md +108 -95
- package/assets/lithermes-plugin/README.md +27 -17
- package/assets/lithermes-plugin/__init__.py +5 -1
- package/assets/lithermes-plugin/core_contexts.py +18 -4
- package/assets/lithermes-plugin/core_routing.py +2 -0
- package/assets/lithermes-plugin/diagnostics.py +48 -16
- package/assets/lithermes-plugin/payload-version.json +105 -13
- package/assets/lithermes-plugin/plugin.yaml +1 -1
- package/assets/lithermes-plugin/skills/frontend-ui-ux/SKILL.md +11 -12
- package/assets/lithermes-plugin/skills/frontend-ui-ux/references/complete-contract.md +24 -13
- package/assets/lithermes-plugin/skills/frontend-ui-ux/references/default-editorial-pixel.json +18 -0
- package/assets/lithermes-plugin/skills/frontend-ui-ux/references/operating-lanes.md +1 -1
- package/assets/lithermes-plugin/skills/frontend-ui-ux/references/product-direction.md +1 -1
- package/assets/lithermes-plugin/skills/frontend-ui-ux/references/production.md +13 -0
- package/assets/lithermes-plugin/skills/readme-studio/SKILL.md +73 -0
- package/assets/lithermes-plugin/skills/readme-studio/references/decoration-patterns.md +36 -0
- package/assets/lithermes-plugin/skills/readme-studio/references/facts.md +11 -0
- package/assets/lithermes-plugin/skills/readme-studio/references/motion.md +34 -0
- package/assets/lithermes-plugin/skills/readme-studio/references/production-interview.md +17 -0
- package/assets/lithermes-plugin/skills/readme-studio/references/type-and-images.md +17 -0
- package/assets/lithermes-plugin/skills/readme-studio/scripts/check_facts.py +103 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/cover-section.md +63 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/cover-settings.json +11 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/cover-source.json +12 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/facts.json +1 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/hyperframes/index.html +54 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/hyperframes/index.motion.json +1 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/hyperframes/package-lock.json +1843 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/hyperframes/package.json +6 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/remotion/package-lock.json +3783 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/remotion/package.json +7 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/remotion/src/index.tsx +34 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/typography/outline.mjs +79 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/typography/package-lock.json +133 -0
- package/assets/lithermes-plugin/skills/readme-studio/templates/typography/package.json +6 -0
- package/assets/lithermes-plugin/skills/visual-qa/references/complete-contract.md +3 -3
- package/package.json +1 -1
- package/readme-assets/Lucide-LICENSE.txt +43 -0
- package/readme-assets/ascii-readme.svg +5 -0
- package/readme-assets/badge-version.svg +1 -1
- package/readme-assets/cover-motion-still.webp +0 -0
- package/readme-assets/cover-motion.webp +0 -0
- package/readme-assets/ignition-film.mp4 +0 -0
- package/readme-assets/lucide-book-open.svg +14 -0
- package/readme-assets/lucide-play.svg +13 -0
- package/readme-assets/lucide-shield-check.svg +14 -0
- package/src/lib/check.js +75 -2
- package/src/lib/config.js +23 -0
- package/src/lib/install.js +2 -1
- package/src/lib/modelConfig.js +11 -7
- package/src/lib/modelRoutePolicy.js +94 -51
- package/src/lib/skillPayload.js +1 -1
package/src/lib/check.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
2
|
const path = require("node:path");
|
|
3
3
|
const { spawnSync } = require("node:child_process");
|
|
4
|
-
const { configHasLitHermes, inspectHermesCapabilities, readConfig } = require("./config");
|
|
5
|
-
const { detectHermesRuntimeRepo, detectHermesVersion, ensureHermesHome, inspectHermesHostCapabilities, LitHermesError } = require("./hermesDiscovery");
|
|
4
|
+
const { configHasLitHermes, inspectHermesCapabilities, readConfig, readExternalSkillDirsConfig } = require("./config");
|
|
5
|
+
const { detectHermesRuntimeRepo, detectHermesVersion, ensureHermesHome, expandHome, inspectHermesHostCapabilities, LitHermesError } = require("./hermesDiscovery");
|
|
6
6
|
const { formatManagedRoute } = require("./modelRoutePolicy");
|
|
7
7
|
const { inspectPythonCache } = require("./files");
|
|
8
8
|
const { assetRoot, pluginDest } = require("./install");
|
|
@@ -112,6 +112,75 @@ function loadedStatusMatchesOrigin(output, expectedPluginPath) {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
function isRegularSkillFile(file) {
|
|
116
|
+
try {
|
|
117
|
+
return fs.lstatSync(file).isFile();
|
|
118
|
+
} catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Bounded, non-symlink-following scan for `<HERMES_HOME>/skills/**/<id>/SKILL.md`.
|
|
124
|
+
// Real local-skill trees are shallow, so a small depth/entry cap keeps this cheap
|
|
125
|
+
// while still catching a collision a couple of category folders deep.
|
|
126
|
+
function collectLocalSkillShadows(hermesHome, skillIds, { maxDepth = 3, maxEntries = 2000 } = {}) {
|
|
127
|
+
const remaining = new Set(skillIds);
|
|
128
|
+
const found = new Map();
|
|
129
|
+
let visited = 0;
|
|
130
|
+
function walk(dir, depth) {
|
|
131
|
+
if (!remaining.size || depth > maxDepth || visited >= maxEntries) return;
|
|
132
|
+
let entries;
|
|
133
|
+
try {
|
|
134
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
135
|
+
} catch {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
for (const entry of entries) {
|
|
139
|
+
if (!remaining.size || visited >= maxEntries) return;
|
|
140
|
+
visited += 1;
|
|
141
|
+
if (!entry.isDirectory()) continue;
|
|
142
|
+
const full = path.join(dir, entry.name);
|
|
143
|
+
if (remaining.has(entry.name)) {
|
|
144
|
+
const skillFile = path.join(full, "SKILL.md");
|
|
145
|
+
if (isRegularSkillFile(skillFile)) {
|
|
146
|
+
found.set(entry.name, skillFile);
|
|
147
|
+
remaining.delete(entry.name);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
walk(full, depth + 1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
walk(path.join(hermesHome, "skills"), 0);
|
|
155
|
+
return found;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Hermes resolves a bare skill name (not the `lithermes:<name>` explicit-load form)
|
|
159
|
+
// against `skills.external_dirs` and local `<HERMES_HOME>/skills`; a same-named entry
|
|
160
|
+
// there is picked instead of the LitHermes plugin copy. This is advisory: it never
|
|
161
|
+
// changes doctor's pass/fail status, only surfaces the collision.
|
|
162
|
+
function detectSkillShadows({ configText, hermesHome, skillIds = requiredSkills }) {
|
|
163
|
+
const externalDirs = readExternalSkillDirsConfig(configText)
|
|
164
|
+
.map((dir) => path.resolve(expandHome(dir)));
|
|
165
|
+
const localShadows = collectLocalSkillShadows(hermesHome, skillIds);
|
|
166
|
+
const warnings = [];
|
|
167
|
+
for (const id of skillIds) {
|
|
168
|
+
const externalDir = externalDirs.find((dir) => isRegularSkillFile(path.join(dir, id, "SKILL.md")));
|
|
169
|
+
if (externalDir) {
|
|
170
|
+
warnings.push({ id, path: path.join(externalDir, id, "SKILL.md"), source: "skills.external_dirs" });
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const localPath = localShadows.get(id);
|
|
174
|
+
if (localPath) warnings.push({ id, path: localPath, source: "local skills" });
|
|
175
|
+
}
|
|
176
|
+
return warnings;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function formatSkillShadowWarning(shadow) {
|
|
180
|
+
return `WARNING: skill "${shadow.id}" bare name resolves to ${shadow.path} (${shadow.source}); `
|
|
181
|
+
+ `use lithermes:${shadow.id} to load LitHermes's copy, or remove/rename the other copy.`;
|
|
182
|
+
}
|
|
183
|
+
|
|
115
184
|
function checkLitHermes(flags = {}) {
|
|
116
185
|
const { hermesHome, hermesRepo } = ensureHermesHome(flags);
|
|
117
186
|
const pluginPath = pluginDest(hermesHome);
|
|
@@ -187,6 +256,7 @@ function doctorLitHermes(flags = {}) {
|
|
|
187
256
|
const unsafeRecursion = recursion.status === "unavailable" && recursion.reason.startsWith("nested delegation");
|
|
188
257
|
const unsafeModelRoute = modelSafety.status === "blocked";
|
|
189
258
|
const runtime = capabilities.runtime;
|
|
259
|
+
const skillShadows = detectSkillShadows({ configText, hermesHome });
|
|
190
260
|
const lines = [
|
|
191
261
|
`plugin discovery: ${installedPass && configOk ? "PASS" : "PATCH_AVAILABLE"}`,
|
|
192
262
|
`bundled source: ${bundledPass ? "PASS" : "FAIL"}`,
|
|
@@ -198,6 +268,8 @@ function doctorLitHermes(flags = {}) {
|
|
|
198
268
|
`installed payload: ${installedPass ? "PASS" : "FAIL"}`,
|
|
199
269
|
`enabled config: ${configOk ? "PASS" : "PARTIAL"}`,
|
|
200
270
|
`loaded plugin: ${loaded.status} (${loaded.reason})`,
|
|
271
|
+
`skill shadow check: ${skillShadows.length ? "WARNING" : "PASS"}`,
|
|
272
|
+
...skillShadows.map(formatSkillShadowWarning),
|
|
201
273
|
`auto-compaction: ${auto.status}${auto.reason ? ` (${auto.reason})` : ""}`,
|
|
202
274
|
`concurrency: ${concurrency.status}${concurrency.status === "hard" ? ` (per batch ${concurrency.limit}; async batches ${concurrency.asyncBatchLimit}; potential children ${concurrency.potentialChildCeiling})` : ` (${concurrency.reason})`}`,
|
|
203
275
|
`recursion: ${recursion.status}${recursion.status === "hard" ? recursion.flatBy === "depth" ? ` (depth ${recursion.limit}, flat)` : ` (configured depth ${recursion.limit}, flat via orchestrator kill switch)` : ` (${recursion.reason})`}`,
|
|
@@ -222,6 +294,7 @@ module.exports = {
|
|
|
222
294
|
checkGatewaySource,
|
|
223
295
|
checkLitHermes,
|
|
224
296
|
checkTuiSource,
|
|
297
|
+
detectSkillShadows,
|
|
225
298
|
doctorLitHermes,
|
|
226
299
|
enabledUserJsonIncludesPlugin,
|
|
227
300
|
loadedStatusMatchesOrigin,
|
package/src/lib/config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
2
|
const path = require("node:path");
|
|
3
|
+
const { parseDocument } = require("yaml");
|
|
3
4
|
const { writeFileAtomic } = require("./files");
|
|
4
5
|
const modelConfig = require("./modelConfig");
|
|
5
6
|
|
|
@@ -205,6 +206,27 @@ function clearOutputStyleConfig(text) {
|
|
|
205
206
|
return `${updated.replace(/\n*$/, "")}\n`;
|
|
206
207
|
}
|
|
207
208
|
|
|
209
|
+
// Hermes `skills.external_dirs` (config.yaml key, default []): bare-name skill
|
|
210
|
+
// resolution searches these directories, so a same-named directory there can shadow
|
|
211
|
+
// a LitHermes plugin skill (which is only reachable unambiguously as `lithermes:<name>`).
|
|
212
|
+
// Malformed YAML fails closed to an empty list rather than throwing during doctor.
|
|
213
|
+
function readExternalSkillDirsConfig(text) {
|
|
214
|
+
const str = String(text || "");
|
|
215
|
+
if (!str.trim()) return [];
|
|
216
|
+
try {
|
|
217
|
+
const document = parseDocument(str, { strict: true, uniqueKeys: true });
|
|
218
|
+
if (document.errors.length) return [];
|
|
219
|
+
const node = document.getIn(["skills", "external_dirs"], true);
|
|
220
|
+
const value = node && typeof node.toJS === "function" ? node.toJS(document) : node;
|
|
221
|
+
if (!Array.isArray(value)) return [];
|
|
222
|
+
return value
|
|
223
|
+
.filter((entry) => typeof entry === "string" && entry.trim())
|
|
224
|
+
.map((entry) => entry.trim());
|
|
225
|
+
} catch {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
208
230
|
function writeConfig(hermesHome, text) {
|
|
209
231
|
fs.mkdirSync(hermesHome, { recursive: true });
|
|
210
232
|
writeFileAtomic(configPath(hermesHome), text, "utf8");
|
|
@@ -220,6 +242,7 @@ module.exports = {
|
|
|
220
242
|
enableLitHermesConfig,
|
|
221
243
|
readConfig,
|
|
222
244
|
readDisplaySkinConfig,
|
|
245
|
+
readExternalSkillDirsConfig,
|
|
223
246
|
readOutputStyleConfig,
|
|
224
247
|
readTuiAgentsNudgeConfig,
|
|
225
248
|
setDisplaySkinConfig,
|
package/src/lib/install.js
CHANGED
|
@@ -17,6 +17,7 @@ const { assertStateParent, assertPluginParent, defaultHermesHome, defaultHermesR
|
|
|
17
17
|
const { NOT_PROBED_HOST_VERSION } = require("./modelConfigBoundary");
|
|
18
18
|
const { patchInstalledHermes, rollbackPatches } = require("./patch");
|
|
19
19
|
const {
|
|
20
|
+
ASTRA_MODEL,
|
|
20
21
|
formatManagedRoute,
|
|
21
22
|
managedRequest,
|
|
22
23
|
missingCredentialWarning,
|
|
@@ -344,7 +345,7 @@ function installLitHermes(flags = {}) {
|
|
|
344
345
|
);
|
|
345
346
|
}
|
|
346
347
|
if (dryRun) {
|
|
347
|
-
const selectedModel = modelPlan.request?.model ||
|
|
348
|
+
const selectedModel = modelPlan.request?.model || ASTRA_MODEL;
|
|
348
349
|
const selectedEffort = modelPlan.request?.effort || "xhigh";
|
|
349
350
|
return {
|
|
350
351
|
message: [
|
package/src/lib/modelConfig.js
CHANGED
|
@@ -6,6 +6,7 @@ const { OPENAI_PROVIDER, RESPONSES_MODE, classifyHostVersion,
|
|
|
6
6
|
const {
|
|
7
7
|
ASTRA_MODEL,
|
|
8
8
|
MANAGED_PROVIDER_MODELS,
|
|
9
|
+
MODEL_IDS,
|
|
9
10
|
applyManagedRoute,
|
|
10
11
|
customChildTransportReason,
|
|
11
12
|
inspectEffectiveRouteSafety,
|
|
@@ -17,8 +18,6 @@ const {
|
|
|
17
18
|
unavailableTuiRouteVisibility,
|
|
18
19
|
} = require("./modelRoutePolicy");
|
|
19
20
|
|
|
20
|
-
const MODELS = new Set(["gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"]);
|
|
21
|
-
|
|
22
21
|
// The route every "configured" verdict is measured against: explicit installer
|
|
23
22
|
// options win; otherwise the document's own route when it is a catalog route;
|
|
24
23
|
// otherwise today's shipped default.
|
|
@@ -45,6 +44,12 @@ function expectedRoute(options = {}, document = null) {
|
|
|
45
44
|
const SAFE_CONTEXT_LENGTH = 372000;
|
|
46
45
|
const SAFE_COMPRESSION_THRESHOLD = 0.9;
|
|
47
46
|
const SAFE_AUTO_COMPACTION_LIMIT = SAFE_CONTEXT_LENGTH * SAFE_COMPRESSION_THRESHOLD;
|
|
47
|
+
const LEGACY_CONTEXT_MODELS = new Set([
|
|
48
|
+
"gpt-5.6",
|
|
49
|
+
"gpt-5.6-sol",
|
|
50
|
+
"gpt-5.6-terra",
|
|
51
|
+
"gpt-5.6-luna",
|
|
52
|
+
]);
|
|
48
53
|
const MANAGED_SAMPLING_KEYS = ["temperature", "top_p", "top_logprobs"];
|
|
49
54
|
|
|
50
55
|
function hasValue(document, path) {
|
|
@@ -156,7 +161,7 @@ function classificationFromDocument(document, fresh) {
|
|
|
156
161
|
if (provider === OPENAI_PROVIDER && (dispatch === "gpt-5.4" || dispatch === "gpt-5.5")) {
|
|
157
162
|
return { class: "managed_legacy", originalDispatchId };
|
|
158
163
|
}
|
|
159
|
-
if (provider === OPENAI_PROVIDER &&
|
|
164
|
+
if (provider === OPENAI_PROVIDER && MODEL_IDS.has(dispatch)) {
|
|
160
165
|
return { class: "existing_managed", originalDispatchId };
|
|
161
166
|
}
|
|
162
167
|
if (MANAGED_PROVIDER_MODELS[provider]?.has(dispatch)) {
|
|
@@ -364,10 +369,9 @@ function planModelConfig(text, options = {}) {
|
|
|
364
369
|
}
|
|
365
370
|
const document = boundary.document;
|
|
366
371
|
applyManagedRoute(document, route);
|
|
367
|
-
// The verified
|
|
368
|
-
// resets
|
|
369
|
-
|
|
370
|
-
if (options.reconfigure && route.model !== ASTRA_MODEL && route.childModel !== ASTRA_MODEL) {
|
|
372
|
+
// The verified context/compression defaults apply only to explicit GPT-5.6
|
|
373
|
+
// model resets. GPT-6 model routes have no published evidence for these limits.
|
|
374
|
+
if (options.reconfigure && LEGACY_CONTEXT_MODELS.has(route.model)) {
|
|
371
375
|
document.setIn(["model", "context_length"], SAFE_CONTEXT_LENGTH);
|
|
372
376
|
document.setIn(["compression", "threshold"], SAFE_COMPRESSION_THRESHOLD);
|
|
373
377
|
}
|
|
@@ -1,38 +1,77 @@
|
|
|
1
1
|
const ASTRA_MODEL = "gpt-6-astra";
|
|
2
|
-
const
|
|
2
|
+
const GPT6_LEAD_EFFORTS = new Set(["low", "medium", "high", "xhigh", "max", "ultra"]);
|
|
3
|
+
const ASTRA_EFFORTS = GPT6_LEAD_EFFORTS;
|
|
3
4
|
const PARENT_MODEL = ASTRA_MODEL;
|
|
4
5
|
const PARENT_EFFORT = "xhigh";
|
|
5
|
-
const
|
|
6
|
+
const SOL_MODEL = "gpt-6-sol";
|
|
7
|
+
const CHILD_MODEL = "gpt-6-luna";
|
|
8
|
+
const LEGACY_SOL_MODEL = "gpt-5.6-sol";
|
|
9
|
+
const LEGACY_CHILD_MODEL = "gpt-5.6-luna";
|
|
6
10
|
const CHILD_EFFORT = "max";
|
|
7
|
-
const
|
|
11
|
+
const GPT6_LUNA_EFFORTS = new Set(["low", "medium", "high", "xhigh", "max"]);
|
|
12
|
+
const LEGACY_LUNA_EFFORTS = new Set(["high", "max"]);
|
|
13
|
+
const LUNA_EFFORTS = LEGACY_LUNA_EFFORTS;
|
|
14
|
+
const LUNA_MODELS = new Set([CHILD_MODEL, LEGACY_CHILD_MODEL]);
|
|
8
15
|
const TERRA_MODEL = "gpt-5.6-terra";
|
|
9
16
|
const TERRA_EFFORTS = new Set(["high", "xhigh", "max"]);
|
|
17
|
+
const LEGACY_SOL_EFFORTS = new Set(["high", "xhigh"]);
|
|
18
|
+
const MODEL_EFFORTS = new Map([
|
|
19
|
+
[ASTRA_MODEL, GPT6_LEAD_EFFORTS],
|
|
20
|
+
[SOL_MODEL, GPT6_LEAD_EFFORTS],
|
|
21
|
+
[CHILD_MODEL, GPT6_LUNA_EFFORTS],
|
|
22
|
+
[LEGACY_SOL_MODEL, LEGACY_SOL_EFFORTS],
|
|
23
|
+
[LEGACY_CHILD_MODEL, LEGACY_LUNA_EFFORTS],
|
|
24
|
+
["gpt-5.6", new Set(["high"])],
|
|
25
|
+
[TERRA_MODEL, TERRA_EFFORTS],
|
|
26
|
+
]);
|
|
10
27
|
const CHILD_TRANSPORT_KEYS = ["provider", "base_url", "api_mode"];
|
|
11
28
|
const { OPENAI_PROVIDER: OPENAI_PROVIDER_ID } = require("./modelConfigBoundary");
|
|
12
29
|
const XAI_PROVIDER_ID = "xai";
|
|
13
30
|
// Installer choice catalog (plans/references/installer-choice-contract.md, LitHermes row).
|
|
14
|
-
// OpenAI rows
|
|
15
|
-
//
|
|
16
|
-
// reasoning-capable models of the Hermes 0.19 static xAI catalog
|
|
31
|
+
// OpenAI rows follow each model's listed effort set, including selectable legacy
|
|
32
|
+
// GPT-5.6 routes. xAI rows use the reasoning-capable models of the Hermes 0.19 catalog
|
|
17
33
|
// (hermes_cli/models.py `_XAI_STATIC_FALLBACK`), newest first, with the Hermes
|
|
18
34
|
// reasoning_effort vocabulary (hermes_cli/config.py delegation.reasoning_effort).
|
|
19
35
|
const ROUTE_CATALOG = {
|
|
20
36
|
[OPENAI_PROVIDER_ID]: {
|
|
21
37
|
credentialEnv: null,
|
|
22
|
-
label: "OpenAI OAuth Responses (Astra +
|
|
38
|
+
label: "OpenAI OAuth Responses (Astra + Sol + Luna)",
|
|
23
39
|
rows: [
|
|
24
|
-
...["low", "medium", "high", "xhigh", "max"].map((effort) => ({
|
|
40
|
+
...["low", "medium", "high", "xhigh", "max", "ultra"].map((effort) => ({
|
|
25
41
|
effort,
|
|
26
42
|
model: ASTRA_MODEL,
|
|
27
|
-
note: effort === "
|
|
43
|
+
note: effort === "ultra"
|
|
28
44
|
? "deepest Astra reasoning"
|
|
29
45
|
: effort === PARENT_EFFORT
|
|
30
46
|
? "recommended lead"
|
|
31
47
|
: "Astra Responses effort",
|
|
32
48
|
})),
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
...["low", "medium", "high", "xhigh", "max", "ultra"].map((effort) => ({
|
|
50
|
+
effort,
|
|
51
|
+
model: SOL_MODEL,
|
|
52
|
+
note: effort === PARENT_EFFORT ? "coding lead alternative" : "Sol Responses effort",
|
|
53
|
+
})),
|
|
54
|
+
...["low", "medium", "high", "xhigh", "max"].map((effort) => ({
|
|
55
|
+
effort,
|
|
56
|
+
model: CHILD_MODEL,
|
|
57
|
+
note: effort === CHILD_EFFORT
|
|
58
|
+
? "balanced (recommended helper)"
|
|
59
|
+
: effort === "high"
|
|
60
|
+
? "balanced, lighter effort"
|
|
61
|
+
: "Luna Responses effort",
|
|
62
|
+
})),
|
|
63
|
+
...["high", "xhigh"].map((effort) => ({
|
|
64
|
+
effort,
|
|
65
|
+
model: LEGACY_SOL_MODEL,
|
|
66
|
+
note: "previous-generation Sol lead route",
|
|
67
|
+
})),
|
|
68
|
+
...["high", "xhigh", "max"].map((effort) => ({
|
|
69
|
+
effort,
|
|
70
|
+
model: TERRA_MODEL,
|
|
71
|
+
note: "previous-generation Terra route",
|
|
72
|
+
})),
|
|
73
|
+
{ effort: CHILD_EFFORT, model: LEGACY_CHILD_MODEL, note: "previous-generation balanced helper" },
|
|
74
|
+
{ effort: "high", model: LEGACY_CHILD_MODEL, note: "previous-generation lighter helper" },
|
|
36
75
|
{ effort: "high", model: "gpt-5.6", note: "general model" },
|
|
37
76
|
],
|
|
38
77
|
lead: { effort: PARENT_EFFORT, model: PARENT_MODEL },
|
|
@@ -55,6 +94,10 @@ const PROVIDER_IDS = Object.keys(ROUTE_CATALOG);
|
|
|
55
94
|
const MANAGED_PROVIDER_MODELS = Object.fromEntries(
|
|
56
95
|
PROVIDER_IDS.map((id) => [id, new Set(ROUTE_CATALOG[id].rows.map((row) => row.model))]),
|
|
57
96
|
);
|
|
97
|
+
const MODEL_IDS = new Set([
|
|
98
|
+
...MANAGED_PROVIDER_MODELS[OPENAI_PROVIDER_ID],
|
|
99
|
+
TERRA_MODEL,
|
|
100
|
+
]);
|
|
58
101
|
const MANAGED_PROVIDERS = new Set(PROVIDER_IDS);
|
|
59
102
|
const UNSAFE_ROUTE_CODE = "LITHERMES_UNSAFE_MODEL_ROUTE";
|
|
60
103
|
const REVIEWER_ROUTE_NAME = String.fromCharCode(109, 111, 109, 117, 115);
|
|
@@ -83,42 +126,32 @@ function inspectEffectiveRouteSafety(document, expectedProvider) {
|
|
|
83
126
|
const managedRoutes = routes.filter((route) => route.provider === expectedProvider);
|
|
84
127
|
for (const route of managedRoutes) {
|
|
85
128
|
if (transportReason && route.route === "global_child") continue;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
reason: `${route.route} Astra effort is unsupported or missing; choose one of: ${[...ASTRA_EFFORTS].join(", ")}`,
|
|
92
|
-
route: route.route,
|
|
93
|
-
status: "blocked",
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
if (route.model === CHILD_MODEL && route.effort === "xhigh") {
|
|
97
|
-
return {
|
|
98
|
-
classificationClass: "conflicting_luna_xhigh",
|
|
99
|
-
code: UNSAFE_ROUTE_CODE,
|
|
100
|
-
observedSource: `${route.route} model, effort, and provider config`,
|
|
101
|
-
reason: `${route.route} Luna xhigh is a forbidden pair (Luna runs at high or max)`,
|
|
102
|
-
route: route.route,
|
|
103
|
-
status: "blocked",
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
if (route.model === CHILD_MODEL && !LUNA_EFFORTS.has(route.effort)) {
|
|
107
|
-
return {
|
|
108
|
-
classificationClass: "luna_effort_below_high",
|
|
109
|
-
code: UNSAFE_ROUTE_CODE,
|
|
110
|
-
observedSource: `${route.route} model, effort, and provider config`,
|
|
111
|
-
reason: `${route.route} Luna effort is below high or missing`,
|
|
112
|
-
route: route.route,
|
|
113
|
-
status: "blocked",
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
if (route.model === TERRA_MODEL && !TERRA_EFFORTS.has(route.effort)) {
|
|
129
|
+
const modelEfforts = MODEL_EFFORTS.get(route.model);
|
|
130
|
+
if (modelEfforts && !modelEfforts.has(route.effort)) {
|
|
131
|
+
const isAstra = route.model === ASTRA_MODEL;
|
|
132
|
+
const isLuna = LUNA_MODELS.has(route.model);
|
|
133
|
+
const isLegacyLunaXhigh = route.model === LEGACY_CHILD_MODEL && route.effort === "xhigh";
|
|
117
134
|
return {
|
|
118
|
-
classificationClass:
|
|
135
|
+
classificationClass: isAstra
|
|
136
|
+
? "astra_effort_unsupported"
|
|
137
|
+
: isLegacyLunaXhigh
|
|
138
|
+
? "conflicting_luna_xhigh"
|
|
139
|
+
: isLuna
|
|
140
|
+
? "luna_effort_below_high"
|
|
141
|
+
: route.model === TERRA_MODEL
|
|
142
|
+
? "terra_effort_below_high"
|
|
143
|
+
: "model_effort_unsupported",
|
|
119
144
|
code: UNSAFE_ROUTE_CODE,
|
|
120
145
|
observedSource: `${route.route} model, effort, and provider config`,
|
|
121
|
-
reason:
|
|
146
|
+
reason: isAstra
|
|
147
|
+
? `${route.route} Astra effort is unsupported or missing; choose one of: ${[...modelEfforts].join(", ")}`
|
|
148
|
+
: isLegacyLunaXhigh
|
|
149
|
+
? `${route.route} Luna xhigh is a forbidden pair (legacy Luna runs at high or max)`
|
|
150
|
+
: isLuna
|
|
151
|
+
? `${route.route} Luna effort is unsupported; choose one of: ${[...modelEfforts].join(", ")}`
|
|
152
|
+
: route.model === TERRA_MODEL
|
|
153
|
+
? `${route.route} TERRA effort is below high or missing`
|
|
154
|
+
: `${route.route} ${route.model} effort is unsupported or missing; choose one of: ${[...modelEfforts].join(", ")}`,
|
|
122
155
|
route: route.route,
|
|
123
156
|
status: "blocked",
|
|
124
157
|
};
|
|
@@ -140,7 +173,7 @@ function inspectEffectiveRouteSafety(document, expectedProvider) {
|
|
|
140
173
|
}
|
|
141
174
|
return {
|
|
142
175
|
observedSource: "parent and global delegation model policy",
|
|
143
|
-
reason: "no effective
|
|
176
|
+
reason: "no effective model and effort pair outside the model catalog is configured",
|
|
144
177
|
status: "safe",
|
|
145
178
|
};
|
|
146
179
|
}
|
|
@@ -162,8 +195,8 @@ function resolveRow(provider, role, model, effort) {
|
|
|
162
195
|
const hasModel = model !== undefined;
|
|
163
196
|
const hasEffort = effort !== undefined;
|
|
164
197
|
const resolvedModel = hasModel ? String(model) : preset.model;
|
|
165
|
-
if (resolvedModel ===
|
|
166
|
-
throw new Error(`${role} route ${
|
|
198
|
+
if (resolvedModel === LEGACY_CHILD_MODEL && hasEffort && effort === "xhigh") {
|
|
199
|
+
throw new Error(`${role} route ${resolvedModel} xhigh is a forbidden pair; legacy Luna runs at high or max`);
|
|
167
200
|
}
|
|
168
201
|
const rowsForModel = catalog.rows.filter((row) => row.model === resolvedModel);
|
|
169
202
|
if (!rowsForModel.length) {
|
|
@@ -244,10 +277,10 @@ function inspectManagedRoute(document, expectedProvider, route = managedRequest(
|
|
|
244
277
|
&& childModel === route.childModel
|
|
245
278
|
&& childEffort === route.childEffort;
|
|
246
279
|
const legacyConfigured = parentProvider === expectedProvider
|
|
247
|
-
&& parentModel ===
|
|
280
|
+
&& parentModel === LEGACY_CHILD_MODEL
|
|
248
281
|
&& parentEffort === "max"
|
|
249
|
-
&& childModel ===
|
|
250
|
-
&&
|
|
282
|
+
&& childModel === LEGACY_CHILD_MODEL
|
|
283
|
+
&& LEGACY_LUNA_EFFORTS.has(childEffort);
|
|
251
284
|
if (!configured && !legacyConfigured) {
|
|
252
285
|
return {
|
|
253
286
|
status: "unavailable",
|
|
@@ -359,8 +392,18 @@ function formatManagedRoute(route) {
|
|
|
359
392
|
module.exports = {
|
|
360
393
|
ASTRA_EFFORTS,
|
|
361
394
|
ASTRA_MODEL,
|
|
395
|
+
CHILD_MODEL,
|
|
396
|
+
GPT6_LEAD_EFFORTS,
|
|
397
|
+
GPT6_LUNA_EFFORTS,
|
|
398
|
+
LEGACY_LUNA_EFFORTS,
|
|
399
|
+
LEGACY_CHILD_MODEL,
|
|
400
|
+
LEGACY_SOL_MODEL,
|
|
401
|
+
LUNA_EFFORTS,
|
|
402
|
+
LUNA_MODELS,
|
|
362
403
|
MANAGED_PROVIDER_MODELS,
|
|
404
|
+
MODEL_IDS,
|
|
363
405
|
OPENAI_PROVIDER_ID,
|
|
406
|
+
SOL_MODEL,
|
|
364
407
|
PROVIDER_IDS,
|
|
365
408
|
ROUTE_CATALOG,
|
|
366
409
|
XAI_PROVIDER_ID,
|
package/src/lib/skillPayload.js
CHANGED
|
@@ -16,7 +16,7 @@ const MAX_PAYLOAD_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
|
16
16
|
const requiredSkills = [
|
|
17
17
|
"lit-burnoff-file", "autoconference", "autoresearch", "browser-drive", "comment-checker", "debugging",
|
|
18
18
|
"deep-interview",
|
|
19
|
-
"frontend-ui-ux", "lit-commit", "lit-crucible", "lit-init",
|
|
19
|
+
"frontend-ui-ux", "readme-studio", "lit-commit", "lit-crucible", "lit-init",
|
|
20
20
|
"lit-korean", "lit-comprehend", "lit-handoff", "lit-plan", "lit-recap",
|
|
21
21
|
"lit-scientific-visualization", "litgoal", "litresearch", "litwork", "lsp",
|
|
22
22
|
"lsp-setup", "lit-code", "refactor", "lit-burnoff", "review-work",
|