open-multi-agent-kit 0.90.4 → 0.90.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/CHANGELOG.md +54 -0
- package/README.md +9 -9
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/codexbar-cli.d.ts +39 -0
- package/dist/codexbar-cli.d.ts.map +1 -0
- package/dist/codexbar-cli.js +230 -0
- package/dist/codexbar-cli.js.map +1 -0
- package/dist/commands/doctor-provider.d.ts.map +1 -1
- package/dist/commands/doctor-provider.js +16 -3
- package/dist/commands/doctor-provider.js.map +1 -1
- package/dist/core/adaptorch-bridge.d.ts +14 -21
- package/dist/core/adaptorch-bridge.d.ts.map +1 -1
- package/dist/core/adaptorch-bridge.js +11 -18
- package/dist/core/adaptorch-bridge.js.map +1 -1
- package/dist/core/agent-session.d.ts +6 -39
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +37 -107
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/codexbar-adapter.d.ts +44 -0
- package/dist/core/codexbar-adapter.d.ts.map +1 -0
- package/dist/core/codexbar-adapter.js +211 -0
- package/dist/core/codexbar-adapter.js.map +1 -0
- package/dist/core/compaction/index.d.ts +2 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +2 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/model-policy.d.ts +9 -0
- package/dist/core/compaction/model-policy.d.ts.map +1 -0
- package/dist/core/compaction/model-policy.js +37 -0
- package/dist/core/compaction/model-policy.js.map +1 -0
- package/dist/core/compaction/resume-policy.d.ts +6 -0
- package/dist/core/compaction/resume-policy.d.ts.map +1 -0
- package/dist/core/compaction/resume-policy.js +8 -0
- package/dist/core/compaction/resume-policy.js.map +1 -0
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +10 -2
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +7 -1
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/domain-loadouts.d.ts.map +1 -1
- package/dist/core/domain-loadouts.js +68 -1
- package/dist/core/domain-loadouts.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +12 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +15 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/grok-harness-dispatch.d.ts +22 -0
- package/dist/core/grok-harness-dispatch.d.ts.map +1 -0
- package/dist/core/grok-harness-dispatch.js +44 -0
- package/dist/core/grok-harness-dispatch.js.map +1 -0
- package/dist/core/grok-harness.d.ts +25 -0
- package/dist/core/grok-harness.d.ts.map +1 -0
- package/dist/core/grok-harness.js +61 -0
- package/dist/core/grok-harness.js.map +1 -0
- package/dist/core/grok-playbook.d.ts +7 -0
- package/dist/core/grok-playbook.d.ts.map +1 -0
- package/dist/core/grok-playbook.js +34 -0
- package/dist/core/grok-playbook.js.map +1 -0
- package/dist/core/reasoning-router-bias.d.ts +11 -23
- package/dist/core/reasoning-router-bias.d.ts.map +1 -1
- package/dist/core/reasoning-router-bias.js +9 -18
- package/dist/core/reasoning-router-bias.js.map +1 -1
- package/dist/core/reasoning-router-resolver.d.ts +44 -0
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -0
- package/dist/core/reasoning-router-resolver.js +79 -0
- package/dist/core/reasoning-router-resolver.js.map +1 -0
- package/dist/core/reasoning-router-v4-weights.d.ts +28 -72
- package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4-weights.js +16 -60
- package/dist/core/reasoning-router-v4-weights.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +25 -70
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +46 -144
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/router-feedback-collector.d.ts +13 -16
- package/dist/core/router-feedback-collector.d.ts.map +1 -1
- package/dist/core/router-feedback-collector.js +5 -8
- package/dist/core/router-feedback-collector.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +31 -12
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +4 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +16 -98
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +3 -2
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +42 -17
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/correctness-wall.md +117 -0
- package/docs/grok-harness.md +63 -0
- package/docs/loadout-domains/README.md +2 -1
- package/docs/loadout-domains/ai-agent-ops.md +8 -1
- package/docs/loadout-domains/grok-harness.md +74 -0
- package/docs/providers.md +4 -0
- package/docs/usage.md +11 -12
- package/examples/extensions/correctness-wall/LOADOUT.md +87 -0
- package/examples/extensions/correctness-wall/README.md +111 -0
- package/examples/extensions/correctness-wall/adjudication-fixture.ts +151 -0
- package/examples/extensions/correctness-wall/index.ts +470 -0
- package/examples/extensions/correctness-wall/repair-state.ts +77 -0
- package/examples/extensions/correctness-wall/wall-cache.ts +81 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/agent-capability-router.test.ts +123 -0
- package/examples/extensions/subagent/agent-capability-router.ts +274 -0
- package/examples/extensions/subagent/agents/planner.md +3 -0
- package/examples/extensions/subagent/agents/reviewer.md +3 -0
- package/examples/extensions/subagent/agents/scout.md +3 -0
- package/examples/extensions/subagent/agents/worker.md +2 -0
- package/examples/extensions/subagent/agents.ts +14 -0
- package/examples/extensions/subagent/capabilities.ts +368 -0
- package/examples/extensions/subagent/domain-profiles.ts +1089 -0
- package/examples/extensions/subagent/index.ts +71 -3
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +5 -5
- package/dist/core/compactor.d.ts +0 -42
- package/dist/core/compactor.d.ts.map +0 -1
- package/dist/core/compactor.js +0 -128
- package/dist/core/compactor.js.map +0 -1
- package/dist/core/reasoning-router-v2.d.ts +0 -94
- package/dist/core/reasoning-router-v2.d.ts.map +0 -1
- package/dist/core/reasoning-router-v2.js +0 -288
- package/dist/core/reasoning-router-v2.js.map +0 -1
- package/dist/core/reasoning-router-v3.d.ts +0 -15
- package/dist/core/reasoning-router-v3.d.ts.map +0 -1
- package/dist/core/reasoning-router-v3.js +0 -193
- package/dist/core/reasoning-router-v3.js.map +0 -1
- package/dist/core/reasoning-router-weights.d.ts +0 -155
- package/dist/core/reasoning-router-weights.d.ts.map +0 -1
- package/dist/core/reasoning-router-weights.js +0 -204
- package/dist/core/reasoning-router-weights.js.map +0 -1
- package/dist/core/reasoning-router.d.ts +0 -44
- package/dist/core/reasoning-router.d.ts.map +0 -1
- package/dist/core/reasoning-router.js +0 -138
- package/dist/core/reasoning-router.js.map +0 -1
- package/dist/core/token-optimizer.d.ts +0 -58
- package/dist/core/token-optimizer.d.ts.map +0 -1
- package/dist/core/token-optimizer.js +0 -179
- package/dist/core/token-optimizer.js.map +0 -1
|
@@ -20,15 +20,36 @@ import type { AgentToolResult } from "omk-agent-core";
|
|
|
20
20
|
import type { Message } from "omk-ai";
|
|
21
21
|
import { StringEnum } from "omk-ai";
|
|
22
22
|
import { Container, Markdown, Spacer, Text } from "omk-tui";
|
|
23
|
-
import { type ExtensionAPI, getMarkdownTheme, withFileMutationQueue } from "open-multi-agent-kit";
|
|
23
|
+
import { type ExtensionAPI, getAgentDir, getMarkdownTheme, withFileMutationQueue } from "open-multi-agent-kit";
|
|
24
24
|
import { Type } from "typebox";
|
|
25
|
+
import { deriveCapabilities } from "./agent-capability-router.ts";
|
|
25
26
|
import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.ts";
|
|
27
|
+
import {
|
|
28
|
+
type AgentCapabilities,
|
|
29
|
+
buildCapabilitiesPreamble,
|
|
30
|
+
buildCapabilityCatalog,
|
|
31
|
+
buildEnforcementArgs,
|
|
32
|
+
type CapabilityCatalog,
|
|
33
|
+
parseEmbeddedCapabilities,
|
|
34
|
+
validateCapabilities,
|
|
35
|
+
} from "./capabilities.ts";
|
|
26
36
|
|
|
27
37
|
const MAX_PARALLEL_TASKS = 8;
|
|
28
38
|
const MAX_CONCURRENCY = 4;
|
|
29
39
|
const COLLAPSED_ITEM_COUNT = 10;
|
|
30
40
|
const PER_TASK_OUTPUT_CAP = 50 * 1024;
|
|
31
41
|
|
|
42
|
+
// Capability catalog is expensive to build (scans every SKILL.md on disk); memoize
|
|
43
|
+
// once per dispatcher process.
|
|
44
|
+
let cachedCapabilityCatalog: CapabilityCatalog | null = null;
|
|
45
|
+
|
|
46
|
+
function getCapabilityCatalog(): CapabilityCatalog {
|
|
47
|
+
if (!cachedCapabilityCatalog) {
|
|
48
|
+
cachedCapabilityCatalog = buildCapabilityCatalog({ agentDir: getAgentDir() });
|
|
49
|
+
}
|
|
50
|
+
return cachedCapabilityCatalog;
|
|
51
|
+
}
|
|
52
|
+
|
|
32
53
|
function formatTokens(count: number): string {
|
|
33
54
|
if (count < 1000) return count.toString();
|
|
34
55
|
if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
|
|
@@ -289,6 +310,43 @@ async function runSingleAgent(
|
|
|
289
310
|
if (agent.model) args.push("--model", agent.model);
|
|
290
311
|
if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
|
|
291
312
|
|
|
313
|
+
// Capability routing, three tiers: frontmatter is canonical; the embedded "Assigned
|
|
314
|
+
// capabilities" body section is the fallback for the ~233 broad-catalog agents; the
|
|
315
|
+
// deterministic capability router (name/description keyword classification against the
|
|
316
|
+
// live catalog) is the final fallback for agents with neither (e.g. the ua-* pipeline
|
|
317
|
+
// stages, or any new agent file dropped in without a capability declaration). Validate
|
|
318
|
+
// against the live catalog so unknown (e.g. hallucinated) names are pruned and surfaced.
|
|
319
|
+
const declaredCapabilities = agent.capabilities ?? parseEmbeddedCapabilities(agent.systemPrompt);
|
|
320
|
+
let isAutoDerived = false;
|
|
321
|
+
let effectiveCapabilities: AgentCapabilities | undefined = declaredCapabilities;
|
|
322
|
+
if (!effectiveCapabilities) {
|
|
323
|
+
const derived = deriveCapabilities(agent.name, agent.description, getCapabilityCatalog());
|
|
324
|
+
if (derived.skills.length > 0) {
|
|
325
|
+
effectiveCapabilities = derived;
|
|
326
|
+
isAutoDerived = true;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const validatedCapabilities = effectiveCapabilities
|
|
330
|
+
? validateCapabilities(effectiveCapabilities, getCapabilityCatalog())
|
|
331
|
+
: undefined;
|
|
332
|
+
if (validatedCapabilities) {
|
|
333
|
+
const unknowns = [
|
|
334
|
+
...validatedCapabilities.unknownSkills,
|
|
335
|
+
...validatedCapabilities.unknownMcp,
|
|
336
|
+
...validatedCapabilities.unknownHooks,
|
|
337
|
+
];
|
|
338
|
+
if (unknowns.length > 0) {
|
|
339
|
+
console.warn(`[subagent] agent "${agentName}" declares unknown capabilities: ${unknowns.join(", ")}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// Opt-in hard enforcement: restrict the subprocess to the declared skills only, via the
|
|
343
|
+
// existing --no-skills + --skill <path> flags (no core change). Off by default.
|
|
344
|
+
if (agent.enforceCapabilities && validatedCapabilities) {
|
|
345
|
+
for (const arg of buildEnforcementArgs(validatedCapabilities, getCapabilityCatalog())) {
|
|
346
|
+
args.push(arg);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
292
350
|
let tmpPromptDir: string | null = null;
|
|
293
351
|
let tmpPromptPath: string | null = null;
|
|
294
352
|
|
|
@@ -314,8 +372,18 @@ async function runSingleAgent(
|
|
|
314
372
|
};
|
|
315
373
|
|
|
316
374
|
try {
|
|
317
|
-
|
|
318
|
-
|
|
375
|
+
let systemPromptForSpawn = agent.systemPrompt;
|
|
376
|
+
if (validatedCapabilities) {
|
|
377
|
+
const preamble = buildCapabilitiesPreamble(validatedCapabilities);
|
|
378
|
+
if (preamble) {
|
|
379
|
+
const prefixed = isAutoDerived
|
|
380
|
+
? `${preamble}\n(auto-derived: no declared capabilities found; classified from agent name/description by the deterministic capability router, not curated)`
|
|
381
|
+
: preamble;
|
|
382
|
+
systemPromptForSpawn = `${prefixed}\n\n${agent.systemPrompt}`;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (systemPromptForSpawn.trim()) {
|
|
386
|
+
const tmp = await writePromptToTempFile(agent.name, systemPromptForSpawn);
|
|
319
387
|
tmpPromptDir = tmp.dir;
|
|
320
388
|
tmpPromptPath = tmp.filePath;
|
|
321
389
|
args.push("--append-system-prompt", tmpPromptPath);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omk-extension-with-deps",
|
|
3
|
-
"version": "0.90.
|
|
3
|
+
"version": "0.90.6",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omk-extension-with-deps",
|
|
9
|
-
"version": "0.90.
|
|
9
|
+
"version": "0.90.6",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|
|
@@ -26,7 +26,7 @@ if (process.env.MY_ANTHROPIC_KEY) {
|
|
|
26
26
|
// Model registry with no custom models.json
|
|
27
27
|
const modelRegistry = ModelRegistry.inMemory(authStorage);
|
|
28
28
|
|
|
29
|
-
const model = getModel("anthropic", "claude-sonnet-4-
|
|
29
|
+
const model = getModel("anthropic", "claude-sonnet-4-5");
|
|
30
30
|
if (!model) throw new Error("Model not found");
|
|
31
31
|
|
|
32
32
|
// In-memory settings with overrides
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-multi-agent-kit",
|
|
3
|
-
"version": "0.90.
|
|
3
|
+
"version": "0.90.6",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "open-multi-agent-kit",
|
|
9
|
-
"version": "0.90.
|
|
9
|
+
"version": "0.90.6",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"omk-agent-core": "^0.90.
|
|
13
|
-
"omk-ai": "^0.90.
|
|
14
|
-
"omk-tui": "^0.90.
|
|
12
|
+
"omk-agent-core": "^0.90.6",
|
|
13
|
+
"omk-ai": "^0.90.6",
|
|
14
|
+
"omk-tui": "^0.90.6",
|
|
15
15
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
16
16
|
"chalk": "5.6.2",
|
|
17
17
|
"cross-spawn": "7.0.6",
|
|
@@ -1423,11 +1423,11 @@
|
|
|
1423
1423
|
}
|
|
1424
1424
|
},
|
|
1425
1425
|
"node_modules/omk-agent-core": {
|
|
1426
|
-
"version": "0.90.
|
|
1427
|
-
"resolved": "https://registry.npmjs.org/omk-agent-core/-/omk-agent-core-0.90.
|
|
1426
|
+
"version": "0.90.6",
|
|
1427
|
+
"resolved": "https://registry.npmjs.org/omk-agent-core/-/omk-agent-core-0.90.6.tgz",
|
|
1428
1428
|
"license": "MIT",
|
|
1429
1429
|
"dependencies": {
|
|
1430
|
-
"omk-ai": "^0.90.
|
|
1430
|
+
"omk-ai": "^0.90.6",
|
|
1431
1431
|
"ignore": "7.0.5",
|
|
1432
1432
|
"typebox": "1.1.38",
|
|
1433
1433
|
"yaml": "2.9.0"
|
|
@@ -1437,8 +1437,8 @@
|
|
|
1437
1437
|
}
|
|
1438
1438
|
},
|
|
1439
1439
|
"node_modules/omk-ai": {
|
|
1440
|
-
"version": "0.90.
|
|
1441
|
-
"resolved": "https://registry.npmjs.org/omk-ai/-/omk-ai-0.90.
|
|
1440
|
+
"version": "0.90.6",
|
|
1441
|
+
"resolved": "https://registry.npmjs.org/omk-ai/-/omk-ai-0.90.6.tgz",
|
|
1442
1442
|
"license": "MIT",
|
|
1443
1443
|
"dependencies": {
|
|
1444
1444
|
"@anthropic-ai/sdk": "0.91.1",
|
|
@@ -1460,8 +1460,8 @@
|
|
|
1460
1460
|
}
|
|
1461
1461
|
},
|
|
1462
1462
|
"node_modules/omk-tui": {
|
|
1463
|
-
"version": "0.90.
|
|
1464
|
-
"resolved": "https://registry.npmjs.org/omk-tui/-/omk-tui-0.90.
|
|
1463
|
+
"version": "0.90.6",
|
|
1464
|
+
"resolved": "https://registry.npmjs.org/omk-tui/-/omk-tui-0.90.6.tgz",
|
|
1465
1465
|
"license": "MIT",
|
|
1466
1466
|
"dependencies": {
|
|
1467
1467
|
"get-east-asian-width": "1.6.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-multi-agent-kit",
|
|
3
|
-
"version": "0.90.
|
|
3
|
+
"version": "0.90.6",
|
|
4
4
|
"description": "OMK (Open Multi-Agent Kit) coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"omkConfig": {
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"omk-agent-core": "^0.90.
|
|
45
|
-
"omk-ai": "^0.90.
|
|
46
|
-
"omk-tui": "^0.90.
|
|
44
|
+
"omk-agent-core": "^0.90.6",
|
|
45
|
+
"omk-ai": "^0.90.6",
|
|
46
|
+
"omk-tui": "^0.90.6",
|
|
47
47
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
48
48
|
"chalk": "5.6.2",
|
|
49
49
|
"cross-spawn": "7.0.6",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"license": "MIT",
|
|
92
92
|
"repository": {
|
|
93
93
|
"type": "git",
|
|
94
|
-
"url": "git+https://github.com/dmae97/
|
|
94
|
+
"url": "git+https://github.com/dmae97/omk.git",
|
|
95
95
|
"directory": "packages/coding-agent"
|
|
96
96
|
},
|
|
97
97
|
"engines": {
|
package/dist/core/compactor.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
export interface CompactionTurn {
|
|
3
|
-
index: number;
|
|
4
|
-
role: string;
|
|
5
|
-
content: string;
|
|
6
|
-
timestamp: number;
|
|
7
|
-
importance?: number;
|
|
8
|
-
}
|
|
9
|
-
export interface CompactionResult {
|
|
10
|
-
preserved: CompactionTurn[];
|
|
11
|
-
summarized: CompactionTurn[];
|
|
12
|
-
summary: string;
|
|
13
|
-
originalCount: number;
|
|
14
|
-
finalCount: number;
|
|
15
|
-
compressionRatio: number;
|
|
16
|
-
}
|
|
17
|
-
export declare class SlidingWindowCompactor extends EventEmitter {
|
|
18
|
-
private windowSize;
|
|
19
|
-
constructor(windowSize?: number);
|
|
20
|
-
compact(turns: CompactionTurn[]): {
|
|
21
|
-
preserved: CompactionTurn[];
|
|
22
|
-
evicted: CompactionTurn[];
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export declare class SemanticDeduplicator extends EventEmitter {
|
|
26
|
-
deduplicate(turns: CompactionTurn[]): CompactionTurn[];
|
|
27
|
-
private normalize;
|
|
28
|
-
}
|
|
29
|
-
export declare class ImportanceScorer extends EventEmitter {
|
|
30
|
-
private keywords;
|
|
31
|
-
score(turn: CompactionTurn): number;
|
|
32
|
-
}
|
|
33
|
-
export declare class ContextCompactor extends EventEmitter {
|
|
34
|
-
private slidingWindow;
|
|
35
|
-
private deduplicator;
|
|
36
|
-
private scorer;
|
|
37
|
-
constructor(windowSize?: number);
|
|
38
|
-
compact(turns: CompactionTurn[], _level?: "gentle" | "moderate" | "aggressive"): CompactionResult;
|
|
39
|
-
private summarize;
|
|
40
|
-
}
|
|
41
|
-
export default ContextCompactor;
|
|
42
|
-
//# sourceMappingURL=compactor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compactor.d.ts","sourceRoot":"","sources":["../../src/core/compactor.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,sBAAuB,SAAQ,YAAY;IACvD,OAAO,CAAC,UAAU,CAAS;IAE3B,YAAY,UAAU,SAAK,EAG1B;IAED,OAAO,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG;QAAE,SAAS,EAAE,cAAc,EAAE,CAAC;QAAC,OAAO,EAAE,cAAc,EAAE,CAAA;KAAE,CAQ3F;CACD;AAED,qBAAa,oBAAqB,SAAQ,YAAY;IACrD,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAarD;IAED,OAAO,CAAC,SAAS;CAGjB;AAED,qBAAa,gBAAiB,SAAQ,YAAY;IACjD,OAAO,CAAC,QAAQ,CAAiE;IAEjF,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAYlC;CACD;AAED,qBAAa,gBAAiB,SAAQ,YAAY;IACjD,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,MAAM,CAAmB;IAEjC,YAAY,UAAU,SAAK,EAK1B;IAED,OAAO,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,MAAM,GAAE,QAAQ,GAAG,UAAU,GAAG,YAAyB,GAAG,gBAAgB,CAsC5G;IAED,OAAO,CAAC,SAAS;CASjB;AAED,eAAe,gBAAgB,CAAC","sourcesContent":["// [DEPRECATED — DEAD CODE] OMK v6.2 — Context Compactor (TypeScript)\n// ==================================================================\n// packages/coding-agent/src/core/compactor.ts\n//\n// STATUS: DEAD CODE — Not imported by any module at runtime.\n// This file is NOT wired into AgentSession or any active pipeline.\n//\n// WHY DEAD:\n// - agent-session.ts imports CompactionResult from compaction/index.ts,\n// NOT from this file. The CompactionResult interfaces are different.\n// - No other file in src/ imports from compactor.ts.\n// - All classes (SlidingWindowCompactor, SemanticDeduplicator,\n// ImportanceScorer, ContextCompactor) are only referenced within this file.\n//\n// ACTUAL COMPACTION SYSTEM:\n// - compaction/compaction.ts → real compaction with LLM summarization\n// - compaction/branch-summarization.ts → branch-specific summarization\n// - compaction/utils.ts → compaction utilities\n// - agent-session.ts imports compact(), prepareCompaction(), shouldCompact()\n// from compaction/index.ts\n//\n// DO NOT MODIFY — preserved for reference only.\n\nimport { EventEmitter } from \"events\";\n\nexport interface CompactionTurn {\n\tindex: number;\n\trole: string;\n\tcontent: string;\n\ttimestamp: number;\n\timportance?: number;\n}\n\nexport interface CompactionResult {\n\tpreserved: CompactionTurn[];\n\tsummarized: CompactionTurn[];\n\tsummary: string;\n\toriginalCount: number;\n\tfinalCount: number;\n\tcompressionRatio: number;\n}\n\nexport class SlidingWindowCompactor extends EventEmitter {\n\tprivate windowSize: number;\n\n\tconstructor(windowSize = 10) {\n\t\tsuper();\n\t\tthis.windowSize = windowSize;\n\t}\n\n\tcompact(turns: CompactionTurn[]): { preserved: CompactionTurn[]; evicted: CompactionTurn[] } {\n\t\tif (turns.length <= this.windowSize) {\n\t\t\treturn { preserved: turns, evicted: [] };\n\t\t}\n\t\treturn {\n\t\t\tpreserved: turns.slice(-this.windowSize),\n\t\t\tevicted: turns.slice(0, -this.windowSize),\n\t\t};\n\t}\n}\n\nexport class SemanticDeduplicator extends EventEmitter {\n\tdeduplicate(turns: CompactionTurn[]): CompactionTurn[] {\n\t\tconst seen = new Set<string>();\n\t\tconst unique: CompactionTurn[] = [];\n\n\t\tfor (const turn of turns) {\n\t\t\tconst key = this.normalize(turn.content);\n\t\t\tif (!seen.has(key)) {\n\t\t\t\tseen.add(key);\n\t\t\t\tunique.push(turn);\n\t\t\t}\n\t\t}\n\n\t\treturn unique;\n\t}\n\n\tprivate normalize(text: string): string {\n\t\treturn text.toLowerCase().replace(/\\s+/g, \" \").trim().substring(0, 100);\n\t}\n}\n\nexport class ImportanceScorer extends EventEmitter {\n\tprivate keywords = [\"refusal\", \"error\", \"strategy\", \"phase\", \"decision\", \"goal\"];\n\n\tscore(turn: CompactionTurn): number {\n\t\tlet score = 0;\n\t\tconst content = turn.content.toLowerCase();\n\n\t\tfor (const kw of this.keywords) {\n\t\t\tif (content.includes(kw)) score += 2;\n\t\t}\n\n\t\tif (turn.role === \"system\") score += 1;\n\t\tif (turn.role === \"assistant\" && content.includes(\"refuse\")) score += 5;\n\n\t\treturn score;\n\t}\n}\n\nexport class ContextCompactor extends EventEmitter {\n\tprivate slidingWindow: SlidingWindowCompactor;\n\tprivate deduplicator: SemanticDeduplicator;\n\tprivate scorer: ImportanceScorer;\n\n\tconstructor(windowSize = 10) {\n\t\tsuper();\n\t\tthis.slidingWindow = new SlidingWindowCompactor(windowSize);\n\t\tthis.deduplicator = new SemanticDeduplicator();\n\t\tthis.scorer = new ImportanceScorer();\n\t}\n\n\tcompact(turns: CompactionTurn[], _level: \"gentle\" | \"moderate\" | \"aggressive\" = \"moderate\"): CompactionResult {\n\t\tconst originalCount = turns.length;\n\n\t\t// 1. Importance scoring\n\t\tconst scored = turns.map((t) => ({ ...t, importance: this.scorer.score(t) }));\n\n\t\t// 2. Protect high-importance turns\n\t\tconst protectedTurns = scored.filter((t) => (t.importance ?? 0) >= 3);\n\t\tconst candidates = scored.filter((t) => (t.importance ?? 0) < 3);\n\n\t\t// 3. Sliding window\n\t\tconst { preserved, evicted } = this.slidingWindow.compact(candidates);\n\n\t\t// 4. Deduplicate evicted\n\t\tconst uniqueEvicted = this.deduplicator.deduplicate(evicted);\n\n\t\t// 5. Summarize evicted\n\t\tconst summary = this.summarize(uniqueEvicted);\n\n\t\t// 6. Assemble result\n\t\tconst finalTurns = [...protectedTurns, ...preserved];\n\t\tif (summary) {\n\t\t\tfinalTurns.push({\n\t\t\t\tindex: -1,\n\t\t\t\trole: \"system\",\n\t\t\t\tcontent: `[Summary]: ${summary}`,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tpreserved: protectedTurns,\n\t\t\tsummarized: uniqueEvicted,\n\t\t\tsummary,\n\t\t\toriginalCount,\n\t\t\tfinalCount: finalTurns.length,\n\t\t\tcompressionRatio: finalTurns.length / originalCount,\n\t\t};\n\t}\n\n\tprivate summarize(turns: CompactionTurn[]): string {\n\t\tif (turns.length === 0) return \"\";\n\t\tconst topics = new Set<string>();\n\t\tfor (const turn of turns) {\n\t\t\tconst words = turn.content.split(/\\s+/).filter((w) => w.length > 4);\n\t\t\tfor (const w of words.slice(0, 3)) topics.add(w);\n\t\t}\n\t\treturn `Topics: ${Array.from(topics).slice(0, 5).join(\", \")}`;\n\t}\n}\n\nexport default ContextCompactor;\n"]}
|
package/dist/core/compactor.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
// [DEPRECATED — DEAD CODE] OMK v6.2 — Context Compactor (TypeScript)
|
|
2
|
-
// ==================================================================
|
|
3
|
-
// packages/coding-agent/src/core/compactor.ts
|
|
4
|
-
//
|
|
5
|
-
// STATUS: DEAD CODE — Not imported by any module at runtime.
|
|
6
|
-
// This file is NOT wired into AgentSession or any active pipeline.
|
|
7
|
-
//
|
|
8
|
-
// WHY DEAD:
|
|
9
|
-
// - agent-session.ts imports CompactionResult from compaction/index.ts,
|
|
10
|
-
// NOT from this file. The CompactionResult interfaces are different.
|
|
11
|
-
// - No other file in src/ imports from compactor.ts.
|
|
12
|
-
// - All classes (SlidingWindowCompactor, SemanticDeduplicator,
|
|
13
|
-
// ImportanceScorer, ContextCompactor) are only referenced within this file.
|
|
14
|
-
//
|
|
15
|
-
// ACTUAL COMPACTION SYSTEM:
|
|
16
|
-
// - compaction/compaction.ts → real compaction with LLM summarization
|
|
17
|
-
// - compaction/branch-summarization.ts → branch-specific summarization
|
|
18
|
-
// - compaction/utils.ts → compaction utilities
|
|
19
|
-
// - agent-session.ts imports compact(), prepareCompaction(), shouldCompact()
|
|
20
|
-
// from compaction/index.ts
|
|
21
|
-
//
|
|
22
|
-
// DO NOT MODIFY — preserved for reference only.
|
|
23
|
-
import { EventEmitter } from "events";
|
|
24
|
-
export class SlidingWindowCompactor extends EventEmitter {
|
|
25
|
-
windowSize;
|
|
26
|
-
constructor(windowSize = 10) {
|
|
27
|
-
super();
|
|
28
|
-
this.windowSize = windowSize;
|
|
29
|
-
}
|
|
30
|
-
compact(turns) {
|
|
31
|
-
if (turns.length <= this.windowSize) {
|
|
32
|
-
return { preserved: turns, evicted: [] };
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
preserved: turns.slice(-this.windowSize),
|
|
36
|
-
evicted: turns.slice(0, -this.windowSize),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export class SemanticDeduplicator extends EventEmitter {
|
|
41
|
-
deduplicate(turns) {
|
|
42
|
-
const seen = new Set();
|
|
43
|
-
const unique = [];
|
|
44
|
-
for (const turn of turns) {
|
|
45
|
-
const key = this.normalize(turn.content);
|
|
46
|
-
if (!seen.has(key)) {
|
|
47
|
-
seen.add(key);
|
|
48
|
-
unique.push(turn);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return unique;
|
|
52
|
-
}
|
|
53
|
-
normalize(text) {
|
|
54
|
-
return text.toLowerCase().replace(/\s+/g, " ").trim().substring(0, 100);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
export class ImportanceScorer extends EventEmitter {
|
|
58
|
-
keywords = ["refusal", "error", "strategy", "phase", "decision", "goal"];
|
|
59
|
-
score(turn) {
|
|
60
|
-
let score = 0;
|
|
61
|
-
const content = turn.content.toLowerCase();
|
|
62
|
-
for (const kw of this.keywords) {
|
|
63
|
-
if (content.includes(kw))
|
|
64
|
-
score += 2;
|
|
65
|
-
}
|
|
66
|
-
if (turn.role === "system")
|
|
67
|
-
score += 1;
|
|
68
|
-
if (turn.role === "assistant" && content.includes("refuse"))
|
|
69
|
-
score += 5;
|
|
70
|
-
return score;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
export class ContextCompactor extends EventEmitter {
|
|
74
|
-
slidingWindow;
|
|
75
|
-
deduplicator;
|
|
76
|
-
scorer;
|
|
77
|
-
constructor(windowSize = 10) {
|
|
78
|
-
super();
|
|
79
|
-
this.slidingWindow = new SlidingWindowCompactor(windowSize);
|
|
80
|
-
this.deduplicator = new SemanticDeduplicator();
|
|
81
|
-
this.scorer = new ImportanceScorer();
|
|
82
|
-
}
|
|
83
|
-
compact(turns, _level = "moderate") {
|
|
84
|
-
const originalCount = turns.length;
|
|
85
|
-
// 1. Importance scoring
|
|
86
|
-
const scored = turns.map((t) => ({ ...t, importance: this.scorer.score(t) }));
|
|
87
|
-
// 2. Protect high-importance turns
|
|
88
|
-
const protectedTurns = scored.filter((t) => (t.importance ?? 0) >= 3);
|
|
89
|
-
const candidates = scored.filter((t) => (t.importance ?? 0) < 3);
|
|
90
|
-
// 3. Sliding window
|
|
91
|
-
const { preserved, evicted } = this.slidingWindow.compact(candidates);
|
|
92
|
-
// 4. Deduplicate evicted
|
|
93
|
-
const uniqueEvicted = this.deduplicator.deduplicate(evicted);
|
|
94
|
-
// 5. Summarize evicted
|
|
95
|
-
const summary = this.summarize(uniqueEvicted);
|
|
96
|
-
// 6. Assemble result
|
|
97
|
-
const finalTurns = [...protectedTurns, ...preserved];
|
|
98
|
-
if (summary) {
|
|
99
|
-
finalTurns.push({
|
|
100
|
-
index: -1,
|
|
101
|
-
role: "system",
|
|
102
|
-
content: `[Summary]: ${summary}`,
|
|
103
|
-
timestamp: Date.now(),
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
preserved: protectedTurns,
|
|
108
|
-
summarized: uniqueEvicted,
|
|
109
|
-
summary,
|
|
110
|
-
originalCount,
|
|
111
|
-
finalCount: finalTurns.length,
|
|
112
|
-
compressionRatio: finalTurns.length / originalCount,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
summarize(turns) {
|
|
116
|
-
if (turns.length === 0)
|
|
117
|
-
return "";
|
|
118
|
-
const topics = new Set();
|
|
119
|
-
for (const turn of turns) {
|
|
120
|
-
const words = turn.content.split(/\s+/).filter((w) => w.length > 4);
|
|
121
|
-
for (const w of words.slice(0, 3))
|
|
122
|
-
topics.add(w);
|
|
123
|
-
}
|
|
124
|
-
return `Topics: ${Array.from(topics).slice(0, 5).join(", ")}`;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
export default ContextCompactor;
|
|
128
|
-
//# sourceMappingURL=compactor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compactor.js","sourceRoot":"","sources":["../../src/core/compactor.ts"],"names":[],"mappings":"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","sourcesContent":["// [DEPRECATED — DEAD CODE] OMK v6.2 — Context Compactor (TypeScript)\n// ==================================================================\n// packages/coding-agent/src/core/compactor.ts\n//\n// STATUS: DEAD CODE — Not imported by any module at runtime.\n// This file is NOT wired into AgentSession or any active pipeline.\n//\n// WHY DEAD:\n// - agent-session.ts imports CompactionResult from compaction/index.ts,\n// NOT from this file. The CompactionResult interfaces are different.\n// - No other file in src/ imports from compactor.ts.\n// - All classes (SlidingWindowCompactor, SemanticDeduplicator,\n// ImportanceScorer, ContextCompactor) are only referenced within this file.\n//\n// ACTUAL COMPACTION SYSTEM:\n// - compaction/compaction.ts → real compaction with LLM summarization\n// - compaction/branch-summarization.ts → branch-specific summarization\n// - compaction/utils.ts → compaction utilities\n// - agent-session.ts imports compact(), prepareCompaction(), shouldCompact()\n// from compaction/index.ts\n//\n// DO NOT MODIFY — preserved for reference only.\n\nimport { EventEmitter } from \"events\";\n\nexport interface CompactionTurn {\n\tindex: number;\n\trole: string;\n\tcontent: string;\n\ttimestamp: number;\n\timportance?: number;\n}\n\nexport interface CompactionResult {\n\tpreserved: CompactionTurn[];\n\tsummarized: CompactionTurn[];\n\tsummary: string;\n\toriginalCount: number;\n\tfinalCount: number;\n\tcompressionRatio: number;\n}\n\nexport class SlidingWindowCompactor extends EventEmitter {\n\tprivate windowSize: number;\n\n\tconstructor(windowSize = 10) {\n\t\tsuper();\n\t\tthis.windowSize = windowSize;\n\t}\n\n\tcompact(turns: CompactionTurn[]): { preserved: CompactionTurn[]; evicted: CompactionTurn[] } {\n\t\tif (turns.length <= this.windowSize) {\n\t\t\treturn { preserved: turns, evicted: [] };\n\t\t}\n\t\treturn {\n\t\t\tpreserved: turns.slice(-this.windowSize),\n\t\t\tevicted: turns.slice(0, -this.windowSize),\n\t\t};\n\t}\n}\n\nexport class SemanticDeduplicator extends EventEmitter {\n\tdeduplicate(turns: CompactionTurn[]): CompactionTurn[] {\n\t\tconst seen = new Set<string>();\n\t\tconst unique: CompactionTurn[] = [];\n\n\t\tfor (const turn of turns) {\n\t\t\tconst key = this.normalize(turn.content);\n\t\t\tif (!seen.has(key)) {\n\t\t\t\tseen.add(key);\n\t\t\t\tunique.push(turn);\n\t\t\t}\n\t\t}\n\n\t\treturn unique;\n\t}\n\n\tprivate normalize(text: string): string {\n\t\treturn text.toLowerCase().replace(/\\s+/g, \" \").trim().substring(0, 100);\n\t}\n}\n\nexport class ImportanceScorer extends EventEmitter {\n\tprivate keywords = [\"refusal\", \"error\", \"strategy\", \"phase\", \"decision\", \"goal\"];\n\n\tscore(turn: CompactionTurn): number {\n\t\tlet score = 0;\n\t\tconst content = turn.content.toLowerCase();\n\n\t\tfor (const kw of this.keywords) {\n\t\t\tif (content.includes(kw)) score += 2;\n\t\t}\n\n\t\tif (turn.role === \"system\") score += 1;\n\t\tif (turn.role === \"assistant\" && content.includes(\"refuse\")) score += 5;\n\n\t\treturn score;\n\t}\n}\n\nexport class ContextCompactor extends EventEmitter {\n\tprivate slidingWindow: SlidingWindowCompactor;\n\tprivate deduplicator: SemanticDeduplicator;\n\tprivate scorer: ImportanceScorer;\n\n\tconstructor(windowSize = 10) {\n\t\tsuper();\n\t\tthis.slidingWindow = new SlidingWindowCompactor(windowSize);\n\t\tthis.deduplicator = new SemanticDeduplicator();\n\t\tthis.scorer = new ImportanceScorer();\n\t}\n\n\tcompact(turns: CompactionTurn[], _level: \"gentle\" | \"moderate\" | \"aggressive\" = \"moderate\"): CompactionResult {\n\t\tconst originalCount = turns.length;\n\n\t\t// 1. Importance scoring\n\t\tconst scored = turns.map((t) => ({ ...t, importance: this.scorer.score(t) }));\n\n\t\t// 2. Protect high-importance turns\n\t\tconst protectedTurns = scored.filter((t) => (t.importance ?? 0) >= 3);\n\t\tconst candidates = scored.filter((t) => (t.importance ?? 0) < 3);\n\n\t\t// 3. Sliding window\n\t\tconst { preserved, evicted } = this.slidingWindow.compact(candidates);\n\n\t\t// 4. Deduplicate evicted\n\t\tconst uniqueEvicted = this.deduplicator.deduplicate(evicted);\n\n\t\t// 5. Summarize evicted\n\t\tconst summary = this.summarize(uniqueEvicted);\n\n\t\t// 6. Assemble result\n\t\tconst finalTurns = [...protectedTurns, ...preserved];\n\t\tif (summary) {\n\t\t\tfinalTurns.push({\n\t\t\t\tindex: -1,\n\t\t\t\trole: \"system\",\n\t\t\t\tcontent: `[Summary]: ${summary}`,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tpreserved: protectedTurns,\n\t\t\tsummarized: uniqueEvicted,\n\t\t\tsummary,\n\t\t\toriginalCount,\n\t\t\tfinalCount: finalTurns.length,\n\t\t\tcompressionRatio: finalTurns.length / originalCount,\n\t\t};\n\t}\n\n\tprivate summarize(turns: CompactionTurn[]): string {\n\t\tif (turns.length === 0) return \"\";\n\t\tconst topics = new Set<string>();\n\t\tfor (const turn of turns) {\n\t\t\tconst words = turn.content.split(/\\s+/).filter((w) => w.length > 4);\n\t\t\tfor (const w of words.slice(0, 3)) topics.add(w);\n\t\t}\n\t\treturn `Topics: ${Array.from(topics).slice(0, 5).join(\", \")}`;\n\t}\n}\n\nexport default ContextCompactor;\n"]}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reasoning-router v2 — pure weighted classifier + resolver (Goal 004, Lane I2/I3).
|
|
3
|
-
*
|
|
4
|
-
* Deterministic by construction: same (input, weights) -> same TaskClassV2, and
|
|
5
|
-
* same (taskClass, availableLevels, laneType, bias, hint) -> same ThinkingLevel.
|
|
6
|
-
* No clock, randomness, or I/O. Erasable TypeScript only (ThinkingLevel is
|
|
7
|
-
* imported type-only and erased).
|
|
8
|
-
*
|
|
9
|
-
* ============================================================================
|
|
10
|
-
* v1-COMPAT BEHAVIOR UNDER DEFAULT_WEIGHTS
|
|
11
|
-
* ============================================================================
|
|
12
|
-
* With DEFAULT_WEIGHTS (frozen in reasoning-router-weights.ts), classifyTaskV2
|
|
13
|
-
* reproduces v1 classifyTask on the full v1 corpus (Goal 004 Req 1.4), with one
|
|
14
|
-
* INTENTIONAL fix family: a lone WEAK-debug trigger ("fix") no longer dominates
|
|
15
|
-
* a stronger class signal. Concretely, "fix the typo" classifies as simple-edit,
|
|
16
|
-
* not debug (Goal 004 Req 1.3 — the v1 regression case). This is achieved by the
|
|
17
|
-
* STRONG/WEAK keyword split below: "fix" lives in WEAK-debug only, and
|
|
18
|
-
* DEFAULT_WEIGHTS weights only the STRONG diagonal, so a STRONG simple-edit hit
|
|
19
|
-
* ("typo") outscores the unweighted WEAK "fix".
|
|
20
|
-
*
|
|
21
|
-
* The zero-score cascade (v1 steps 2-6) runs verbatim whenever every scoreClass
|
|
22
|
-
* term is 0, preserving v1's length/lane/default behavior for signal-free turns.
|
|
23
|
-
* sticky/consult/margin thresholds are 0 in DEFAULT_WEIGHTS and treated as
|
|
24
|
-
* INACTIVE (<= 0), so v1-compat never enters the sticky/consult/judge paths.
|
|
25
|
-
* ============================================================================
|
|
26
|
-
*/
|
|
27
|
-
import type { ThinkingLevel } from "omk-agent-core";
|
|
28
|
-
import { type ReasoningLaneTypeV2, type RouterWeights, type TaskClassV2 } from "./reasoning-router-weights.ts";
|
|
29
|
-
export type { ReasoningLaneTypeV2, RouterFeatures, RouterWeights, TaskClassV2, } from "./reasoning-router-weights.ts";
|
|
30
|
-
export { DEFAULT_WEIGHTS, scoreClass, TASK_CLASSES_V2 } from "./reasoning-router-weights.ts";
|
|
31
|
-
/** Ring-buffer cap for multi-turn history (caller-owned). */
|
|
32
|
-
declare const HISTORY_CAP = 8;
|
|
33
|
-
/**
|
|
34
|
-
* Caller-supplied turn input.
|
|
35
|
-
*
|
|
36
|
-
* - prompt: raw turn text (trimmed by the classifier).
|
|
37
|
-
* - laneType: subagent lane, if any (drives lane fallback + resolver step).
|
|
38
|
-
* - history: N=8 ring buffer of prior task classes, NEWEST FIRST (multi-turn).
|
|
39
|
-
* - pressureBucket: context-pressure band 0..3 (see RouterFeatures).
|
|
40
|
-
* - judgeVote: optional tier-2 LLM-judge label (default OFF; injected as data).
|
|
41
|
-
*/
|
|
42
|
-
export interface TaskClassifierInputV2 {
|
|
43
|
-
prompt: string;
|
|
44
|
-
laneType?: ReasoningLaneTypeV2;
|
|
45
|
-
history?: readonly TaskClassV2[];
|
|
46
|
-
pressureBucket?: number;
|
|
47
|
-
judgeVote?: TaskClassV2 | null;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Deterministic weighted multi-signal classifier (Goal 004 Req 1).
|
|
51
|
-
*
|
|
52
|
-
* Pipeline:
|
|
53
|
-
* 1. Extract RouterFeatures from input (STRONG/WEAK keyword 0/1 counts per
|
|
54
|
-
* family, codeFence, diffHunk, lenBucket, multiTurnPrior, pressureBucket,
|
|
55
|
-
* judgeVote).
|
|
56
|
-
* 2. Score every class via the frozen scoreClass(c, f, weights). top1 = argmax
|
|
57
|
-
* with v1-precedence tie-break; margin = top1 - top2.
|
|
58
|
-
* 3. ZERO-SCORE CASCADE (v1-compat): when maxScore === 0, fall through exactly
|
|
59
|
-
* like v1 steps 2-6 (fence/diff -> code-gen; len<40 -> trivial; len>=2400
|
|
60
|
-
* -> plan; lane fallback; default code-gen).
|
|
61
|
-
* 4. HYSTERESIS: only when weights.stickyThreshold > 0 (INACTIVE for
|
|
62
|
-
* DEFAULT_WEIGHTS). If margin < stickyThreshold and history is non-empty,
|
|
63
|
-
* keep the previous class unless a STRONG keyword matched for top1.
|
|
64
|
-
*
|
|
65
|
-
* Pure: same (input, weights) -> same TaskClassV2.
|
|
66
|
-
*/
|
|
67
|
-
export declare function classifyTaskV2(input: TaskClassifierInputV2, weights: RouterWeights): TaskClassV2;
|
|
68
|
-
/**
|
|
69
|
-
* Static rule table: task class -> recommended ThinkingLevel (before lane
|
|
70
|
-
* adjustment, bias, hint, and clamping). Identical to v1 TASK_CLASS_THINKING_LEVELS.
|
|
71
|
-
*/
|
|
72
|
-
export declare const TASK_CLASS_THINKING_LEVELS_V2: Readonly<Record<TaskClassV2, ThinkingLevel>>;
|
|
73
|
-
/**
|
|
74
|
-
* Resolve a ThinkingLevel for a task class (Goal 004 resolver).
|
|
75
|
-
*
|
|
76
|
-
* Pipeline: base rule table -> lane step -> bounded bias [-2,+2] -> optional hint
|
|
77
|
-
* fusion (±2 bounded) -> clamp to availableLevels (v1 algorithm).
|
|
78
|
-
*
|
|
79
|
-
* The clamp guarantees model-capability safety: the return value is always a
|
|
80
|
-
* member of availableLevels and never "off" for reasoning models. With
|
|
81
|
-
* bias=0 and hint=null, output is identical to v1 resolveThinkingLevel.
|
|
82
|
-
*/
|
|
83
|
-
export declare function resolveThinkingLevelV2(taskClass: TaskClassV2, availableLevels: readonly ThinkingLevel[], laneType: ReasoningLaneTypeV2 | undefined, bias: number, hint: {
|
|
84
|
-
level: ThinkingLevel;
|
|
85
|
-
confidence: number;
|
|
86
|
-
} | null): ThinkingLevel;
|
|
87
|
-
/**
|
|
88
|
-
* Thin auto-mode wrapper: resolve with bias=0 and hint=null (what the session
|
|
89
|
-
* calls in v2 auto thinking mode). Output equals v1 resolveThinkingLevel for the
|
|
90
|
-
* same (taskClass, availableLevels, laneType).
|
|
91
|
-
*/
|
|
92
|
-
export declare function resolveThinkingLevelV2ForAuto(taskClass: TaskClassV2, availableLevels: readonly ThinkingLevel[], laneType: ReasoningLaneTypeV2 | undefined): ThinkingLevel;
|
|
93
|
-
export { HISTORY_CAP };
|
|
94
|
-
//# sourceMappingURL=reasoning-router-v2.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reasoning-router-v2.d.ts","sourceRoot":"","sources":["../../src/core/reasoning-router-v2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EACN,KAAK,mBAAmB,EAExB,KAAK,aAAa,EAGlB,KAAK,WAAW,EAChB,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACX,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,WAAW,GACX,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAM7F,6DAA6D;AAC7D,QAAA,MAAM,WAAW,IAAI,CAAC;AAwGtB;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAE,aAAa,GAAG,WAAW,CAsEhG;AAKD;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAQtF,CAAC;AAiBF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACrC,SAAS,EAAE,WAAW,EACtB,eAAe,EAAE,SAAS,aAAa,EAAE,EACzC,QAAQ,EAAE,mBAAmB,GAAG,SAAS,EACzC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GACvD,aAAa,CA4Bf;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC5C,SAAS,EAAE,WAAW,EACtB,eAAe,EAAE,SAAS,aAAa,EAAE,EACzC,QAAQ,EAAE,mBAAmB,GAAG,SAAS,GACvC,aAAa,CAEf;AAED,OAAO,EAAE,WAAW,EAAE,CAAC","sourcesContent":["/**\n * Reasoning-router v2 — pure weighted classifier + resolver (Goal 004, Lane I2/I3).\n *\n * Deterministic by construction: same (input, weights) -> same TaskClassV2, and\n * same (taskClass, availableLevels, laneType, bias, hint) -> same ThinkingLevel.\n * No clock, randomness, or I/O. Erasable TypeScript only (ThinkingLevel is\n * imported type-only and erased).\n *\n * ============================================================================\n * v1-COMPAT BEHAVIOR UNDER DEFAULT_WEIGHTS\n * ============================================================================\n * With DEFAULT_WEIGHTS (frozen in reasoning-router-weights.ts), classifyTaskV2\n * reproduces v1 classifyTask on the full v1 corpus (Goal 004 Req 1.4), with one\n * INTENTIONAL fix family: a lone WEAK-debug trigger (\"fix\") no longer dominates\n * a stronger class signal. Concretely, \"fix the typo\" classifies as simple-edit,\n * not debug (Goal 004 Req 1.3 — the v1 regression case). This is achieved by the\n * STRONG/WEAK keyword split below: \"fix\" lives in WEAK-debug only, and\n * DEFAULT_WEIGHTS weights only the STRONG diagonal, so a STRONG simple-edit hit\n * (\"typo\") outscores the unweighted WEAK \"fix\".\n *\n * The zero-score cascade (v1 steps 2-6) runs verbatim whenever every scoreClass\n * term is 0, preserving v1's length/lane/default behavior for signal-free turns.\n * sticky/consult/margin thresholds are 0 in DEFAULT_WEIGHTS and treated as\n * INACTIVE (<= 0), so v1-compat never enters the sticky/consult/judge paths.\n * ============================================================================\n */\n\nimport type { ThinkingLevel } from \"omk-agent-core\";\n\nimport {\n\ttype ReasoningLaneTypeV2,\n\ttype RouterFeatures,\n\ttype RouterWeights,\n\tscoreClass,\n\tTASK_CLASSES_V2,\n\ttype TaskClassV2,\n} from \"./reasoning-router-weights.ts\";\n\nexport type {\n\tReasoningLaneTypeV2,\n\tRouterFeatures,\n\tRouterWeights,\n\tTaskClassV2,\n} from \"./reasoning-router-weights.ts\";\nexport { DEFAULT_WEIGHTS, scoreClass, TASK_CLASSES_V2 } from \"./reasoning-router-weights.ts\";\n\n/** Prompts shorter than this (trimmed) classify as trivial via the zero-score cascade. */\nconst TRIVIAL_MAX_CHARS = 40;\n/** Prompts at/above this length with no signal are treated as long prose briefs (plan). */\nconst COMPLEX_PROSE_MIN_CHARS = 2400;\n/** Ring-buffer cap for multi-turn history (caller-owned). */\nconst HISTORY_CAP = 8;\n\n/**\n * STRONG (class-defining) keyword families, derived from v1 KEYWORD_FAMILIES\n * (reasoning-router.ts). Each pattern is the v1 alternation MINUS the ambiguous\n * WEAK tokens that are split out below. Default i (no `g` flag): stateless.\n */\nconst STRONG_KEYWORDS: ReadonlyArray<{ taskClass: TaskClassV2; pattern: RegExp }> = [\n\t{\n\t\ttaskClass: \"debug\",\n\t\tpattern:\n\t\t\t/\\b(debug(ging)?|bugs?|errors?|exceptions?|crash(es|ing|ed)?|stack\\s*trace|traceback|regressions?|broken|fail(s|ing|ed|ure|ures)?|flaky|reproduce)\\b/i,\n\t},\n\t{\n\t\ttaskClass: \"refactor\",\n\t\tpattern:\n\t\t\t/\\b(refactor(ing|ed)?|restructur(e|ing)|renam(e|ing)|extract(ing)?|clean\\s*up|cleanup|deduplicat(e|ing)|reorganiz(e|ing)|modulariz(e|ing))\\b/i,\n\t},\n\t{\n\t\ttaskClass: \"review\",\n\t\tpattern: /\\b(review(s|ing|ed)?|audit(s|ing|ed)?|critique|inspect(ing)?)\\b/i,\n\t},\n\t{\n\t\ttaskClass: \"plan\",\n\t\tpattern:\n\t\t\t/\\b(plan(s|ning)?|design(s|ing)?|architect(s|ure|ing)?|roadmap|spec(s|ification|ifications)?|strateg(y|ies|ize)|decompos(e|ing|ition)|milestones?)\\b/i,\n\t},\n\t{\n\t\ttaskClass: \"simple-edit\",\n\t\tpattern:\n\t\t\t/\\b(typos?|tweak(s|ing|ed)?|one-?liner?|single\\s+line|bump(s|ing|ed)?|whitespace|reword(s|ing|ed)?|indentation|punctuation)\\b/i,\n\t},\n\t{\n\t\ttaskClass: \"code-gen\",\n\t\tpattern:\n\t\t\t/\\b(implement(s|ing|ation)?|writ(e|ing)|creat(e|es|ing)|build(s|ing)?|generat(e|es|ing)|scaffold(ing)?|prototype)\\b/i,\n\t},\n];\n\n/**\n * WEAK (ambiguous) keyword sub-patterns split out of the v1 alternations. Under\n * DEFAULT_WEIGHTS these are INERT (the weight matrix has no WEAK coefficients),\n * so they do not affect v1-compat; they exist for calibrated weight presets.\n * The critical entry is debug \"fix\": a lone \"fix\" without a STRONG debug\n * co-trigger no longer wins debug over a stronger sibling-class signal.\n */\nconst WEAK_KEYWORDS: ReadonlyArray<{ taskClass: TaskClassV2; pattern: RegExp }> = [\n\t{ taskClass: \"debug\", pattern: /\\bfix(es|ing|ed)?\\b/i },\n\t{ taskClass: \"code-gen\", pattern: /\\badd(s|ing|ed)?\\b/i },\n\t{ taskClass: \"refactor\", pattern: /\\b(simplif(y|ying|ied)|rewrit(e|ing))\\b/i },\n\t{ taskClass: \"review\", pattern: /\\b(assess(ing|ment)?|lgtm|approve)\\b/i },\n\t{ taskClass: \"plan\", pattern: /\\bbreak\\s+(this\\s+|it\\s+)?down\\b/i },\n];\n\n/** Lane fallback when no keyword/code/diff/length signal decides (mirrors v1). */\nconst LANE_FALLBACK_CLASS_V2: Record<ReasoningLaneTypeV2, TaskClassV2> = {\n\tplanner: \"plan\",\n\tsecurity: \"review\",\n\texplorer: \"review\",\n\tcoder: \"code-gen\",\n\treviewer: \"review\",\n\ttester: \"code-gen\",\n};\n\n/**\n * Tie-break / iteration order: v1 precedence (highest first). When two classes\n * tie on score, the one appearing earlier here wins, matching v1's first-match\n * semantics. trivial is last (it carries no keyword weight under any preset).\n */\nconst PRECEDENCE_ORDER: readonly TaskClassV2[] = [\n\t\"debug\",\n\t\"refactor\",\n\t\"review\",\n\t\"plan\",\n\t\"simple-edit\",\n\t\"code-gen\",\n\t\"trivial\",\n];\n\nfunction hasCodeFence(text: string): boolean {\n\treturn text.includes(\"```\");\n}\n\n/**\n * Diff detection, identical to v1: explicit hunk headers or `diff --git` count\n * alone; bare +/- line starts only count when BOTH added and removed are present\n * (avoids false positives on markdown bullets).\n */\nfunction hasDiffMarkers(text: string): boolean {\n\tif (/^@@[^\\n]*@@/m.test(text) || /^diff --git /m.test(text)) return true;\n\treturn /^\\+(?!\\+)/m.test(text) && /^-(?!-)/m.test(text);\n}\n\nfunction clampLenBucket(len: number): number {\n\t// floor(log2(len+1)) clamped to [0,7]; integer comparison ladder, no float log.\n\tlet bucket = 0;\n\tlet v = len + 1;\n\twhile (v > 1 && bucket < 7) {\n\t\tv >>= 1;\n\t\tbucket++;\n\t}\n\treturn bucket;\n}\n\n/**\n * Caller-supplied turn input.\n *\n * - prompt: raw turn text (trimmed by the classifier).\n * - laneType: subagent lane, if any (drives lane fallback + resolver step).\n * - history: N=8 ring buffer of prior task classes, NEWEST FIRST (multi-turn).\n * - pressureBucket: context-pressure band 0..3 (see RouterFeatures).\n * - judgeVote: optional tier-2 LLM-judge label (default OFF; injected as data).\n */\nexport interface TaskClassifierInputV2 {\n\tprompt: string;\n\tlaneType?: ReasoningLaneTypeV2;\n\thistory?: readonly TaskClassV2[];\n\tpressureBucket?: number;\n\tjudgeVote?: TaskClassV2 | null;\n}\n\n/**\n * Deterministic weighted multi-signal classifier (Goal 004 Req 1).\n *\n * Pipeline:\n * 1. Extract RouterFeatures from input (STRONG/WEAK keyword 0/1 counts per\n * family, codeFence, diffHunk, lenBucket, multiTurnPrior, pressureBucket,\n * judgeVote).\n * 2. Score every class via the frozen scoreClass(c, f, weights). top1 = argmax\n * with v1-precedence tie-break; margin = top1 - top2.\n * 3. ZERO-SCORE CASCADE (v1-compat): when maxScore === 0, fall through exactly\n * like v1 steps 2-6 (fence/diff -> code-gen; len<40 -> trivial; len>=2400\n * -> plan; lane fallback; default code-gen).\n * 4. HYSTERESIS: only when weights.stickyThreshold > 0 (INACTIVE for\n * DEFAULT_WEIGHTS). If margin < stickyThreshold and history is non-empty,\n * keep the previous class unless a STRONG keyword matched for top1.\n *\n * Pure: same (input, weights) -> same TaskClassV2.\n */\nexport function classifyTaskV2(input: TaskClassifierInputV2, weights: RouterWeights): TaskClassV2 {\n\tconst prompt = input.prompt.trim();\n\n\tconst strongKeyword: Partial<Record<TaskClassV2, number>> = {};\n\tconst weakKeyword: Partial<Record<TaskClassV2, number>> = {};\n\tfor (const { taskClass, pattern } of STRONG_KEYWORDS) {\n\t\tstrongKeyword[taskClass] = pattern.test(prompt) ? 1 : 0;\n\t}\n\tfor (const { taskClass, pattern } of WEAK_KEYWORDS) {\n\t\tweakKeyword[taskClass] = (weakKeyword[taskClass] ?? 0) + (pattern.test(prompt) ? 1 : 0);\n\t}\n\n\tconst codeFence = hasCodeFence(prompt);\n\tconst diffHunk = hasDiffMarkers(prompt);\n\tconst lenBucket = clampLenBucket(prompt.length);\n\tconst history = input.history;\n\tconst multiTurnPrior: TaskClassV2 | null = history !== undefined && history.length > 0 ? history[0] : null;\n\tconst pressureBucket = input.pressureBucket ?? 0;\n\tconst judgeVote = input.judgeVote ?? null;\n\n\tconst features: RouterFeatures = {\n\t\tstrongKeyword,\n\t\tweakKeyword,\n\t\tcodeFence,\n\t\tdiffHunk,\n\t\tlenBucket,\n\t\tmultiTurnPrior,\n\t\tpressureBucket,\n\t\tjudgeVote,\n\t};\n\n\t// Score every class; track top1 (v1-precedence tie-break) and the runner-up.\n\tconst scores = new Map<TaskClassV2, number>();\n\tfor (const c of TASK_CLASSES_V2) {\n\t\tscores.set(c, scoreClass(c, features, weights));\n\t}\n\tlet top1: TaskClassV2 = PRECEDENCE_ORDER[0];\n\tfor (const c of PRECEDENCE_ORDER) {\n\t\tif ((scores.get(c) ?? 0) > (scores.get(top1) ?? 0)) top1 = c;\n\t}\n\tlet top2: TaskClassV2 | null = null;\n\tfor (const c of PRECEDENCE_ORDER) {\n\t\tif (c === top1) continue;\n\t\tif (top2 === null || (scores.get(c) ?? 0) > (scores.get(top2) ?? 0)) top2 = c;\n\t}\n\tconst maxScore = scores.get(top1) ?? 0;\n\tconst margin = top2 !== null ? maxScore - (scores.get(top2) ?? 0) : maxScore;\n\n\t// ZERO-SCORE CASCADE: no weighted signal fired -> v1 steps 2-6 verbatim.\n\tif (maxScore <= 0) {\n\t\tif (codeFence || diffHunk) return \"code-gen\";\n\t\tif (prompt.length < TRIVIAL_MAX_CHARS) return \"trivial\";\n\t\tif (prompt.length >= COMPLEX_PROSE_MIN_CHARS) return \"plan\";\n\t\tif (input.laneType) return LANE_FALLBACK_CLASS_V2[input.laneType];\n\t\treturn \"code-gen\";\n\t}\n\n\t// HYSTERESIS: keep previous class on low-margin multi-turn turns. INACTIVE for\n\t// DEFAULT_WEIGHTS (stickyThreshold === 0). A STRONG keyword hit on top1 always\n\t// bypasses stickiness so an intentional topic switch still wins.\n\tif (\n\t\tweights.stickyThreshold > 0 &&\n\t\tmargin < weights.stickyThreshold &&\n\t\tmultiTurnPrior !== null &&\n\t\t(features.strongKeyword[top1] ?? 0) <= 0\n\t) {\n\t\treturn multiTurnPrior;\n\t}\n\n\treturn top1;\n}\n\n/** Reasoning ladder used for targets and clamping. Intentionally excludes \"off\". */\nconst REASONING_LADDER_V2: readonly ThinkingLevel[] = [\"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n\n/**\n * Static rule table: task class -> recommended ThinkingLevel (before lane\n * adjustment, bias, hint, and clamping). Identical to v1 TASK_CLASS_THINKING_LEVELS.\n */\nexport const TASK_CLASS_THINKING_LEVELS_V2: Readonly<Record<TaskClassV2, ThinkingLevel>> = {\n\ttrivial: \"minimal\",\n\t\"simple-edit\": \"low\",\n\t\"code-gen\": \"medium\",\n\tdebug: \"high\",\n\trefactor: \"high\",\n\treview: \"high\",\n\tplan: \"xhigh\",\n};\n\n/**\n * Lane ladder adjustment (mirrors DEFAULT_WEIGHTS.laneStep and v1 LANE_STEP):\n * planner/security escalate one step, explorer de-escalates one step.\n */\nconst LANE_STEP_V2: Readonly<Partial<Record<ReasoningLaneTypeV2, 1 | -1>>> = {\n\tplanner: 1,\n\tsecurity: 1,\n\texplorer: -1,\n};\n\n/** Maximum magnitude of the learning/consult bias (ladder steps). */\nconst BIAS_MAX = 2;\n/** Confidence floor at which an override hint is fused into the target. */\nconst HINT_CONFIDENCE_THRESHOLD = 0.7;\n\n/**\n * Resolve a ThinkingLevel for a task class (Goal 004 resolver).\n *\n * Pipeline: base rule table -> lane step -> bounded bias [-2,+2] -> optional hint\n * fusion (±2 bounded) -> clamp to availableLevels (v1 algorithm).\n *\n * The clamp guarantees model-capability safety: the return value is always a\n * member of availableLevels and never \"off\" for reasoning models. With\n * bias=0 and hint=null, output is identical to v1 resolveThinkingLevel.\n */\nexport function resolveThinkingLevelV2(\n\ttaskClass: TaskClassV2,\n\tavailableLevels: readonly ThinkingLevel[],\n\tlaneType: ReasoningLaneTypeV2 | undefined,\n\tbias: number,\n\thint: { level: ThinkingLevel; confidence: number } | null,\n): ThinkingLevel {\n\tconst baseIndex = REASONING_LADDER_V2.indexOf(TASK_CLASS_THINKING_LEVELS_V2[taskClass]);\n\tconst laneStep = laneType ? (LANE_STEP_V2[laneType] ?? 0) : 0;\n\tconst biasClamped = Math.max(-BIAS_MAX, Math.min(BIAS_MAX, bias));\n\tconst ladderTop = REASONING_LADDER_V2.length - 1;\n\tlet targetIndex = Math.max(0, Math.min(baseIndex + laneStep + biasClamped, ladderTop));\n\n\t// Hint fusion (Phase A: hint is null). A valid high-confidence hint moves the\n\t// target toward hint.level by at most ±2 ladder steps (bounded blast radius).\n\tif (hint !== null && hint.confidence >= HINT_CONFIDENCE_THRESHOLD) {\n\t\tconst hintIndex = REASONING_LADDER_V2.indexOf(hint.level);\n\t\tif (hintIndex >= 0) {\n\t\t\tconst delta = hintIndex - targetIndex;\n\t\t\tconst step = Math.max(-BIAS_MAX, Math.min(BIAS_MAX, delta));\n\t\t\ttargetIndex = Math.max(0, Math.min(targetIndex + step, ladderTop));\n\t\t}\n\t}\n\n\t// Clamp to capability: highest available level <= target, else lowest available.\n\tconst availableOnLadder = REASONING_LADDER_V2.filter((level) => availableLevels.includes(level));\n\tif (availableOnLadder.length === 0) {\n\t\treturn availableLevels[0] ?? \"off\";\n\t}\n\tfor (let i = targetIndex; i >= 0; i--) {\n\t\tconst candidate = REASONING_LADDER_V2[i];\n\t\tif (availableOnLadder.includes(candidate)) return candidate;\n\t}\n\treturn availableOnLadder[0];\n}\n\n/**\n * Thin auto-mode wrapper: resolve with bias=0 and hint=null (what the session\n * calls in v2 auto thinking mode). Output equals v1 resolveThinkingLevel for the\n * same (taskClass, availableLevels, laneType).\n */\nexport function resolveThinkingLevelV2ForAuto(\n\ttaskClass: TaskClassV2,\n\tavailableLevels: readonly ThinkingLevel[],\n\tlaneType: ReasoningLaneTypeV2 | undefined,\n): ThinkingLevel {\n\treturn resolveThinkingLevelV2(taskClass, availableLevels, laneType, 0, null);\n}\n\nexport { HISTORY_CAP };\n"]}
|