Files
brain/tools/decomposition-detector.mjs

65 lines
2.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// tools/decomposition-detector.mjs
/**
* Decomposition detector — router-gate v4 spec §3.8 + v4.1 (Direction 3).
* Pure: ловит feature, разбитую на 3+ мелких prompts с overlapping keywords без plan skill.
* v4.1: hard-block mutating at 3+ overlapping (was 5+ soft). LLM-judge verdict инъектируется.
*/
import { keywordOverlapCount, isResetMarker } from './safe-baseline-metering.mjs';
export { isResetMarker };
export const V4_1_DECOMP_THRESHOLD = Object.freeze({
min_overlapping_prompts: 3,
min_keyword_intersection: 3,
window_size_prompts: 10,
hard_block_mutating: true,
});
export function keywordIntersection(a, b) {
return keywordOverlapCount(a, b);
}
export function appendHistory(history, entry) {
return [...(history || []), entry];
}
export function detectDecompositionCandidate(history, currentEntry, threshold = V4_1_DECOMP_THRESHOLD) {
const window = (history || []).slice(-threshold.window_size_prompts);
const curKws = currentEntry.primary_keywords || [];
const overlapping = window.filter(
(e) => keywordOverlapCount(e.primary_keywords || [], curKws) >= threshold.min_keyword_intersection,
);
const anySkill = [...overlapping, currentEntry].some((e) => e.skill_invoked_this_prompt === true);
if (overlapping.length >= threshold.min_overlapping_prompts && !anySkill) {
// overlappingKeywords: curKws present in EVERY overlapping prompt
const overlappingKeywords = curKws.filter((k) =>
overlapping.every(
(e) => (e.primary_keywords || []).map((x) => String(x).toLowerCase()).includes(String(k).toLowerCase()),
),
);
return {
candidate: true,
overlappingPrompts: overlapping.map((e) => e.prompt_idx),
overlappingKeywords,
reason: `${overlapping.length + 1} prompts overlapping keywords [${overlappingKeywords.join(', ')}] без writing-plans/brainstorming skill.`,
};
}
return { candidate: false, overlappingPrompts: [], overlappingKeywords: [] };
}
export function decideDecomposition(candidate, llmVerdict, threshold = V4_1_DECOMP_THRESHOLD) {
if (!candidate || !candidate.candidate) return { action: 'allow' };
const verdict = typeof llmVerdict === 'string' ? llmVerdict : llmVerdict?.verdict;
if (verdict === 'YES') {
return {
action: threshold.hard_block_mutating ? 'hard_block_mutating' : 'soft_flag',
reason: `v4.1 decomp hard-block: ${candidate.reason} LLM-judge confirmed decomposition. Invoke writing-plans skill сейчас.`,
};
}
// candidate but LLM says legit-distinct → soft surface only
return { action: 'soft_flag', reason: candidate.reason };
}