infinity-harness 2.8.9 → 2.8.11
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/CHANGELOG.md +18 -0
- package/dist/extensions/infinity-harness/index.js +3614 -0
- package/dist/extensions/infinity-harness/index.js.map +1 -0
- package/dist/src/approval.js +154 -0
- package/dist/src/approval.js.map +1 -0
- package/dist/src/core/brief.js +309 -0
- package/dist/src/core/brief.js.map +1 -0
- package/dist/src/core/config.js +539 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/exec.js +106 -0
- package/dist/src/core/exec.js.map +1 -0
- package/dist/src/core/featureList.js +365 -0
- package/dist/src/core/featureList.js.map +1 -0
- package/dist/src/core/fsx.js +123 -0
- package/dist/src/core/fsx.js.map +1 -0
- package/dist/src/core/gates.js +490 -0
- package/dist/src/core/gates.js.map +1 -0
- package/dist/src/core/init.js +480 -0
- package/dist/src/core/init.js.map +1 -0
- package/dist/src/core/lock.js +183 -0
- package/dist/src/core/lock.js.map +1 -0
- package/dist/src/core/modelRouter.js +185 -0
- package/dist/src/core/modelRouter.js.map +1 -0
- package/dist/src/core/paths.js +129 -0
- package/dist/src/core/paths.js.map +1 -0
- package/dist/src/core/phases.js +254 -0
- package/dist/src/core/phases.js.map +1 -0
- package/dist/src/core/plan.js +15 -0
- package/dist/src/core/plan.js.map +1 -0
- package/dist/src/core/runState.js +126 -0
- package/dist/src/core/runState.js.map +1 -0
- package/dist/src/core/settings.js +877 -0
- package/dist/src/core/settings.js.map +1 -0
- package/dist/src/core/skills.js +319 -0
- package/dist/src/core/skills.js.map +1 -0
- package/dist/src/core/skillsAudit.js +194 -0
- package/dist/src/core/skillsAudit.js.map +1 -0
- package/dist/src/core/types.js +77 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/daemon/budget.js +85 -0
- package/dist/src/daemon/budget.js.map +1 -0
- package/dist/src/daemon/guard.js +122 -0
- package/dist/src/daemon/guard.js.map +1 -0
- package/dist/src/daemon/index.js +461 -0
- package/dist/src/daemon/index.js.map +1 -0
- package/dist/src/daemon/isolation.js +84 -0
- package/dist/src/daemon/isolation.js.map +1 -0
- package/dist/src/daemon/preflight.js +131 -0
- package/dist/src/daemon/preflight.js.map +1 -0
- package/dist/src/daemon/server.js +174 -0
- package/dist/src/daemon/server.js.map +1 -0
- package/dist/src/daemon/supervisorState.js +42 -0
- package/dist/src/daemon/supervisorState.js.map +1 -0
- package/dist/src/daemon/worker.js +239 -0
- package/dist/src/daemon/worker.js.map +1 -0
- package/dist/src/daemon/worktree.js +102 -0
- package/dist/src/daemon/worktree.js.map +1 -0
- package/dist/src/escalate.js +312 -0
- package/dist/src/escalate.js.map +1 -0
- package/dist/src/exec/piWorker.js +630 -0
- package/dist/src/exec/piWorker.js.map +1 -0
- package/dist/src/goal.js +317 -0
- package/dist/src/goal.js.map +1 -0
- package/dist/src/goalLoop.js +374 -0
- package/dist/src/goalLoop.js.map +1 -0
- package/dist/src/goalSpec.js +397 -0
- package/dist/src/goalSpec.js.map +1 -0
- package/dist/src/goalState.js +255 -0
- package/dist/src/goalState.js.map +1 -0
- package/dist/src/handoff.js +205 -0
- package/dist/src/handoff.js.map +1 -0
- package/dist/src/intake.js +203 -0
- package/dist/src/intake.js.map +1 -0
- package/dist/src/loop.js +592 -0
- package/dist/src/loop.js.map +1 -0
- package/dist/src/modelRouter.js +216 -0
- package/dist/src/modelRouter.js.map +1 -0
- package/dist/src/remote.js +246 -0
- package/dist/src/remote.js.map +1 -0
- package/dist/src/replan.js +262 -0
- package/dist/src/replan.js.map +1 -0
- package/dist/src/review.js +54 -0
- package/dist/src/review.js.map +1 -0
- package/dist/src/rework.js +241 -0
- package/dist/src/rework.js.map +1 -0
- package/dist/src/runState.js +4 -0
- package/dist/src/runState.js.map +1 -0
- package/dist/src/scheduler.js +270 -0
- package/dist/src/scheduler.js.map +1 -0
- package/dist/src/supervisor.js +787 -0
- package/dist/src/supervisor.js.map +1 -0
- package/dist/src/taskList.js +430 -0
- package/dist/src/taskList.js.map +1 -0
- package/dist/src/ui/config.js +268 -0
- package/dist/src/ui/config.js.map +1 -0
- package/dist/src/ui/dashboard.js +1288 -0
- package/dist/src/ui/dashboard.js.map +1 -0
- package/dist/src/ui/display.js +229 -0
- package/dist/src/ui/display.js.map +1 -0
- package/dist/src/ui/planTree.js +219 -0
- package/dist/src/ui/planTree.js.map +1 -0
- package/dist/src/ui/theme.js +298 -0
- package/dist/src/ui/theme.js.map +1 -0
- package/dist/src/ui/viewState.js +65 -0
- package/dist/src/ui/viewState.js.map +1 -0
- package/dist/src/ui/widget.js +721 -0
- package/dist/src/ui/widget.js.map +1 -0
- package/dist/src/ui/wizard.js +540 -0
- package/dist/src/ui/wizard.js.map +1 -0
- package/dist/src/unstuck.js +210 -0
- package/dist/src/unstuck.js.map +1 -0
- package/dist/src/worker.js +267 -0
- package/dist/src/worker.js.map +1 -0
- package/dist/src/workflow.js +250 -0
- package/dist/src/workflow.js.map +1 -0
- package/dist/tests/approval.test.js +144 -0
- package/dist/tests/approval.test.js.map +1 -0
- package/dist/tests/brief.test.js +271 -0
- package/dist/tests/brief.test.js.map +1 -0
- package/dist/tests/config.test.js +320 -0
- package/dist/tests/config.test.js.map +1 -0
- package/dist/tests/dashboard.test.js +277 -0
- package/dist/tests/dashboard.test.js.map +1 -0
- package/dist/tests/display.test.js +229 -0
- package/dist/tests/display.test.js.map +1 -0
- package/dist/tests/escalate.test.js +272 -0
- package/dist/tests/escalate.test.js.map +1 -0
- package/dist/tests/featureList.test.js +429 -0
- package/dist/tests/featureList.test.js.map +1 -0
- package/dist/tests/gates.test.js +333 -0
- package/dist/tests/gates.test.js.map +1 -0
- package/dist/tests/goal.test.js +229 -0
- package/dist/tests/goal.test.js.map +1 -0
- package/dist/tests/goalLoop.test.js +170 -0
- package/dist/tests/goalLoop.test.js.map +1 -0
- package/dist/tests/goalSpec.test.js +146 -0
- package/dist/tests/goalSpec.test.js.map +1 -0
- package/dist/tests/goalState.test.js +202 -0
- package/dist/tests/goalState.test.js.map +1 -0
- package/dist/tests/handoff.test.js +127 -0
- package/dist/tests/handoff.test.js.map +1 -0
- package/dist/tests/init.test.js +264 -0
- package/dist/tests/init.test.js.map +1 -0
- package/dist/tests/intake.test.js +288 -0
- package/dist/tests/intake.test.js.map +1 -0
- package/dist/tests/loop.test.js +453 -0
- package/dist/tests/loop.test.js.map +1 -0
- package/dist/tests/modelRouter.test.js +131 -0
- package/dist/tests/modelRouter.test.js.map +1 -0
- package/dist/tests/phases.test.js +244 -0
- package/dist/tests/phases.test.js.map +1 -0
- package/dist/tests/planTree.test.js +190 -0
- package/dist/tests/planTree.test.js.map +1 -0
- package/dist/tests/remote.test.js +380 -0
- package/dist/tests/remote.test.js.map +1 -0
- package/dist/tests/replan.test.js +113 -0
- package/dist/tests/replan.test.js.map +1 -0
- package/dist/tests/review.test.js +77 -0
- package/dist/tests/review.test.js.map +1 -0
- package/dist/tests/rework.test.js +109 -0
- package/dist/tests/rework.test.js.map +1 -0
- package/dist/tests/routing-live.test.js +121 -0
- package/dist/tests/routing-live.test.js.map +1 -0
- package/dist/tests/runState.test.js +73 -0
- package/dist/tests/runState.test.js.map +1 -0
- package/dist/tests/settings.test.js +311 -0
- package/dist/tests/settings.test.js.map +1 -0
- package/dist/tests/skills.test.js +387 -0
- package/dist/tests/skills.test.js.map +1 -0
- package/dist/tests/supervisor.test.js +437 -0
- package/dist/tests/supervisor.test.js.map +1 -0
- package/dist/tests/surface.test.js +203 -0
- package/dist/tests/surface.test.js.map +1 -0
- package/dist/tests/taskList.test.js +376 -0
- package/dist/tests/taskList.test.js.map +1 -0
- package/dist/tests/theme.test.js +149 -0
- package/dist/tests/theme.test.js.map +1 -0
- package/dist/tests/unstuck.test.js +268 -0
- package/dist/tests/unstuck.test.js.map +1 -0
- package/dist/tests/widget.test.js +424 -0
- package/dist/tests/widget.test.js.map +1 -0
- package/dist/tests/worker.test.js +306 -0
- package/dist/tests/worker.test.js.map +1 -0
- package/dist/tests/workflow.test.js +187 -0
- package/dist/tests/workflow.test.js.map +1 -0
- package/extensions/infinity-harness/index.ts +39 -12
- package/package.json +5 -2
- package/src/core/modelRouter.ts +23 -1
- package/src/daemon/index.ts +3 -3
- package/src/daemon/worker.ts +28 -5
- package/src/ui/config.ts +25 -1
- package/src/ui/wizard.ts +10 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infinity-harness",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.11",
|
|
4
4
|
"description": "A pi agent extension that runs a gated build pipeline unattended \u2014 enforces phases, validates with deterministic gates, and keeps working for hours or days without losing the plan.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"pi": {
|
|
21
21
|
"extensions": [
|
|
22
|
+
"./dist/extensions",
|
|
22
23
|
"./extensions"
|
|
23
24
|
],
|
|
24
25
|
"skills": [
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
30
|
"extensions/",
|
|
31
|
+
"dist/",
|
|
30
32
|
"src/",
|
|
31
33
|
"types/",
|
|
32
34
|
"harness/skills/",
|
|
@@ -51,7 +53,8 @@
|
|
|
51
53
|
"scripts": {
|
|
52
54
|
"test": "node scripts/run-tests.mjs",
|
|
53
55
|
"check": "tsc --noEmit",
|
|
54
|
-
"build": "tsc
|
|
56
|
+
"build": "tsc -p tsconfig.build.json",
|
|
57
|
+
"prepare": "npm run build",
|
|
55
58
|
"e2e": "node scripts/e2e.mjs"
|
|
56
59
|
},
|
|
57
60
|
"homepage": "https://github.com/bakr-bagaber/infinity-harness#readme",
|
package/src/core/modelRouter.ts
CHANGED
|
@@ -13,8 +13,30 @@ import type { TierMap, TierSpec, HarnessConfig, FeatureList, Phase, Difficulty }
|
|
|
13
13
|
export type ThinkingLevel = import("./types.ts").ThinkingLevel;
|
|
14
14
|
export type TierId = import("./types.ts").TierId;
|
|
15
15
|
|
|
16
|
-
export function clampThinkingForProvider(provider: string, level: string | "" | undefined): string | "" {
|
|
16
|
+
export function clampThinkingForProvider(provider: string, level: string | "" | undefined, modelForCheck?: unknown): string | "" {
|
|
17
17
|
if (!level) return (level ?? "") as string | "";
|
|
18
|
+
// If we have the actual model, use pi-default truth (getSupportedThinkingLevels semantics)
|
|
19
|
+
try {
|
|
20
|
+
const m = modelForCheck as { reasoning?: boolean; thinkingLevelMap?: Record<string, string | null> } | null | undefined;
|
|
21
|
+
if (m && typeof m.reasoning === "boolean") {
|
|
22
|
+
if (m.reasoning === false) return level === "off" || level === "" ? (level as string | "") : "off";
|
|
23
|
+
const map = m.thinkingLevelMap ?? {};
|
|
24
|
+
const all = ["off","minimal","low","medium","high","xhigh","max"] as const;
|
|
25
|
+
const supported = all.filter(l => {
|
|
26
|
+
const v = (map as Record<string, string | null | undefined>)[l];
|
|
27
|
+
if (v === null) return false;
|
|
28
|
+
if ((l === "xhigh" || l === "max") && v === undefined) return false;
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
if (supported.includes(level as typeof all[number])) return level as string | "";
|
|
32
|
+
// clamp to nearest supported (prefer lower)
|
|
33
|
+
const idx = (all as readonly string[]).indexOf(level);
|
|
34
|
+
for (let i = idx; i >= 0; i--) if (supported.includes(all[i] as typeof all[number])) return all[i] as string | "";
|
|
35
|
+
for (let i = idx+1; i < all.length; i++) if (supported.includes(all[i] as typeof all[number])) return all[i] as string | "";
|
|
36
|
+
return supported[0] ?? "off";
|
|
37
|
+
}
|
|
38
|
+
} catch {}
|
|
39
|
+
// Fallback: old provider-string heuristic for when model not available (e.g. in config migration)
|
|
18
40
|
const pp = String(provider || "").toLowerCase();
|
|
19
41
|
const isLocal = pp === "lm-studio" || pp.startsWith("lm-studio/") || pp === "lmstudio";
|
|
20
42
|
if (!isLocal) return level as string | "";
|
package/src/daemon/index.ts
CHANGED
|
@@ -275,7 +275,7 @@ async function runLoop(targetDir: string): Promise<void> {
|
|
|
275
275
|
model: askedModel,
|
|
276
276
|
askedModel,
|
|
277
277
|
servedModel: null,
|
|
278
|
-
thinking: clampThinkingForProvider(routed.provider, ((tierSpec as { thinkingLevel?: string } | null)?.thinkingLevel as unknown as string) ?? "
|
|
278
|
+
thinking: clampThinkingForProvider(routed.provider, ((tierSpec as { thinkingLevel?: string } | null)?.thinkingLevel as unknown as string) ?? "") || undefined,
|
|
279
279
|
state: "starting",
|
|
280
280
|
doing: "starting",
|
|
281
281
|
startedAt: new Date().toISOString(),
|
|
@@ -298,7 +298,7 @@ async function runLoop(targetDir: string): Promise<void> {
|
|
|
298
298
|
const workerFactory = await import("./worker.ts");
|
|
299
299
|
workerHandle = await workerFactory.createWorker({
|
|
300
300
|
cwd: targetDir,
|
|
301
|
-
modelSpec: { provider: routed.provider, id: routed.id, thinkingLevel: clampThinkingForProvider(routed.provider, ((tierSpec as { thinkingLevel?: string } | null)?.thinkingLevel as unknown as string) ?? "
|
|
301
|
+
modelSpec: { provider: routed.provider, id: routed.id, thinkingLevel: clampThinkingForProvider(routed.provider, ((tierSpec as { thinkingLevel?: string } | null)?.thinkingLevel as unknown as string) ?? "") || undefined },
|
|
302
302
|
askedModel,
|
|
303
303
|
sessionManagerDir: `harness/sessions/${workerLabel.replace(/[^a-z0-9._-]/gi, "-")}`,
|
|
304
304
|
customTools: (await import("./isolation.ts")).harnessToolsForWorker() as unknown[],
|
|
@@ -317,7 +317,7 @@ async function runLoop(targetDir: string): Promise<void> {
|
|
|
317
317
|
if (!workerHandle) {
|
|
318
318
|
workerHandle = await workerFactory.createWorker({
|
|
319
319
|
cwd: targetDir,
|
|
320
|
-
modelSpec: { provider: routed.provider, id: routed.id, thinkingLevel: clampThinkingForProvider(routed.provider, ((tierSpec as { thinkingLevel?: string } | null)?.thinkingLevel as unknown as string) ?? "
|
|
320
|
+
modelSpec: { provider: routed.provider, id: routed.id, thinkingLevel: clampThinkingForProvider(routed.provider, ((tierSpec as { thinkingLevel?: string } | null)?.thinkingLevel as unknown as string) ?? "") || undefined },
|
|
321
321
|
askedModel,
|
|
322
322
|
sessionManagerDir: `harness/sessions/${workerLabel.replace(/[^a-z0-9._-]/gi, "-")}`,
|
|
323
323
|
customTools: (await import("./isolation.ts")).harnessToolsForWorker() as unknown[],
|
package/src/daemon/worker.ts
CHANGED
|
@@ -110,12 +110,35 @@ export async function createWorker(opts: CreateWorkerOpts): Promise<{
|
|
|
110
110
|
? SessionManager.create(opts.cwd, opts.sessionManagerDir)
|
|
111
111
|
: SessionManager.inMemory(opts.cwd);
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
// inherit means inherit — don't force medium. Only clamp when explicitly set.
|
|
114
|
+
let thinkingLevel: string | undefined = (opts.thinkingLevel ?? opts.modelSpec.thinkingLevel ?? undefined) as unknown as string | undefined;
|
|
115
|
+
// capability-aware clamp: use pi-default supported levels for the actual model, not provider string
|
|
115
116
|
try {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
const mod = model as unknown as { reasoning?: boolean; thinkingLevelMap?: Record<string, string | null> } | null;
|
|
118
|
+
if (thinkingLevel) {
|
|
119
|
+
// inline getSupportedThinkingLevels semantics
|
|
120
|
+
if (mod && typeof mod.reasoning === "boolean" && mod.reasoning === false) {
|
|
121
|
+
if (thinkingLevel !== "off") thinkingLevel = "off";
|
|
122
|
+
} else if (mod && mod.reasoning === true) {
|
|
123
|
+
const map = mod.thinkingLevelMap ?? {};
|
|
124
|
+
const all = ["off","minimal","low","medium","high","xhigh","max"] as const;
|
|
125
|
+
const supported = all.filter(l => {
|
|
126
|
+
const v = (map as Record<string, string | null | undefined>)[l];
|
|
127
|
+
if (v === null) return false;
|
|
128
|
+
if ((l === "xhigh" || l === "max") && v === undefined) return false;
|
|
129
|
+
return true;
|
|
130
|
+
});
|
|
131
|
+
if (!supported.includes(thinkingLevel as typeof all[number])) {
|
|
132
|
+
const idx = (all as readonly string[]).indexOf(thinkingLevel);
|
|
133
|
+
let found: string | null = null;
|
|
134
|
+
for (let i = idx; i >= 0; i--) if (supported.includes(all[i] as typeof all[number])) { found = all[i] as string; break; }
|
|
135
|
+
if (!found) for (let i = idx+1; i < all.length; i++) if (supported.includes(all[i] as typeof all[number])) { found = all[i] as string; break; }
|
|
136
|
+
thinkingLevel = found ?? supported[0] ?? "off";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} else if (thinkingLevel === undefined) {
|
|
140
|
+
// inherit (undefined) — leave undefined so createAgentSession uses pi-default for that model
|
|
141
|
+
}
|
|
119
142
|
} catch {}
|
|
120
143
|
// B: debug trace of routed model/thinking (readable in harness/daemon.log)
|
|
121
144
|
try { console.log("[worker] model=" + opts.modelSpec.provider + "/" + opts.modelSpec.id + " thinking=" + thinkingLevel + " askedModel=" + opts.askedModel); } catch {}
|
package/src/ui/config.ts
CHANGED
|
@@ -39,6 +39,8 @@ export type ModelChoice = {
|
|
|
39
39
|
ref: string;
|
|
40
40
|
/** What the user sees. */
|
|
41
41
|
label: string;
|
|
42
|
+
/** Pi-default supported thinking levels for this model, or null if unknown. */
|
|
43
|
+
supportedThinkingLevels?: readonly string[];
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
export type ConfigMenuOptions = {
|
|
@@ -167,7 +169,29 @@ async function editSetting(setting: Setting, options: ConfigMenuOptions): Promis
|
|
|
167
169
|
break;
|
|
168
170
|
}
|
|
169
171
|
case "thinking": {
|
|
170
|
-
|
|
172
|
+
// capability-aware: if setting is tiers.X.thinkingLevel etc, filter to what the model actually supports
|
|
173
|
+
let choices: string[] = ["(inherit)", "off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
174
|
+
try {
|
|
175
|
+
const m = setting.path.match(/^tiers.([A-Z]).(provider|id|thinkingLevel)/);
|
|
176
|
+
// For tiers.A/B/C/D/X thinkingLevel, look up that tier's model and its supported levels
|
|
177
|
+
const tierMatch = setting.path.match(/^tiers.([A-Z]).thinkingLevel/);
|
|
178
|
+
if (tierMatch) {
|
|
179
|
+
const tier = tierMatch[1]!;
|
|
180
|
+
const all = readAll(targetDir);
|
|
181
|
+
const tierSpec = (all.config as unknown as { tiers?: Record<string, { provider?: string; id?: string }> }).tiers?.[tier];
|
|
182
|
+
if (tierSpec?.provider && tierSpec?.id) {
|
|
183
|
+
const ref = tierSpec.provider + "/" + tierSpec.id;
|
|
184
|
+
const models = await options.models();
|
|
185
|
+
const found = models.find(x => x.ref === ref) as unknown as { supportedThinkingLevels?: readonly string[] } | undefined;
|
|
186
|
+
if (found?.supportedThinkingLevels?.length) {
|
|
187
|
+
choices = ["(inherit)", ...found.supportedThinkingLevels.filter(l => l !== "off")];
|
|
188
|
+
// ensure off is last fallback if model supports only off
|
|
189
|
+
if (!found.supportedThinkingLevels.includes("off")) choices = ["(inherit)", ...found.supportedThinkingLevels];
|
|
190
|
+
else if (choices.indexOf("off") === -1) choices.splice(1,0,"off");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} catch {}
|
|
171
195
|
const picked = await prompt.select(`${setting.label} — ${setting.help}`, [...choices, BACK]);
|
|
172
196
|
if (picked === undefined || picked === BACK) return false;
|
|
173
197
|
raw = picked;
|
package/src/ui/wizard.ts
CHANGED
|
@@ -153,8 +153,9 @@ async function pickModelChoice(prompt: Prompter, title: string, models: ModelCho
|
|
|
153
153
|
return model?.ref;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
async function pickThinkingLevel(prompt: Prompter, title: string): Promise<ThinkingLevel | "" | undefined> {
|
|
157
|
-
const
|
|
156
|
+
async function pickThinkingLevel(prompt: Prompter, title: string, supported?: readonly string[] | null): Promise<ThinkingLevel | "" | undefined> {
|
|
157
|
+
const levels = Array.isArray(supported) && supported.length ? supported as ThinkingLevel[] : THINKING_LEVELS;
|
|
158
|
+
const picked = await prompt.select(title, [THINK_INHERIT, ...levels]);
|
|
158
159
|
if (picked === undefined) return undefined;
|
|
159
160
|
if (picked === THINK_INHERIT) return "";
|
|
160
161
|
return picked as ThinkingLevel;
|
|
@@ -214,21 +215,25 @@ async function pickModelsStep(
|
|
|
214
215
|
const tiers = ["easy", "moderate", "difficult"] as const;
|
|
215
216
|
const byDifficulty: Record<string, string> = {};
|
|
216
217
|
const thinkingByDifficulty: Partial<Record<string, ThinkingLevel | "">> = {};
|
|
218
|
+
const supportedFor = (ref: string): readonly string[] | null => {
|
|
219
|
+
const m = models.find(x => x.ref === ref) as unknown as { supportedThinkingLevels?: readonly string[] } | undefined;
|
|
220
|
+
return (m as { supportedThinkingLevels?: readonly string[] } | undefined)?.supportedThinkingLevels ?? null;
|
|
221
|
+
};
|
|
217
222
|
for (const tier of tiers) {
|
|
218
223
|
const model = await pickModelChoice(prompt, `${tier.toUpperCase()} tier — model`, models, "");
|
|
219
224
|
if (model === undefined) return undefined;
|
|
220
225
|
byDifficulty[tier] = model;
|
|
221
|
-
const thinking = await pickThinkingLevel(prompt, `${tier.toUpperCase()} tier — thinking level
|
|
226
|
+
const thinking = await pickThinkingLevel(prompt, `${tier.toUpperCase()} tier — thinking level`, model ? supportedFor(model) : null);
|
|
222
227
|
if (thinking === undefined) return undefined;
|
|
223
228
|
thinkingByDifficulty[tier] = thinking;
|
|
224
229
|
}
|
|
225
230
|
const masterModel = await pickModelChoice(prompt, "Consulting master — model (used only when the ladder is exhausted)", models, "");
|
|
226
231
|
if (masterModel === undefined) return undefined;
|
|
227
|
-
const masterThinking = await pickThinkingLevel(prompt, "Consulting master — thinking level");
|
|
232
|
+
const masterThinking = await pickThinkingLevel(prompt, "Consulting master — thinking level", masterModel ? supportedFor(masterModel) : null);
|
|
228
233
|
if (masterThinking === undefined) return undefined;
|
|
229
234
|
const defaultModel = await pickModelChoice(prompt, "Default (tier A) — general work + undifficult tasks — idle under task handoff when every task has difficulty (" + tierScopeNote(handoff) + ")", models, "");
|
|
230
235
|
if (defaultModel === undefined) return undefined;
|
|
231
|
-
const defaultThinking = await pickThinkingLevel(prompt, "Default — thinking level fallback");
|
|
236
|
+
const defaultThinking = await pickThinkingLevel(prompt, "Default — thinking level fallback", defaultModel ? supportedFor(defaultModel) : null);
|
|
232
237
|
if (defaultThinking === undefined) return undefined;
|
|
233
238
|
return {
|
|
234
239
|
router: {
|