/** * Behaviour Selection — Experiment 19 (Passive) * * A small deterministic selector that maps Investigation State Assessment * output to one of five behaviours: Acknowledge, Clarify, Summarise, Continue, * Pause. * * This experiment tests whether behaviour selection is useful. It does not * change engine behaviour — it only observes and reports through Developer * Details. * * Design reference: docs/behaviour-selection.md (v0.1 Implementation Brief) */ /* ── Behaviour constants ──────────────────────────────────── */ const BEHAVIOURS = [ "acknowledge", "clarify", "summarise", "continue", "pause", ]; const PRIORITIES = { acknowledge: 1, clarify: 2, summarise: 3, pause: 4, continue: 5, // default }; /* ── Selection rules (one rule per behaviour) ─────────────── */ function selectAcknowledge(assessment) { if (assessment.conversationHealth.value === "healthy" && assessment.phase.confidence !== "low") { return { behaviour: "acknowledge", confidence: "medium", reason: "Healthy conversation with established context — user provided useful information that warrants acknowledgment before introducing new uncertainty." }; } return null; } function selectClarify(assessment) { if (assessment.conversationHealth.value === "too_broad") { return { behaviour: "clarify", confidence: "high", reason: "Conversation health is too broad — investigation may be spreading too thin. Narrow focus through a specific clarification question." }; } if (assessment.phase.value === "orienting" && assessment.phase.evidence?.observationDensity < 3) { return { behaviour: "clarify", confidence: "medium", reason: "Investigation is in orienting phase with insufficient observations (< 3). A targeted clarification question will anchor the starting point." }; } return null; } function selectSummarise(assessment) { if (assessment.phase.value === "synthesising") { return { behaviour: "summarise", confidence: "high", reason: "Investigation is in synthesising phase — connected observations have accumulated and a restatement of current understanding will compress without losing detail." }; } if (assessment.phase.value === "concluding") { return { behaviour: "summarise", confidence: "high", reason: "Investigation is concluding — a summary of resolved understanding provides closure anchor before the user decides next steps." }; } // Turn-count based summarisation (conservative threshold) if (assessment.phase.evidence?.resolvedNodeCount >= 3 && assessment.progress.value === "steady") { return { behaviour: "summarise", confidence: "medium", reason: "Three or more items resolved with steady progress — enough accumulated understanding warrants a compression pass." }; } return null; } function selectPause(assessment) { if (assessment.phase.value === "focusing" && assessment.progress.value === "stalled") { return { behaviour: "pause", confidence: "high", reason: "Focusing phase with stalled progress — the investigation has reached a single active unknown but momentum has stopped. Hold space rather than pushing for more." }; } if (assessment.conversationHealth.value === "user_overloaded") { return { behaviour: "pause", confidence: "medium", reason: "User appears overloaded — reduce pressure by acknowledging progress before inviting further contribution." }; } return null; } /* ── Main selector ─────────────────────────────────────────── */ /** * Select a behaviour based on investigation state assessment. * * Applies five deterministic rules in priority order. If no rule fires, * returns continue (the default). * * @param {Object} assessment — Investigation State Assessment from Exp 18 * @param {string} assessment.version — Assessment version * @param {string} assessment.confidence — Overall confidence (high/medium/low) * @param {Object} assessment.phase — Phase assessment { value, confidence, signals, evidence } * @param {Object} assessment.progress — Progress assessment { value, confidence, signals, evidence } * @param {Object} assessment.conversationHealth — Health assessment { value, confidence, signals, evidence } * @returns {{ behaviour: string, confidence: string, reason: string }} */ export function selectBehaviour(assessment) { if (!assessment) { return { behaviour: "continue", confidence: "low", reason: "No assessment available — defaulting to continue (ask next question).", priority: PRIORITIES.continue }; } // Guard against partial assessment objects with missing sub-structures if (!assessment.conversationHealth || !assessment.phase) { return { behaviour: "continue", confidence: "low", reason: "Assessment incomplete — missing required dimensions, defaulting to continue (ask next question).", priority: PRIORITIES.continue }; } // Apply rules in priority order let result = selectAcknowledge(assessment); if (result) return { ...result, priority: PRIORITIES.acknowledge }; result = selectClarify(assessment); if (result) return { ...result, priority: PRIORITIES.clarify }; result = selectSummarise(assessment); if (result) return { ...result, priority: PRIORITIES.summarise }; result = selectPause(assessment); if (result) return { ...result, priority: PRIORITIES.pause }; // Default — Continue return { behaviour: "continue", confidence: "low", reason: "No explicit rule matched — defaulting to continue (ask the next question).", priority: PRIORITIES.continue }; } export const BEHAVIOUR_OPTIONS = BEHAVIOURS; export default selectBehaviour;