/** * Deadlock detection + persuasion→bargaining mode shift (IND-428, backlog item 6). * * Grounding: Wells & Reed (2006), *Knowing When to Bargain* — a persuasion * dialogue (arguing the merits) that reaches a stalemate may execute a *legal * shift* into a negotiation dialogue (offering concessions). See * `docs/design/negotiation-dialogue-game.md` for the formal framing of the * turn protocol as a dialogue game. * * Design constraints (hard): * - **Deterministic**: deadlock is decided by pure inspection of the persisted * turn history — never by an LLM. * - **Stance, not rules**: a detected deadlock changes the system agent's * *drafting stance* only. Locutions, seat vocabularies (`allowedActionsFor`), * termination, and turn-cap semantics are untouched. * - **Default-off**: gated on `NEGOTIATION_DEADLOCK_SHIFT_ENABLED === "true"` * (strict literal) and applied only to v2 negotiations, checked alongside the * protocol-version plumbing. When off, the legacy path is byte-identical. * - **Fail-open**: any detection error means "no deadlock" — advisory * infrastructure never blocks a negotiation. */ import { type NegotiatorStance } from "./negotiation.stance.contracts.js"; export type { DeadlockShiftRecord } from "./negotiation.deadlock.contracts.js"; /** * Whether the deadlock→bargaining mode shift is enabled, from the * `NEGOTIATION_DEADLOCK_SHIFT_ENABLED` env switch. Strict literal `"true"` * only — the deployment is byte-for-byte unchanged until the flag is flipped, * and rolling back is the same single switch. */ export declare function configuredDeadlockShiftEnabled(): boolean; /** * Default deadlock threshold: 4 consecutive non-convergent turns. Sized * against the ambient turn cap (6): an outreach plus 4 unbroken counters * leaves exactly the closing turns to draft in the bargaining stance. */ export declare const DEFAULT_DEADLOCK_THRESHOLD = 4; /** * Lower bound on the configurable threshold. Below 2 the "stalemate" signal is * meaningless — a single counter is ordinary dialogue, not a deadlock. */ export declare const MIN_DEADLOCK_THRESHOLD = 2; /** * Consecutive non-convergent turns that constitute a deadlock, from * `NEGOTIATION_DEADLOCK_THRESHOLD`. Must be an integer >= 2; invalid, * non-integer, or out-of-range values fall back to the default (fail-open * toward the documented behavior, mirroring `askUserAnswerWindowMs`). */ export declare function configuredDeadlockThreshold(): number; export interface DeadlockAssessment { /** True when the trailing non-convergent run has reached the threshold. */ deadlocked: boolean; /** Length of the maximal trailing run of counter/question turns. */ consecutiveNonConvergent: number; /** The threshold the run was compared against. */ threshold: number; } /** * Deterministic stalemate detector: measures the maximal *trailing* run of * non-convergent turns (`counter`/`question`) in the persisted history and * compares it against the threshold. Continuation histories are included by * construction — the caller passes the full turn list, so a deadlock spanning * sessions still counts. * * Pure state inspection; no LLM, no I/O, no clock. */ export declare function assessDeadlock(history: ReadonlyArray<{ action?: string; }>, threshold?: number): DeadlockAssessment; /** * Renders the deadlock-stance prompt section. Returns the empty string when * the shift is not active, so the rendered system prompt is byte-identical to * the legacy build on every non-shifted turn (mirrors * `renderNegotiatorMemorySection`). The `ask_user` escalation line renders * only when the caller already legally holds the action (`canAskUser`) — the * shift never invents a locution. * * IND-611: `stance` selects which resolution the shift drafts toward — * bargaining (`advocate`/`evaluator`, the default and today's behavior) or * stalemate (`skeptic`). Omitted → bargaining, byte-identical to before. */ export declare function renderBargainingShiftSection(input: { active: boolean; userName: string; canAskUser: boolean; consecutiveNonConvergent: number; stance?: NegotiatorStance; }): string;