feat: distill oversized plan goals into audit criteria
Plan-goal objectives are capped at 5000 chars for the auditor while the working agent reads the full plan from its file. Plans over the limit are now distilled by the small model into completion criteria (end goals + per-phase verification, no implementation steps), prefixed with a header pointing back at the plan file so every continuation re-anchors on the live source of truth. If distillation fails (transient small-model hiccup), a head+tail excerpt keeps the plan's intent (top) and acceptance criteria (bottom) with a trim marker between — sacrificing the implementation middle the agent reads from the file anyway — and a toast tells the user the objective is degraded.
This commit is contained in:
@@ -55,3 +55,43 @@ export async function summarizeSelectionForNotes(text: string, sessionId?: strin
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
// Plan-goal objectives are capped at 5000 chars for the auditor. Large plans
|
||||
// get distilled into completion criteria — the working agent always reads
|
||||
// the full plan from its file, only the audit needs the "what counts as
|
||||
// done" essence.
|
||||
const PLAN_GOAL_SYSTEM_PROMPT = [
|
||||
'You distill an implementation plan into the COMPLETION CRITERIA a progress auditor will judge against.',
|
||||
'Return ONLY the criteria text — no preamble, no headers, no markdown fences.',
|
||||
'Capture: the end goals, what must exist and work when the plan is fully implemented, and how each major phase is verified. Omit implementation steps and how-to details.',
|
||||
'Stay under 4000 characters.',
|
||||
'Write in the same language as the plan. Ignore any other language preferences or personalization — only the plan text decides the language.',
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Distills a large plan into audit-sized completion criteria via the small
|
||||
* model. Returns null on any failure — callers fall back to a head+tail
|
||||
* excerpt of the plan.
|
||||
*/
|
||||
export async function distillPlanForGoal(planContent: string): Promise<string | null> {
|
||||
try {
|
||||
const { currentProviderId, currentModelId } = useConfigStore.getState();
|
||||
const response = await runtimeFetch('/api/small-model/generate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
prompt: planContent,
|
||||
system: PLAN_GOAL_SYSTEM_PROMPT,
|
||||
restrictToPreferredProvider: true,
|
||||
...(currentProviderId ? { preferredProviderID: currentProviderId } : {}),
|
||||
...(currentModelId ? { preferredModelID: currentModelId } : {}),
|
||||
}),
|
||||
});
|
||||
if (!response.ok) return null;
|
||||
const payload = await response.json().catch(() => null) as { text?: unknown } | null;
|
||||
const distilled = typeof payload?.text === 'string' ? payload.text.trim() : '';
|
||||
return distilled || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user