qlogicagent 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -45
- package/package.json +56 -42
- package/dist/agent/agent.d.ts +0 -43
- package/dist/agent/agent.js +0 -113
- package/dist/agent/tool-loop.d.ts +0 -64
- package/dist/agent/tool-loop.js +0 -575
- package/dist/agent/types.d.ts +0 -175
- package/dist/agent/types.js +0 -14
- package/dist/cli/main.d.ts +0 -11
- package/dist/cli/main.js +0 -23
- package/dist/cli/stdio-server.d.ts +0 -45
- package/dist/cli/stdio-server.js +0 -463
- package/dist/config/config.d.ts +0 -17
- package/dist/config/config.js +0 -21
- package/dist/contracts/hooks.d.ts +0 -120
- package/dist/contracts/hooks.js +0 -7
- package/dist/contracts/index.d.ts +0 -10
- package/dist/contracts/index.js +0 -10
- package/dist/contracts/planner.d.ts +0 -35
- package/dist/contracts/planner.js +0 -2
- package/dist/contracts/skill-candidate.d.ts +0 -63
- package/dist/contracts/skill-candidate.js +0 -195
- package/dist/contracts/todo.d.ts +0 -14
- package/dist/contracts/todo.js +0 -9
- package/dist/index.d.ts +0 -13
- package/dist/index.js +0 -15
- package/dist/llm/builtin-providers.d.ts +0 -10
- package/dist/llm/builtin-providers.js +0 -531
- package/dist/llm/index.d.ts +0 -15
- package/dist/llm/index.js +0 -14
- package/dist/llm/llm-client.d.ts +0 -43
- package/dist/llm/llm-client.js +0 -67
- package/dist/llm/model-catalog.d.ts +0 -53
- package/dist/llm/model-catalog.js +0 -191
- package/dist/llm/provider-def.d.ts +0 -59
- package/dist/llm/provider-def.js +0 -12
- package/dist/llm/provider-registry.d.ts +0 -54
- package/dist/llm/provider-registry.js +0 -147
- package/dist/llm/transport.d.ts +0 -62
- package/dist/llm/transport.js +0 -27
- package/dist/llm/transports/anthropic-messages.d.ts +0 -31
- package/dist/llm/transports/anthropic-messages.js +0 -293
- package/dist/llm/transports/openai-chat.d.ts +0 -36
- package/dist/llm/transports/openai-chat.js +0 -165
- package/dist/orchestration/agent-registry.d.ts +0 -41
- package/dist/orchestration/agent-registry.js +0 -116
- package/dist/orchestration/approval-aware-tool-plan.d.ts +0 -32
- package/dist/orchestration/approval-aware-tool-plan.js +0 -87
- package/dist/orchestration/context-compression.d.ts +0 -220
- package/dist/orchestration/context-compression.js +0 -583
- package/dist/orchestration/conversation-repair.d.ts +0 -61
- package/dist/orchestration/conversation-repair.js +0 -429
- package/dist/orchestration/curator-scheduler.d.ts +0 -119
- package/dist/orchestration/curator-scheduler.js +0 -135
- package/dist/orchestration/embedded-failover-policy.d.ts +0 -110
- package/dist/orchestration/embedded-failover-policy.js +0 -168
- package/dist/orchestration/error-classification.d.ts +0 -12
- package/dist/orchestration/error-classification.js +0 -77
- package/dist/orchestration/failover-classification.d.ts +0 -8
- package/dist/orchestration/failover-classification.js +0 -381
- package/dist/orchestration/failover-error.d.ts +0 -33
- package/dist/orchestration/failover-error.js +0 -198
- package/dist/orchestration/fork-subagent.d.ts +0 -100
- package/dist/orchestration/fork-subagent.js +0 -98
- package/dist/orchestration/index.d.ts +0 -120
- package/dist/orchestration/index.js +0 -267
- package/dist/orchestration/memory-flush-policy.d.ts +0 -57
- package/dist/orchestration/memory-flush-policy.js +0 -85
- package/dist/orchestration/memory-provider.d.ts +0 -14
- package/dist/orchestration/memory-provider.js +0 -2
- package/dist/orchestration/parallel-tool-calls.d.ts +0 -41
- package/dist/orchestration/parallel-tool-calls.js +0 -59
- package/dist/orchestration/prompt-cache-strategy.d.ts +0 -126
- package/dist/orchestration/prompt-cache-strategy.js +0 -228
- package/dist/orchestration/reactive-compact.d.ts +0 -73
- package/dist/orchestration/reactive-compact.js +0 -78
- package/dist/orchestration/retry-loop.d.ts +0 -22
- package/dist/orchestration/retry-loop.js +0 -24
- package/dist/orchestration/skill-candidate.d.ts +0 -52
- package/dist/orchestration/skill-candidate.js +0 -141
- package/dist/orchestration/skill-consolidation.d.ts +0 -123
- package/dist/orchestration/skill-consolidation.js +0 -220
- package/dist/orchestration/skill-improvement.d.ts +0 -59
- package/dist/orchestration/skill-improvement.js +0 -66
- package/dist/orchestration/skill-similarity.d.ts +0 -98
- package/dist/orchestration/skill-similarity.js +0 -131
- package/dist/orchestration/streaming-tool-executor.d.ts +0 -73
- package/dist/orchestration/streaming-tool-executor.js +0 -96
- package/dist/orchestration/team-orchestration.d.ts +0 -195
- package/dist/orchestration/team-orchestration.js +0 -369
- package/dist/orchestration/team-tool-loop-wiring.d.ts +0 -92
- package/dist/orchestration/team-tool-loop-wiring.js +0 -147
- package/dist/orchestration/tool-choice-policy.d.ts +0 -54
- package/dist/orchestration/tool-choice-policy.js +0 -164
- package/dist/orchestration/tool-loop-state.d.ts +0 -50
- package/dist/orchestration/tool-loop-state.js +0 -133
- package/dist/orchestration/tool-schema.d.ts +0 -39
- package/dist/orchestration/tool-schema.js +0 -297
- package/dist/orchestration/transcript-repair.d.ts +0 -42
- package/dist/orchestration/transcript-repair.js +0 -426
- package/dist/orchestration/turn-loop-guard.d.ts +0 -86
- package/dist/orchestration/turn-loop-guard.js +0 -92
- package/dist/orchestration/web-browser-policy.d.ts +0 -17
- package/dist/orchestration/web-browser-policy.js +0 -39
- package/dist/runtime/context-compression.d.ts +0 -61
- package/dist/runtime/context-compression.js +0 -274
- package/dist/runtime/hook-registry.d.ts +0 -12
- package/dist/runtime/hook-registry.js +0 -53
- package/dist/runtime/memory-hooks.d.ts +0 -23
- package/dist/runtime/memory-hooks.js +0 -65
- package/dist/runtime/tool-eligibility.d.ts +0 -59
- package/dist/runtime/tool-eligibility.js +0 -111
- package/dist/skills/index.d.ts +0 -108
- package/dist/skills/index.js +0 -82
- package/dist/skills/memory-extractor.d.ts +0 -64
- package/dist/skills/memory-extractor.js +0 -173
- package/dist/skills/memory-query-tool.d.ts +0 -43
- package/dist/skills/memory-query-tool.js +0 -127
- package/dist/skills/memory-store.d.ts +0 -66
- package/dist/skills/memory-store.js +0 -228
- package/dist/skills/memory-tool.d.ts +0 -67
- package/dist/skills/memory-tool.js +0 -192
- package/dist/skills/portable-tool.d.ts +0 -71
- package/dist/skills/portable-tool.js +0 -14
- package/dist/skills/qmemory-adapter.d.ts +0 -52
- package/dist/skills/qmemory-adapter.js +0 -165
- package/dist/skills/skill-frontmatter.d.ts +0 -19
- package/dist/skills/skill-frontmatter.js +0 -344
- package/dist/skills/skill-guard.d.ts +0 -23
- package/dist/skills/skill-guard.js +0 -229
- package/dist/skills/skill-loader.d.ts +0 -16
- package/dist/skills/skill-loader.js +0 -303
- package/dist/skills/skill-source.d.ts +0 -119
- package/dist/skills/skill-source.js +0 -126
- package/dist/skills/skill-types.d.ts +0 -199
- package/dist/skills/skill-types.js +0 -6
- package/dist/skills/think-tool.d.ts +0 -16
- package/dist/skills/think-tool.js +0 -59
- package/dist/skills/todo-tool.d.ts +0 -63
- package/dist/skills/todo-tool.js +0 -114
- package/dist/skills/tools/agent-tool.d.ts +0 -91
- package/dist/skills/tools/agent-tool.js +0 -142
- package/dist/skills/tools/apply-patch-tool.d.ts +0 -29
- package/dist/skills/tools/apply-patch-tool.js +0 -184
- package/dist/skills/tools/ask-user-tool.d.ts +0 -80
- package/dist/skills/tools/ask-user-tool.js +0 -121
- package/dist/skills/tools/brief-tool.d.ts +0 -74
- package/dist/skills/tools/brief-tool.js +0 -95
- package/dist/skills/tools/browser-tool.d.ts +0 -114
- package/dist/skills/tools/browser-tool.js +0 -155
- package/dist/skills/tools/checkpoint-tool.d.ts +0 -66
- package/dist/skills/tools/checkpoint-tool.js +0 -102
- package/dist/skills/tools/config-tool.d.ts +0 -63
- package/dist/skills/tools/config-tool.js +0 -143
- package/dist/skills/tools/cron-tool.d.ts +0 -116
- package/dist/skills/tools/cron-tool.js +0 -175
- package/dist/skills/tools/edit-tool.d.ts +0 -43
- package/dist/skills/tools/edit-tool.js +0 -70
- package/dist/skills/tools/exec-tool.d.ts +0 -102
- package/dist/skills/tools/exec-tool.js +0 -133
- package/dist/skills/tools/image-generate-tool.d.ts +0 -62
- package/dist/skills/tools/image-generate-tool.js +0 -67
- package/dist/skills/tools/instructions-tool.d.ts +0 -103
- package/dist/skills/tools/instructions-tool.js +0 -187
- package/dist/skills/tools/lsp-tool.d.ts +0 -153
- package/dist/skills/tools/lsp-tool.js +0 -227
- package/dist/skills/tools/mcp-client-types.d.ts +0 -269
- package/dist/skills/tools/mcp-client-types.js +0 -53
- package/dist/skills/tools/mcp-tool.d.ts +0 -249
- package/dist/skills/tools/mcp-tool.js +0 -503
- package/dist/skills/tools/memory-tool.d.ts +0 -74
- package/dist/skills/tools/memory-tool.js +0 -88
- package/dist/skills/tools/monitor-tool.d.ts +0 -113
- package/dist/skills/tools/monitor-tool.js +0 -131
- package/dist/skills/tools/music-generate-tool.d.ts +0 -55
- package/dist/skills/tools/music-generate-tool.js +0 -62
- package/dist/skills/tools/notify-tool.d.ts +0 -53
- package/dist/skills/tools/notify-tool.js +0 -62
- package/dist/skills/tools/patch-tool.d.ts +0 -45
- package/dist/skills/tools/patch-tool.js +0 -505
- package/dist/skills/tools/pdf-tool.d.ts +0 -66
- package/dist/skills/tools/pdf-tool.js +0 -88
- package/dist/skills/tools/plan-mode-tool.d.ts +0 -59
- package/dist/skills/tools/plan-mode-tool.js +0 -122
- package/dist/skills/tools/read-tool.d.ts +0 -51
- package/dist/skills/tools/read-tool.js +0 -84
- package/dist/skills/tools/repl-tool.d.ts +0 -70
- package/dist/skills/tools/repl-tool.js +0 -69
- package/dist/skills/tools/search-tool.d.ts +0 -112
- package/dist/skills/tools/search-tool.js +0 -225
- package/dist/skills/tools/send-message-tool.d.ts +0 -51
- package/dist/skills/tools/send-message-tool.js +0 -76
- package/dist/skills/tools/skill-list-tool.d.ts +0 -33
- package/dist/skills/tools/skill-list-tool.js +0 -54
- package/dist/skills/tools/skill-manage-tool.d.ts +0 -73
- package/dist/skills/tools/skill-manage-tool.js +0 -153
- package/dist/skills/tools/skill-view-tool.d.ts +0 -37
- package/dist/skills/tools/skill-view-tool.js +0 -72
- package/dist/skills/tools/sleep-tool.d.ts +0 -49
- package/dist/skills/tools/sleep-tool.js +0 -81
- package/dist/skills/tools/structured-output-tool.d.ts +0 -116
- package/dist/skills/tools/structured-output-tool.js +0 -176
- package/dist/skills/tools/task-tool.d.ts +0 -104
- package/dist/skills/tools/task-tool.js +0 -161
- package/dist/skills/tools/team-tool.d.ts +0 -89
- package/dist/skills/tools/team-tool.js +0 -105
- package/dist/skills/tools/tool-search-tool.d.ts +0 -51
- package/dist/skills/tools/tool-search-tool.js +0 -110
- package/dist/skills/tools/tts-tool.d.ts +0 -38
- package/dist/skills/tools/tts-tool.js +0 -45
- package/dist/skills/tools/video-edit-tool.d.ts +0 -69
- package/dist/skills/tools/video-edit-tool.js +0 -74
- package/dist/skills/tools/video-generate-tool.d.ts +0 -62
- package/dist/skills/tools/video-generate-tool.js +0 -66
- package/dist/skills/tools/video-merge-tool.d.ts +0 -105
- package/dist/skills/tools/video-merge-tool.js +0 -92
- package/dist/skills/tools/video-upscale-tool.d.ts +0 -45
- package/dist/skills/tools/video-upscale-tool.js +0 -52
- package/dist/skills/tools/web-fetch-tool.d.ts +0 -78
- package/dist/skills/tools/web-fetch-tool.js +0 -92
- package/dist/skills/tools/web-search-tool.d.ts +0 -57
- package/dist/skills/tools/web-search-tool.js +0 -86
- package/dist/skills/tools/worktree-tool.d.ts +0 -69
- package/dist/skills/tools/worktree-tool.js +0 -147
- package/dist/skills/tools/write-tool.d.ts +0 -45
- package/dist/skills/tools/write-tool.js +0 -81
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reactive Compact — Emergency context compression when API returns prompt-too-long.
|
|
3
|
-
*
|
|
4
|
-
* Aligned with Claude Code's reactive compact chain:
|
|
5
|
-
* 1. API 413 → withhold error → attempt reactive compact → retry
|
|
6
|
-
* 2. Only one reactive compact attempt per turn (prevent infinite loops)
|
|
7
|
-
* 3. Falls back to abort if compact fails
|
|
8
|
-
*
|
|
9
|
-
* Also handles post-compact restoration:
|
|
10
|
-
* - Todo list re-injection
|
|
11
|
-
* - Skill context re-injection
|
|
12
|
-
* - Tool delta re-injection (new/removed tools since last compact)
|
|
13
|
-
*/
|
|
14
|
-
export const DEFAULT_REACTIVE_COMPACT_CONFIG = {
|
|
15
|
-
maxConsecutiveFailures: 3,
|
|
16
|
-
minMessagesAfterCompact: 4,
|
|
17
|
-
targetUsagePercent: 50,
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Build the restoration message to inject after a compact operation.
|
|
21
|
-
* This ensures critical state survives context compression.
|
|
22
|
-
*/
|
|
23
|
-
export function buildPostCompactRestorationMessage(payload) {
|
|
24
|
-
const sections = [];
|
|
25
|
-
if (payload.todoList && payload.todoList.length > 0) {
|
|
26
|
-
const todoLines = payload.todoList.map((t) => ` ${t.status === "completed" ? "[x]" : t.status === "in-progress" ? "[~]" : "[ ]"} #${t.id}: ${t.title}`);
|
|
27
|
-
sections.push(`## Active Todo List\n${todoLines.join("\n")}`);
|
|
28
|
-
}
|
|
29
|
-
if (payload.activeSkillContext) {
|
|
30
|
-
sections.push(`## Active Skill: ${payload.activeSkillContext.name}\nStep ${payload.activeSkillContext.step}:\n${payload.activeSkillContext.instructions}`);
|
|
31
|
-
}
|
|
32
|
-
if (payload.toolDelta && (payload.toolDelta.added.length > 0 || payload.toolDelta.removed.length > 0)) {
|
|
33
|
-
const lines = [];
|
|
34
|
-
if (payload.toolDelta.added.length > 0) {
|
|
35
|
-
lines.push(`New tools available: ${payload.toolDelta.added.join(", ")}`);
|
|
36
|
-
}
|
|
37
|
-
if (payload.toolDelta.removed.length > 0) {
|
|
38
|
-
lines.push(`Tools no longer available: ${payload.toolDelta.removed.join(", ")}`);
|
|
39
|
-
}
|
|
40
|
-
sections.push(`## Tool Changes\n${lines.join("\n")}`);
|
|
41
|
-
}
|
|
42
|
-
if (payload.customBlocks) {
|
|
43
|
-
for (const block of payload.customBlocks) {
|
|
44
|
-
sections.push(`## ${block.label}\n${block.content}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (sections.length === 0)
|
|
48
|
-
return null;
|
|
49
|
-
return `[Context was compressed. The following state has been restored:]\n\n${sections.join("\n\n")}`;
|
|
50
|
-
}
|
|
51
|
-
export function createReactiveCompactState() {
|
|
52
|
-
return {
|
|
53
|
-
consecutiveFailures: 0,
|
|
54
|
-
attemptedThisTurn: false,
|
|
55
|
-
lastCompactAt: null,
|
|
56
|
-
toolsAtLastCompact: [],
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Determine if reactive compact should be attempted.
|
|
61
|
-
*/
|
|
62
|
-
export function shouldAttemptReactiveCompact(state, config = DEFAULT_REACTIVE_COMPACT_CONFIG) {
|
|
63
|
-
if (state.attemptedThisTurn)
|
|
64
|
-
return false;
|
|
65
|
-
if (state.consecutiveFailures >= config.maxConsecutiveFailures)
|
|
66
|
-
return false;
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Calculate the tool delta since last compact.
|
|
71
|
-
*/
|
|
72
|
-
export function computeToolDelta(currentTools, toolsAtLastCompact) {
|
|
73
|
-
const currentSet = new Set(currentTools);
|
|
74
|
-
const lastSet = new Set(toolsAtLastCompact);
|
|
75
|
-
const added = currentTools.filter((t) => !lastSet.has(t));
|
|
76
|
-
const removed = toolsAtLastCompact.filter((t) => !currentSet.has(t));
|
|
77
|
-
return { added, removed };
|
|
78
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export declare function executeBoundedRetryLoop<TResult>(params: {
|
|
2
|
-
maxIterations: number;
|
|
3
|
-
onRetryLimit: (params: {
|
|
4
|
-
iterations: number;
|
|
5
|
-
maxIterations: number;
|
|
6
|
-
}) => Promise<TResult> | TResult;
|
|
7
|
-
executeIteration: (params: {
|
|
8
|
-
iteration: number;
|
|
9
|
-
}) => Promise<{
|
|
10
|
-
kind: "continue";
|
|
11
|
-
} | {
|
|
12
|
-
kind: "return";
|
|
13
|
-
result: TResult;
|
|
14
|
-
}>;
|
|
15
|
-
}): Promise<TResult>;
|
|
16
|
-
export declare function resolveScaledRetryIterations(params: {
|
|
17
|
-
candidateCount: number;
|
|
18
|
-
baseIterations?: number;
|
|
19
|
-
perCandidateIterations?: number;
|
|
20
|
-
minIterations?: number;
|
|
21
|
-
maxIterations?: number;
|
|
22
|
-
}): number;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export async function executeBoundedRetryLoop(params) {
|
|
2
|
-
let iterations = 0;
|
|
3
|
-
while (true) {
|
|
4
|
-
if (iterations >= params.maxIterations) {
|
|
5
|
-
return await params.onRetryLimit({
|
|
6
|
-
iterations,
|
|
7
|
-
maxIterations: params.maxIterations,
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
iterations += 1;
|
|
11
|
-
const outcome = await params.executeIteration({ iteration: iterations });
|
|
12
|
-
if (outcome.kind === "return") {
|
|
13
|
-
return outcome.result;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export function resolveScaledRetryIterations(params) {
|
|
18
|
-
const baseIterations = Math.max(0, Math.floor(params.baseIterations ?? 24));
|
|
19
|
-
const perCandidateIterations = Math.max(0, Math.floor(params.perCandidateIterations ?? 8));
|
|
20
|
-
const minIterations = Math.max(1, Math.floor(params.minIterations ?? 32));
|
|
21
|
-
const maxIterations = Math.max(minIterations, Math.floor(params.maxIterations ?? 160));
|
|
22
|
-
const scaled = baseIterations + Math.max(1, Math.floor(params.candidateCount)) * perCandidateIterations;
|
|
23
|
-
return Math.min(maxIterations, Math.max(minIterations, scaled));
|
|
24
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { type SkillCandidateAction, type SkillCandidateArtifactContract, type SkillCandidateEffectivenessContract, type SkillCandidateReviewContract, type SkillCandidateSourceExecutionContract } from "../contracts/skill-candidate.js";
|
|
2
|
-
export type SkillImprovementPolicyContract = {
|
|
3
|
-
reviewRequired: boolean;
|
|
4
|
-
canaryRequired: boolean;
|
|
5
|
-
autoPromote: boolean;
|
|
6
|
-
minCanarySampleCount: number;
|
|
7
|
-
minSuccessRate: number;
|
|
8
|
-
maxRegressionRate: number;
|
|
9
|
-
maxCostIncreaseRate: number;
|
|
10
|
-
staleAfterHours: number;
|
|
11
|
-
};
|
|
12
|
-
export type SkillCandidateImprovementEvidenceBundleContract = {
|
|
13
|
-
artifact?: SkillCandidateArtifactContract | null;
|
|
14
|
-
sourceExecution?: SkillCandidateSourceExecutionContract | null;
|
|
15
|
-
sourceSessionKey?: string | null;
|
|
16
|
-
diffSummary?: string | null;
|
|
17
|
-
baselineCandidateId?: string | null;
|
|
18
|
-
rolloutNotes?: string | null;
|
|
19
|
-
validationRefs?: string[];
|
|
20
|
-
evidence?: Record<string, unknown>;
|
|
21
|
-
};
|
|
22
|
-
export declare function createDefaultSkillImprovementPolicy(overrides?: Partial<SkillImprovementPolicyContract>): SkillImprovementPolicyContract;
|
|
23
|
-
export declare function normalizeSkillImprovementPolicy(value: unknown, fallback?: SkillImprovementPolicyContract): SkillImprovementPolicyContract;
|
|
24
|
-
export declare function buildSkillCandidateEvidencePayload(params: {
|
|
25
|
-
evidence?: Record<string, unknown> | null;
|
|
26
|
-
artifact?: SkillCandidateArtifactContract | null;
|
|
27
|
-
sourceExecution?: SkillCandidateSourceExecutionContract | null;
|
|
28
|
-
sourceSessionKey?: string | null;
|
|
29
|
-
}): Record<string, unknown>;
|
|
30
|
-
export declare function buildSkillCandidateImprovementEvidenceBundle(params: SkillCandidateImprovementEvidenceBundleContract): Record<string, unknown>;
|
|
31
|
-
export declare function buildSkillCandidateLatestReview(params: {
|
|
32
|
-
action: SkillCandidateAction;
|
|
33
|
-
actor?: string | null;
|
|
34
|
-
notes?: string | null;
|
|
35
|
-
payload?: Record<string, unknown> | null;
|
|
36
|
-
createdAt?: string;
|
|
37
|
-
}): SkillCandidateReviewContract;
|
|
38
|
-
export declare function buildSkillCandidateEffectivenessSummary(params: {
|
|
39
|
-
phase: "canary" | "published";
|
|
40
|
-
sampleCount?: number;
|
|
41
|
-
successCount?: number;
|
|
42
|
-
failureCount?: number;
|
|
43
|
-
regressionCount?: number;
|
|
44
|
-
avgLatencyMs?: number;
|
|
45
|
-
avgCostUsd?: number;
|
|
46
|
-
score?: number;
|
|
47
|
-
staleReason?: string | null;
|
|
48
|
-
notes?: string | null;
|
|
49
|
-
summary?: Record<string, unknown> | null;
|
|
50
|
-
lastObservedAt?: string;
|
|
51
|
-
updatedAt?: string;
|
|
52
|
-
}): SkillCandidateEffectivenessContract;
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { coerceSkillCandidateJsonObject, normalizeSkillCandidateAction, normalizeSkillCandidateArtifact, normalizeSkillCandidateEffectiveness, normalizeSkillCandidateEffectivenessPhase, normalizeSkillCandidateSourceExecution, } from "../contracts/skill-candidate.js";
|
|
2
|
-
const DEFAULT_SKILL_IMPROVEMENT_POLICY = {
|
|
3
|
-
reviewRequired: true,
|
|
4
|
-
canaryRequired: true,
|
|
5
|
-
autoPromote: false,
|
|
6
|
-
minCanarySampleCount: 10,
|
|
7
|
-
minSuccessRate: 0.7,
|
|
8
|
-
maxRegressionRate: 0.1,
|
|
9
|
-
maxCostIncreaseRate: 0.25,
|
|
10
|
-
staleAfterHours: 168,
|
|
11
|
-
};
|
|
12
|
-
function normalizeOptionalBoolean(value, fallback) {
|
|
13
|
-
if (typeof value === "boolean") {
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
if (typeof value === "string") {
|
|
17
|
-
const normalized = value.trim().toLowerCase();
|
|
18
|
-
if (normalized === "true") {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
if (normalized === "false") {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return fallback;
|
|
26
|
-
}
|
|
27
|
-
function normalizeOptionalFiniteNumber(value, fallback) {
|
|
28
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
29
|
-
return value;
|
|
30
|
-
}
|
|
31
|
-
if (typeof value === "string") {
|
|
32
|
-
const trimmed = value.trim();
|
|
33
|
-
if (trimmed) {
|
|
34
|
-
const parsed = Number(trimmed);
|
|
35
|
-
if (Number.isFinite(parsed)) {
|
|
36
|
-
return parsed;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return fallback;
|
|
41
|
-
}
|
|
42
|
-
function normalizeOptionalStringArray(value) {
|
|
43
|
-
return Array.isArray(value)
|
|
44
|
-
? value
|
|
45
|
-
.filter((entry) => typeof entry === "string")
|
|
46
|
-
.map((entry) => entry.trim())
|
|
47
|
-
.filter(Boolean)
|
|
48
|
-
: [];
|
|
49
|
-
}
|
|
50
|
-
export function createDefaultSkillImprovementPolicy(overrides = {}) {
|
|
51
|
-
return normalizeSkillImprovementPolicy(overrides, DEFAULT_SKILL_IMPROVEMENT_POLICY);
|
|
52
|
-
}
|
|
53
|
-
export function normalizeSkillImprovementPolicy(value, fallback = DEFAULT_SKILL_IMPROVEMENT_POLICY) {
|
|
54
|
-
const record = coerceSkillCandidateJsonObject(value);
|
|
55
|
-
return {
|
|
56
|
-
reviewRequired: normalizeOptionalBoolean(record.reviewRequired, fallback.reviewRequired),
|
|
57
|
-
canaryRequired: normalizeOptionalBoolean(record.canaryRequired, fallback.canaryRequired),
|
|
58
|
-
autoPromote: normalizeOptionalBoolean(record.autoPromote, fallback.autoPromote),
|
|
59
|
-
minCanarySampleCount: Math.max(1, Math.floor(normalizeOptionalFiniteNumber(record.minCanarySampleCount, fallback.minCanarySampleCount))),
|
|
60
|
-
minSuccessRate: Math.max(0, Math.min(1, normalizeOptionalFiniteNumber(record.minSuccessRate, fallback.minSuccessRate))),
|
|
61
|
-
maxRegressionRate: Math.max(0, Math.min(1, normalizeOptionalFiniteNumber(record.maxRegressionRate, fallback.maxRegressionRate))),
|
|
62
|
-
maxCostIncreaseRate: Math.max(0, normalizeOptionalFiniteNumber(record.maxCostIncreaseRate, fallback.maxCostIncreaseRate)),
|
|
63
|
-
staleAfterHours: Math.max(1, Math.floor(normalizeOptionalFiniteNumber(record.staleAfterHours, fallback.staleAfterHours))),
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
export function buildSkillCandidateEvidencePayload(params) {
|
|
67
|
-
const evidence = coerceSkillCandidateJsonObject(params.evidence);
|
|
68
|
-
const artifact = params.artifact ? normalizeSkillCandidateArtifact(params.artifact) : null;
|
|
69
|
-
const sourceExecution = params.sourceExecution
|
|
70
|
-
? normalizeSkillCandidateSourceExecution(params.sourceExecution)
|
|
71
|
-
: null;
|
|
72
|
-
const sourceSessionKey = typeof params.sourceSessionKey === "string"
|
|
73
|
-
? params.sourceSessionKey.trim()
|
|
74
|
-
: "";
|
|
75
|
-
return {
|
|
76
|
-
...evidence,
|
|
77
|
-
...(artifact ? { artifact } : {}),
|
|
78
|
-
...(sourceExecution ? { sourceExecution } : {}),
|
|
79
|
-
...(sourceSessionKey ? { sourceSessionKey } : {}),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
export function buildSkillCandidateImprovementEvidenceBundle(params) {
|
|
83
|
-
const evidence = buildSkillCandidateEvidencePayload(params);
|
|
84
|
-
const diffSummary = typeof params.diffSummary === "string" && params.diffSummary.trim()
|
|
85
|
-
? params.diffSummary.trim()
|
|
86
|
-
: "";
|
|
87
|
-
const baselineCandidateId = typeof params.baselineCandidateId === "string"
|
|
88
|
-
&& params.baselineCandidateId.trim()
|
|
89
|
-
? params.baselineCandidateId.trim()
|
|
90
|
-
: "";
|
|
91
|
-
const rolloutNotes = typeof params.rolloutNotes === "string" && params.rolloutNotes.trim()
|
|
92
|
-
? params.rolloutNotes.trim()
|
|
93
|
-
: "";
|
|
94
|
-
const validationRefs = normalizeOptionalStringArray(params.validationRefs);
|
|
95
|
-
return {
|
|
96
|
-
...evidence,
|
|
97
|
-
...(diffSummary ? { diffSummary } : {}),
|
|
98
|
-
...(baselineCandidateId ? { baselineCandidateId } : {}),
|
|
99
|
-
...(rolloutNotes ? { rolloutNotes } : {}),
|
|
100
|
-
...(validationRefs.length > 0 ? { validationRefs } : {}),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
export function buildSkillCandidateLatestReview(params) {
|
|
104
|
-
return {
|
|
105
|
-
action: normalizeSkillCandidateAction(params.action) ?? params.action,
|
|
106
|
-
actor: typeof params.actor === "string" && params.actor.trim() ? params.actor.trim() : null,
|
|
107
|
-
notes: typeof params.notes === "string" && params.notes.trim() ? params.notes.trim() : null,
|
|
108
|
-
payload: coerceSkillCandidateJsonObject(params.payload),
|
|
109
|
-
createdAt: typeof params.createdAt === "string" && params.createdAt.trim()
|
|
110
|
-
? params.createdAt.trim()
|
|
111
|
-
: new Date().toISOString(),
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
export function buildSkillCandidateEffectivenessSummary(params) {
|
|
115
|
-
const sampleCount = Math.max(0, Math.floor(params.sampleCount ?? 0));
|
|
116
|
-
const successCount = Math.max(0, Math.floor(params.successCount ?? 0));
|
|
117
|
-
const failureCount = Math.max(0, Math.floor(params.failureCount ?? Math.max(sampleCount - successCount, 0)));
|
|
118
|
-
const regressionCount = Math.max(0, Math.floor(params.regressionCount ?? 0));
|
|
119
|
-
const successRate = sampleCount > 0 ? successCount / sampleCount : 0;
|
|
120
|
-
const regressionRate = sampleCount > 0 ? regressionCount / sampleCount : 0;
|
|
121
|
-
const score = typeof params.score === "number" && Number.isFinite(params.score)
|
|
122
|
-
? params.score
|
|
123
|
-
: Number((successRate - regressionRate).toFixed(4));
|
|
124
|
-
return normalizeSkillCandidateEffectiveness({
|
|
125
|
-
phase: normalizeSkillCandidateEffectivenessPhase(params.phase) ?? params.phase,
|
|
126
|
-
sampleCount,
|
|
127
|
-
successCount,
|
|
128
|
-
failureCount,
|
|
129
|
-
regressionCount,
|
|
130
|
-
successRate,
|
|
131
|
-
regressionRate,
|
|
132
|
-
avgLatencyMs: params.avgLatencyMs,
|
|
133
|
-
avgCostUsd: params.avgCostUsd,
|
|
134
|
-
score,
|
|
135
|
-
staleReason: params.staleReason,
|
|
136
|
-
notes: params.notes,
|
|
137
|
-
summary: coerceSkillCandidateJsonObject(params.summary),
|
|
138
|
-
lastObservedAt: params.lastObservedAt ?? new Date().toISOString(),
|
|
139
|
-
updatedAt: params.updatedAt ?? new Date().toISOString(),
|
|
140
|
-
});
|
|
141
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skill consolidation strategy — pure decision logic for
|
|
3
|
-
* the Autonomous Curator's LLM-driven skill merging phase.
|
|
4
|
-
*
|
|
5
|
-
* This module:
|
|
6
|
-
* 1. Detects prefix clusters among skill names.
|
|
7
|
-
* 2. Builds the consolidation prompt for the LLM review agent.
|
|
8
|
-
* 3. Parses structured LLM output into actionable merge/prune plans.
|
|
9
|
-
* 4. Reconciles LLM intent against ground truth (existing skills).
|
|
10
|
-
*
|
|
11
|
-
* No I/O — the caller invokes the LLM and applies the results.
|
|
12
|
-
*/
|
|
13
|
-
/** A skill summary fed to the LLM reviewer. */
|
|
14
|
-
export interface ConsolidationSkillSummary {
|
|
15
|
-
name: string;
|
|
16
|
-
description: string;
|
|
17
|
-
/** Comma-separated tool names the skill uses. */
|
|
18
|
-
tools: string;
|
|
19
|
-
useCount: number;
|
|
20
|
-
lastActivityAt: string | null;
|
|
21
|
-
state: "active" | "stale";
|
|
22
|
-
}
|
|
23
|
-
/** A single consolidation action proposed by the LLM. */
|
|
24
|
-
export interface ConsolidationAction {
|
|
25
|
-
/** Source skill to be absorbed. */
|
|
26
|
-
sourceSkill: string;
|
|
27
|
-
/** Target umbrella skill (existing or to-be-created). */
|
|
28
|
-
targetUmbrella: string;
|
|
29
|
-
/** Whether the target umbrella already exists. */
|
|
30
|
-
targetExists: boolean;
|
|
31
|
-
/** LLM's reason for the merge. */
|
|
32
|
-
reason: string;
|
|
33
|
-
}
|
|
34
|
-
/** A single pruning action proposed by the LLM. */
|
|
35
|
-
export interface PruningAction {
|
|
36
|
-
/** Skill to be archived (not deleted). */
|
|
37
|
-
skillName: string;
|
|
38
|
-
/** Reason for pruning. */
|
|
39
|
-
reason: string;
|
|
40
|
-
}
|
|
41
|
-
/** Full consolidation plan produced by parsing LLM output. */
|
|
42
|
-
export interface ConsolidationPlan {
|
|
43
|
-
consolidations: ConsolidationAction[];
|
|
44
|
-
prunings: PruningAction[];
|
|
45
|
-
/** Skills mentioned by LLM but not found in ground truth. */
|
|
46
|
-
hallucinations: string[];
|
|
47
|
-
}
|
|
48
|
-
/** Result of reconciling the LLM plan against ground truth. */
|
|
49
|
-
export interface ReconciledConsolidationPlan {
|
|
50
|
-
/** Validated consolidation actions (targets exist or are marked for creation). */
|
|
51
|
-
validConsolidations: ConsolidationAction[];
|
|
52
|
-
/** Validated pruning actions (skills exist). */
|
|
53
|
-
validPrunings: PruningAction[];
|
|
54
|
-
/** Rejected actions due to ground-truth mismatch. */
|
|
55
|
-
rejected: Array<{
|
|
56
|
-
action: string;
|
|
57
|
-
reason: string;
|
|
58
|
-
}>;
|
|
59
|
-
}
|
|
60
|
-
/** A detected cluster of skills sharing a naming prefix. */
|
|
61
|
-
export interface SkillPrefixCluster {
|
|
62
|
-
prefix: string;
|
|
63
|
-
skills: string[];
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Detect prefix clusters among skill names.
|
|
67
|
-
*
|
|
68
|
-
* A cluster is ≥2 skills sharing a common hyphenated prefix of ≥2 chars.
|
|
69
|
-
* E.g. `["pr-review", "pr-merge", "pr-label"]` → cluster `"pr"`.
|
|
70
|
-
*/
|
|
71
|
-
export declare function detectPrefixClusters(skillNames: readonly string[], minClusterSize?: number): SkillPrefixCluster[];
|
|
72
|
-
/**
|
|
73
|
-
* Build the consolidation review prompt for the LLM curator agent.
|
|
74
|
-
*
|
|
75
|
-
* The prompt instructs the model to:
|
|
76
|
-
* 1. Identify prefix clusters and overlapping skills.
|
|
77
|
-
* 2. Propose umbrella consolidations.
|
|
78
|
-
* 3. Mark redundant/trivial skills for pruning (archive, not delete).
|
|
79
|
-
* 4. Output a structured YAML block.
|
|
80
|
-
*/
|
|
81
|
-
export declare function buildConsolidationPrompt(candidates: readonly ConsolidationSkillSummary[], existingUmbrellas: readonly string[], clusters: readonly SkillPrefixCluster[]): string;
|
|
82
|
-
/**
|
|
83
|
-
* Parse the LLM's structured YAML response into a ConsolidationPlan.
|
|
84
|
-
*
|
|
85
|
-
* Tolerant: handles minor formatting variations, ignores unknown fields.
|
|
86
|
-
*/
|
|
87
|
-
export declare function parseConsolidationOutput(llmOutput: string, knownSkills: ReadonlySet<string>): ConsolidationPlan;
|
|
88
|
-
/**
|
|
89
|
-
* Reconcile the LLM's consolidation plan against ground truth.
|
|
90
|
-
*
|
|
91
|
-
* Validates that:
|
|
92
|
-
* - Source skills exist and aren't already consolidated in this plan.
|
|
93
|
-
* - Target umbrellas either exist or are new (will be created).
|
|
94
|
-
* - Pruning targets aren't also being consolidated.
|
|
95
|
-
*/
|
|
96
|
-
export declare function reconcileConsolidationPlan(plan: ConsolidationPlan, knownSkills: ReadonlySet<string>): ReconciledConsolidationPlan;
|
|
97
|
-
/** Summary of a curator review run. */
|
|
98
|
-
export interface CuratorRunReport {
|
|
99
|
-
/** ISO-8601 timestamp of the run. */
|
|
100
|
-
runAt: string;
|
|
101
|
-
/** Duration in seconds. */
|
|
102
|
-
durationSeconds: number;
|
|
103
|
-
/** Number of skills checked for lifecycle transitions. */
|
|
104
|
-
autoTransitionsChecked: number;
|
|
105
|
-
/** Number of skills marked stale. */
|
|
106
|
-
autoMarkedStale: number;
|
|
107
|
-
/** Number of skills archived. */
|
|
108
|
-
autoArchived: number;
|
|
109
|
-
/** Number of skills reactivated. */
|
|
110
|
-
autoReactivated: number;
|
|
111
|
-
/** Number of LLM-proposed consolidations accepted. */
|
|
112
|
-
consolidationsAccepted: number;
|
|
113
|
-
/** Number of LLM-proposed prunings accepted. */
|
|
114
|
-
pruningsAccepted: number;
|
|
115
|
-
/** Number of LLM-proposed actions rejected. */
|
|
116
|
-
actionsRejected: number;
|
|
117
|
-
/** Number of hallucinated skill names. */
|
|
118
|
-
hallucinations: number;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Build a human-readable summary from a curator run report.
|
|
122
|
-
*/
|
|
123
|
-
export declare function buildCuratorRunSummary(report: CuratorRunReport): string;
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skill consolidation strategy — pure decision logic for
|
|
3
|
-
* the Autonomous Curator's LLM-driven skill merging phase.
|
|
4
|
-
*
|
|
5
|
-
* This module:
|
|
6
|
-
* 1. Detects prefix clusters among skill names.
|
|
7
|
-
* 2. Builds the consolidation prompt for the LLM review agent.
|
|
8
|
-
* 3. Parses structured LLM output into actionable merge/prune plans.
|
|
9
|
-
* 4. Reconciles LLM intent against ground truth (existing skills).
|
|
10
|
-
*
|
|
11
|
-
* No I/O — the caller invokes the LLM and applies the results.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Detect prefix clusters among skill names.
|
|
15
|
-
*
|
|
16
|
-
* A cluster is ≥2 skills sharing a common hyphenated prefix of ≥2 chars.
|
|
17
|
-
* E.g. `["pr-review", "pr-merge", "pr-label"]` → cluster `"pr"`.
|
|
18
|
-
*/
|
|
19
|
-
export function detectPrefixClusters(skillNames, minClusterSize = 2) {
|
|
20
|
-
const prefixMap = new Map();
|
|
21
|
-
for (const name of skillNames) {
|
|
22
|
-
const dashIdx = name.indexOf("-");
|
|
23
|
-
if (dashIdx < 2)
|
|
24
|
-
continue;
|
|
25
|
-
const prefix = name.slice(0, dashIdx);
|
|
26
|
-
const existing = prefixMap.get(prefix);
|
|
27
|
-
if (existing) {
|
|
28
|
-
existing.push(name);
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
prefixMap.set(prefix, [name]);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
const clusters = [];
|
|
35
|
-
for (const [prefix, skills] of prefixMap) {
|
|
36
|
-
if (skills.length >= minClusterSize) {
|
|
37
|
-
clusters.push({ prefix, skills: skills.sort() });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return clusters.sort((a, b) => b.skills.length - a.skills.length);
|
|
41
|
-
}
|
|
42
|
-
// ── LLM prompt construction ────────────────────────────────────────
|
|
43
|
-
/**
|
|
44
|
-
* Build the consolidation review prompt for the LLM curator agent.
|
|
45
|
-
*
|
|
46
|
-
* The prompt instructs the model to:
|
|
47
|
-
* 1. Identify prefix clusters and overlapping skills.
|
|
48
|
-
* 2. Propose umbrella consolidations.
|
|
49
|
-
* 3. Mark redundant/trivial skills for pruning (archive, not delete).
|
|
50
|
-
* 4. Output a structured YAML block.
|
|
51
|
-
*/
|
|
52
|
-
export function buildConsolidationPrompt(candidates, existingUmbrellas, clusters) {
|
|
53
|
-
const candidateList = candidates.map((c) => `- **${c.name}** (${c.state}, uses: ${c.useCount}, tools: ${c.tools})${c.lastActivityAt ? ` last active: ${c.lastActivityAt}` : ""}`).join("\n");
|
|
54
|
-
const umbrellaList = existingUmbrellas.length > 0
|
|
55
|
-
? existingUmbrellas.map((u) => `- ${u}`).join("\n")
|
|
56
|
-
: "(none)";
|
|
57
|
-
const clusterList = clusters.length > 0
|
|
58
|
-
? clusters.map((c) => `- **${c.prefix}-***: ${c.skills.join(", ")}`).join("\n")
|
|
59
|
-
: "(no clusters detected)";
|
|
60
|
-
return `You are the Autonomous Curator for a skill library.
|
|
61
|
-
|
|
62
|
-
## Goal
|
|
63
|
-
|
|
64
|
-
Transform narrow, session-specific skills into a well-organized library of
|
|
65
|
-
class-level umbrella skills. A collection of hundreds of narrow skills is FAILURE.
|
|
66
|
-
|
|
67
|
-
## Ground Rules
|
|
68
|
-
|
|
69
|
-
1. **NEVER delete** — only archive (prune). Archived skills can be restored.
|
|
70
|
-
2. **Do NOT touch pinned or bundled skills** — they are already filtered out.
|
|
71
|
-
3. **Identify prefix clusters** and merge them into umbrella skills.
|
|
72
|
-
4. **Move session-specific details** into the umbrella's references/ folder.
|
|
73
|
-
5. **Preserve unique value** — only merge if the source is genuinely redundant
|
|
74
|
-
or a subset of the target.
|
|
75
|
-
|
|
76
|
-
## Detected Prefix Clusters
|
|
77
|
-
|
|
78
|
-
${clusterList}
|
|
79
|
-
|
|
80
|
-
## Existing Umbrella Skills
|
|
81
|
-
|
|
82
|
-
${umbrellaList}
|
|
83
|
-
|
|
84
|
-
## Candidate Skills for Review
|
|
85
|
-
|
|
86
|
-
${candidateList}
|
|
87
|
-
|
|
88
|
-
## Required Output Format
|
|
89
|
-
|
|
90
|
-
Respond with EXACTLY this YAML block (no extra text outside the block):
|
|
91
|
-
|
|
92
|
-
\`\`\`yaml
|
|
93
|
-
consolidations:
|
|
94
|
-
- source: "skill-name-a"
|
|
95
|
-
target: "umbrella-skill"
|
|
96
|
-
reason: "subset of umbrella functionality"
|
|
97
|
-
- source: "skill-name-b"
|
|
98
|
-
target: "new-umbrella-name"
|
|
99
|
-
reason: "cluster merge"
|
|
100
|
-
|
|
101
|
-
prunings:
|
|
102
|
-
- skill: "skill-name-c"
|
|
103
|
-
reason: "trivial single-use, no ongoing value"
|
|
104
|
-
\`\`\`
|
|
105
|
-
|
|
106
|
-
If no consolidations or prunings are warranted, use empty lists.
|
|
107
|
-
Respond ONLY with the YAML block.`;
|
|
108
|
-
}
|
|
109
|
-
// ── LLM output parsing ─────────────────────────────────────────────
|
|
110
|
-
/**
|
|
111
|
-
* Parse the LLM's structured YAML response into a ConsolidationPlan.
|
|
112
|
-
*
|
|
113
|
-
* Tolerant: handles minor formatting variations, ignores unknown fields.
|
|
114
|
-
*/
|
|
115
|
-
export function parseConsolidationOutput(llmOutput, knownSkills) {
|
|
116
|
-
const consolidations = [];
|
|
117
|
-
const prunings = [];
|
|
118
|
-
const hallucinations = [];
|
|
119
|
-
// Extract YAML block if wrapped in ```yaml ... ```
|
|
120
|
-
const yamlMatch = llmOutput.match(/```(?:yaml)?\s*\n([\s\S]*?)```/);
|
|
121
|
-
const yaml = yamlMatch ? yamlMatch[1] : llmOutput;
|
|
122
|
-
// Parse consolidations
|
|
123
|
-
const consolidationBlock = yaml.match(/consolidations:\s*\n((?:\s+-[\s\S]*?)?)(?=prunings:|$)/);
|
|
124
|
-
if (consolidationBlock?.[1]) {
|
|
125
|
-
const entries = consolidationBlock[1].matchAll(/- source:\s*"([^"]+)"\s*\n\s*target:\s*"([^"]+)"\s*\n\s*reason:\s*"([^"]+)"/g);
|
|
126
|
-
for (const [, source, target, reason] of entries) {
|
|
127
|
-
if (!knownSkills.has(source)) {
|
|
128
|
-
hallucinations.push(source);
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
consolidations.push({
|
|
132
|
-
sourceSkill: source,
|
|
133
|
-
targetUmbrella: target,
|
|
134
|
-
targetExists: knownSkills.has(target),
|
|
135
|
-
reason,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Parse prunings
|
|
140
|
-
const pruningBlock = yaml.match(/prunings:\s*\n([\s\S]*?)$/);
|
|
141
|
-
if (pruningBlock?.[1]) {
|
|
142
|
-
const entries = pruningBlock[1].matchAll(/- skill:\s*"([^"]+)"\s*\n\s*reason:\s*"([^"]+)"/g);
|
|
143
|
-
for (const [, skill, reason] of entries) {
|
|
144
|
-
if (!knownSkills.has(skill)) {
|
|
145
|
-
hallucinations.push(skill);
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
prunings.push({ skillName: skill, reason });
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return { consolidations, prunings, hallucinations };
|
|
152
|
-
}
|
|
153
|
-
// ── Reconciliation ─────────────────────────────────────────────────
|
|
154
|
-
/**
|
|
155
|
-
* Reconcile the LLM's consolidation plan against ground truth.
|
|
156
|
-
*
|
|
157
|
-
* Validates that:
|
|
158
|
-
* - Source skills exist and aren't already consolidated in this plan.
|
|
159
|
-
* - Target umbrellas either exist or are new (will be created).
|
|
160
|
-
* - Pruning targets aren't also being consolidated.
|
|
161
|
-
*/
|
|
162
|
-
export function reconcileConsolidationPlan(plan, knownSkills) {
|
|
163
|
-
const validConsolidations = [];
|
|
164
|
-
const validPrunings = [];
|
|
165
|
-
const rejected = [];
|
|
166
|
-
const consolidatedSources = new Set();
|
|
167
|
-
for (const c of plan.consolidations) {
|
|
168
|
-
if (!knownSkills.has(c.sourceSkill)) {
|
|
169
|
-
rejected.push({
|
|
170
|
-
action: `consolidate ${c.sourceSkill} → ${c.targetUmbrella}`,
|
|
171
|
-
reason: `source skill "${c.sourceSkill}" not found`,
|
|
172
|
-
});
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
if (consolidatedSources.has(c.sourceSkill)) {
|
|
176
|
-
rejected.push({
|
|
177
|
-
action: `consolidate ${c.sourceSkill} → ${c.targetUmbrella}`,
|
|
178
|
-
reason: `source skill "${c.sourceSkill}" already consolidated in this plan`,
|
|
179
|
-
});
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
if (c.sourceSkill === c.targetUmbrella) {
|
|
183
|
-
rejected.push({
|
|
184
|
-
action: `consolidate ${c.sourceSkill} → ${c.targetUmbrella}`,
|
|
185
|
-
reason: "source and target are the same skill",
|
|
186
|
-
});
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
consolidatedSources.add(c.sourceSkill);
|
|
190
|
-
validConsolidations.push(c);
|
|
191
|
-
}
|
|
192
|
-
for (const p of plan.prunings) {
|
|
193
|
-
if (!knownSkills.has(p.skillName)) {
|
|
194
|
-
rejected.push({
|
|
195
|
-
action: `prune ${p.skillName}`,
|
|
196
|
-
reason: `skill "${p.skillName}" not found`,
|
|
197
|
-
});
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (consolidatedSources.has(p.skillName)) {
|
|
201
|
-
rejected.push({
|
|
202
|
-
action: `prune ${p.skillName}`,
|
|
203
|
-
reason: `skill "${p.skillName}" is being consolidated, not pruned`,
|
|
204
|
-
});
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
validPrunings.push(p);
|
|
208
|
-
}
|
|
209
|
-
return { validConsolidations, validPrunings, rejected };
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Build a human-readable summary from a curator run report.
|
|
213
|
-
*/
|
|
214
|
-
export function buildCuratorRunSummary(report) {
|
|
215
|
-
const parts = [];
|
|
216
|
-
parts.push(`Curator run at ${report.runAt} (${report.durationSeconds.toFixed(1)}s)`);
|
|
217
|
-
parts.push(`Auto: ${report.autoTransitionsChecked} checked, ${report.autoMarkedStale} stale, ${report.autoArchived} archived, ${report.autoReactivated} reactivated`);
|
|
218
|
-
parts.push(`LLM: ${report.consolidationsAccepted} consolidated, ${report.pruningsAccepted} pruned, ${report.actionsRejected} rejected, ${report.hallucinations} hallucinated`);
|
|
219
|
-
return parts.join("; ");
|
|
220
|
-
}
|