/** * Session goal tracker + verifier prompt. No Bare imports. * * Done is update_goal({ completed: true }) passing a single-call verifier, * not the model merely stopping tool use. */ const STATUSES = ['idle', 'planning', 'executing', 'verifying', 'complete', 'blocked']; const MAX_VERIFIER_RUNS = 5; function create(objective, opts) { opts = opts || {}; const text = String(objective || '').trim(); return { objective: text, criteria: Array.isArray(opts.criteria) ? opts.criteria.map(String) : [], status: text ? 'executing' : 'idle', gaps: [], notes: '', verifierRuns: 0, verify: opts.verify !== false, blockedReason: '', }; } function isActive(g) { return !!(g && (g.status === 'planning' || g.status === 'executing' || g.status === 'verifying')); } function plannerAddendum(g) { if (!g || !g.objective) return ''; const criteria = (g.criteria || []).length ? '\nAcceptance criteria:\n' + g.criteria.map((c, i) => (i + 1) + '. ' + c).join('\n') : ''; return ( 'Active goal: ' + g.objective + criteria + '\nComplete all todos, then call update_goal({ completed: true }).' + '\nDo not stop with open todos. If blocked, call update_goal({ blocked_reason: "..." }).' ); } function continuation(g) { const gaps = g && g.gaps && g.gaps.length ? '\nGaps: ' + g.gaps.join('; ') : ''; return ( 'Goal NOT complete — continue. Objective: ' + ((g && g.objective) || '') + gaps + '\nDo not stop until you call update_goal({ completed: true }) or update_goal({ blocked_reason: "..." }).' ); } function verifierPrompt(g, evidence) { const prior = (g && g.gaps && g.gaps.length ? g.gaps.join('\n- ') : '(none)'); return ( 'You are an adversarial verifier. You are NOT the agent that produced the work. ' + 'Your job is to refute that the objective has been met. Default to achieved: false if uncertain.\n\n' + 'OBJECTIVE:\n' + ((g && g.objective) || '') + '\n\nEVIDENCE:\n' + String(evidence || '(none)') + '\n\nPRIOR_GAPS:\n- ' + prior + '\n\nReply with JSON only: {"achieved": true|false, "gaps": ["..."]}' ); } function parseVerifier(text) { const raw = String(text || ''); const m = raw.match(/\{[\s\S]*\}/); if (!m) { const yes = /not refuted|achieved["']?\s*:\s*true/i.test(raw); const no = /refuted|not achieved|achieved["']?\s*:\s*false/i.test(raw); return { achieved: yes && !no, gaps: no ? ['verifier response was not JSON'] : [] }; } try { const j = JSON.parse(m[0]); const gaps = Array.isArray(j.gaps) ? j.gaps.map(String) : []; return { achieved: !!j.achieved, gaps }; } catch (_) { return { achieved: false, gaps: ['verifier response was not JSON'] }; } } function snapshot(g) { if (!g) return null; return { objective: g.objective, criteria: g.criteria || [], status: g.status, gaps: g.gaps || [], notes: g.notes || '', verifierRuns: g.verifierRuns || 0, verify: g.verify !== false, blockedReason: g.blockedReason || '', }; } module.exports = { STATUSES, MAX_VERIFIER_RUNS, create, isActive, plannerAddendum, continuation, verifierPrompt, parseVerifier, snapshot, };