76 lines
5.1 KiB
JavaScript
76 lines
5.1 KiB
JavaScript
// Разбор ОДНОГО завершённого спана: reconcile (категории + суть шага) → шаг → аудит (скрытые
|
|
// вопросы). Общий код для stop-хука (живой разбор) и пересборки дела из сырья (одинаковое качество).
|
|
// Чистая оркестрация над reconcile/audit/layer1; единственный побочный эффект — вызовы callModel.
|
|
import { reconcileTurn, mergeTurnIntoProtocol, collapseProtocol } from './secretary-reconcile.mjs';
|
|
import { buildAuditPrompt, parseAuditResponse, applyAudit, preserveRegistry } from './secretary-audit.mjs';
|
|
import { buildStepLine } from './secretary-layer1.mjs';
|
|
import { fluffyPipelineOn } from './secretary-flag.mjs';
|
|
import { diffTrunk } from './secretary-trunkdiff.mjs';
|
|
import { parseLoose } from './secretary-armor.mjs';
|
|
import { resolveModel } from './secretary-models.mjs';
|
|
import { SYS_11, SYS_12, SYS_13, diagFindings, user11, user12, user13, userG, renderExchangeText } from './secretary-harvest.mjs';
|
|
import { SYS_G } from './secretary-gardener.mjs';
|
|
import { applyResults } from './secretary-apply.mjs';
|
|
|
|
/** Разобрать спан и вернуть НОВЫЙ протокол (вход не мутируется reconcile-веткой; collapse — копия).
|
|
* proto — текущий протокол; spanEx — склеенный обмен спана {user,assistant,actions};
|
|
* {start,end} — границы спана (в ходах сырья); opts: { callModel|null, session, diag }.
|
|
* Без callModel (нет ключа) — пишется только детерминированный шаг, категории/СВ не трогаются. */
|
|
export async function distillSpan(proto, spanEx, { start, end, note = '' }, { callModel, session, diag, flags } = {}) {
|
|
// Снимок реестра СВ ДО reconcile (reconcile перенумеровывает hidden) — вернём после merge.
|
|
const svSnapshot = JSON.parse(JSON.stringify({
|
|
hidden: proto.hidden || [], acceptance: proto.acceptance || [],
|
|
tails: proto.tails || [], nextSvId: proto.nextSvId || 1,
|
|
}));
|
|
|
|
let updated = null;
|
|
if (callModel) {
|
|
updated = await reconcileTurn({ proto, ex: spanEx, turn: start, session, callModel, diag });
|
|
}
|
|
|
|
const modelStep = (updated && updated.step) || null;
|
|
if (updated && 'step' in updated) delete updated.step;
|
|
const step = { turn: start, session,
|
|
text: buildStepLine({ turn: start, endTurn: end, user: spanEx.user, assistant: spanEx.assistant,
|
|
actions: (spanEx.actions || []).map((a) => a.tool), essence: modelStep, note }) };
|
|
const toWrite = mergeTurnIntoProtocol({ proto, updated, step });
|
|
|
|
// Реестр СВ — вотчина аудитора/садовника: вернуть из снимка ДО reconcile.
|
|
preserveRegistry(toWrite, svSnapshot);
|
|
|
|
// НОВЫЙ конвейер «пушистое дерево» (подпроект A) — за флагом. Флаг ВЫКЛ → старый аудит ниже.
|
|
const fluffy = (flags && typeof flags.fluffy === 'boolean') ? flags.fluffy : fluffyPipelineOn();
|
|
if (callModel && fluffy) {
|
|
try {
|
|
const diff = diffTrunk(proto, toWrite); // движение ствола до/после редактора
|
|
const spanText = renderExchangeText(spanEx);
|
|
const txt = (r) => (typeof r === 'string' ? r : (r && r.text) || '');
|
|
const call = (role, system, user) => callModel({ system, user, model: resolveModel(role) });
|
|
// сбор: 1.1 диагностика ∥ 1.2 ловец, затем 1.3 брейншторм (после них)
|
|
const [r11, r12] = await Promise.all([
|
|
call('diagnostic', SYS_11, user11(toWrite, spanText, { start, end })),
|
|
call('catcher', SYS_12, user12(toWrite, spanText)),
|
|
]);
|
|
const d11 = diagFindings(parseLoose(txt(r11), 'lenses'));
|
|
const d12 = parseLoose(txt(r12), 'dropped');
|
|
const r13 = await call('brainstorm', SYS_13, user13(toWrite, spanText, { start, end }, JSON.stringify(d11.new), JSON.stringify(d12.dropped)));
|
|
const d13 = parseLoose(txt(r13), 'forks');
|
|
// садовник (после сбора; видит дифф ствола + свежие ветки)
|
|
const rG = await call('gardener', SYS_G, userG(toWrite, spanText, diff));
|
|
const dG = parseLoose(txt(rG), 'tend');
|
|
return collapseProtocol(applyResults(toWrite, start, d11, d12, d13, dG));
|
|
} catch (e) { if (typeof diag === 'function') diag({ turn: start, reason: 'fluffy-fail', error: e && e.message }); return collapseProtocol(toWrite); }
|
|
}
|
|
|
|
// СТАРЫЙ путь (аудит 9-линз) — без изменений, пока флаг выключен.
|
|
if (callModel) {
|
|
try {
|
|
const auditMsgs = buildAuditPrompt(toWrite, spanEx);
|
|
const raw = await callModel(auditMsgs);
|
|
applyAudit(toWrite, parseAuditResponse(typeof raw === 'string' ? raw : (raw?.text || '')), start);
|
|
} catch (e) { if (typeof diag === 'function') diag({ turn: start, reason: 'audit-fail', error: e && e.message }); }
|
|
}
|
|
|
|
return collapseProtocol(toWrite);
|
|
}
|