export { K as KodaXCompactMemoryProgress, a as KodaXCompactMemorySeed, b as KodaXExtensionSessionRecord, c as KodaXExtensionSessionState, d as KodaXExtensionStore, e as KodaXExtensionStoreEntry, f as KodaXJsonValue, g as KodaXSessionArchiveMarkerEntry, h as KodaXSessionArtifactLedgerEntry, i as KodaXSessionBranchSummaryEntry, j as KodaXSessionCompactionEntry, k as KodaXSessionData, l as KodaXSessionEntry, m as KodaXSessionEntryBase, n as KodaXSessionLabelEntry, o as KodaXSessionLineage, p as KodaXSessionMessageEntry, q as KodaXSessionMeta, r as KodaXSessionNavigationOptions, s as KodaXSessionRuntimeInfo, t as KodaXSessionScope, u as KodaXSessionStorage, v as KodaXSessionTreeNode, w as KodaXSessionUiHistoryItem, x as KodaXSessionUiHistoryItemType, y as KodaXSessionWorkspaceKind, S as SessionErrorMetadata } from './types-chunks/types.d-mM8vqvhT.js';
import { d as AgentManifest, M as ManifestPatch, k as InvariantId, Q as QualityInvariant } from './types-chunks/history-cleanup.d-DznrzEiU.js';
export { A as AdmissionAuditOptions, a as AdmissionCtx, b as AdmissionVerdict, c as AdmittedHandle, C as CompactionContext, e as CompactionEntry, f as CompactionEntryPayload, g as CompactionPolicy, D as DEFAULT_SYSTEM_CAP, h as DefaultSummaryCompaction, i as DefaultSummaryCompactionOptions, j as Deliverable, I as InMemorySessionOptions, l as InvariantResult, m as InvariantSession, K as KODAX_API_MIN_INTERVAL, n as KODAX_DEFAULT_TIMEOUT, o as KODAX_HARD_TIMEOUT, p as KODAX_MAX_INCOMPLETE_RETRIES, q as KODAX_MAX_MAXTOKENS_RETRIES, r as KODAX_MAX_RETRIES, s as KODAX_MAX_TOKENS, t as KODAX_RETRY_BASE_DELAY, u as KODAX_STAGGER_DELAY, v as MessageEntry, O as ObserveCtx, P as PROMISE_PATTERN, w as PolicyCompactionResult, x as PresetDispatcher, y as PresetTracingContext, R as ReadonlyMutationTracker, z as ReadonlyRecorder, B as RunEvent, E as RunOptions, F as RunResult, G as Runner, H as RunnerEvent, S as Session, J as SessionDispatchResult, L as SessionEntry, N as SessionExtension, T as SessionForkOptions, U as StopHookContext, V as StopHookFn, W as StopHookResult, X as SystemCap, Y as TerminalCtx, Z as ToolCapability, _ as ToolPermission, $ as _resetAdmittedAgentBindings, a0 as _resetPresetDispatchers, a1 as buildSystemPrompt, a2 as cleanupIncompleteToolCalls, a3 as countTokens, a4 as createInMemorySession, a5 as createInvariantSessionForAgent, a6 as detectInstructionsInjection, a7 as estimateTokens, a8 as extractAssistantTextFromMessage, a9 as getAdmittedAgentBindings, aa as getAgentConfigHome, ab as getAgentConfigPath, ac as getAppDataDir, ad as registerPresetDispatcher, ae as runAdmissionAudit, af as setAdmittedAgentBindings, ag as setAgentConfigHome, ah as validateAndFixToolHistory } from './types-chunks/history-cleanup.d-DznrzEiU.js';
import { A as Agent, H as Handoff, r as RunnerToolCall, u as RunnerToolResult, w as Span, a as AgentMessage, C as ChildTaskRegistry, D as DiscoveredInstance, S as SessionMeta, v as SessionStateSnapshot, B as StateWriterFs, k as InstanceDiscoveryFs, z as StateWriter } from './types-chunks/instance-discovery.d-BsKnIwpg.js';
export { b as AgentMiddlewareDeclaration, c as AgentReasoningProfile, d as AgentTool, e as CurrentTodoSummary, f as DiscoveryOptions, G as Guardrail, g as GuardrailBlockedError, h as GuardrailContext, i as GuardrailEscalateError, j as GuardrailVerdict, I as InputGuardrail, M as MAX_TOOL_LOOP_ITERATIONS, O as OutputGuardrail, P as PersistedSessionState, R as ReasoningDepth, l as RecentlyModifiedFile, m as RequestTaskStopOptions, n as RequestTaskStopResult, o as RunnableTool, p as RunnerLlmResult, q as RunnerLlmReturn, s as RunnerToolContext, t as RunnerToolObserver, E as StateWriterOptions, T as TaskAbortRegistry, F as ToolBeforeOutcome, J as ToolGuardrail, K as buildAssistantMessageFromLlmResult, L as buildToolResultMessage, N as collectGuardrails, Q as createAgent, U as createHandoff, V as createStateWriter, W as discoverInstances, X as executeRunnerToolCall, Y as isRunnableTool, Z as isRunnerLlmResult, _ as registerChildTask, $ as requestTaskStop, a0 as runInputGuardrails, a1 as runOutputGuardrails, a2 as runToolAfterGuardrails, a3 as runToolBeforeGuardrails } from './types-chunks/instance-discovery.d-BsKnIwpg.js';
import { m as KodaXMessage } from './types-chunks/types.d-B1uGoVTE.js';
export { e as KodaXAssuranceIntent, g as KodaXContentBlock, i as KodaXExecutionMode, j as KodaXExecutionPattern, l as KodaXImageBlock, o as KodaXMutationSurface, r as KodaXProviderConfig, z as KodaXProviderStreamOptions, C as KodaXReasoningCapability, D as KodaXReasoningMode, F as KodaXReasoningRequest, G as KodaXRedactedThinkingBlock, I as KodaXRiskLevel, J as KodaXStreamResult, L as KodaXTaskActionability, M as KodaXTaskBudgetOverrides, N as KodaXTaskComplexity, O as KodaXTaskFamily, P as KodaXTaskRoutingDecision, Q as KodaXTaskType, R as KodaXTaskWorkIntent, S as KodaXTextBlock, T as KodaXThinkingBlock, U as KodaXThinkingBudgetMap, V as KodaXThinkingDepth, W as KodaXTokenUsage, X as KodaXToolDefinition, Y as KodaXToolResultBlock, a0 as KodaXToolUseBlock } from './types-chunks/types.d-B1uGoVTE.js';
export { C as CapabilityKind, a as CapabilityProvider, b as CapabilityResult } from './types-chunks/capability.d-3C62G8Eq.js';
import { Q as QueueEventListener, b as QueuedMessage, E as EnqueueInput, D as DequeueFilter, a as MessagePriority, M as MessageMode } from './types-chunks/types.d-C5mHR87z.js';

/**
 * Runner Handoff Helpers — FEATURE_084 Shard 4 (v0.7.26).
 *
 * When a tool result carries `metadata.handoffTarget`, the Runner should
 * switch ownership to the target Agent declared in
 * `currentAgent.handoffs`. This module provides pure helpers for that
 * transition:
 *
 *   - `detectHandoffSignal(currentAgent, toolResults)` — find the first
 *     tool result that carries a matching handoff and return the resolved
 *     Handoff + target.
 *   - `replaceSystemMessage(transcript, newAgent)` — swap the leading
 *     system message so the next LLM turn sees the new agent's
 *     instructions.
 *   - `emitHandoffSpan(parentSpan, from, to, ...)` — emit the
 *     `HandoffSpan` (FEATURE_083 span kind).
 *
 * Guardrail scoping for Shard 4: input / output guardrails are **run-scoped**
 * — they use the starting agent's declarations and run once at start/end of
 * the overall run. They do NOT re-run on handoff. Tool guardrails apply to
 * every tool invocation regardless of which agent is calling. This keeps
 * the mental model simple; later shards may refine.
 */

interface HandoffSignal {
    readonly from: Agent;
    readonly to: Agent;
    readonly handoff: Handoff;
    /** Index of the tool result that triggered the handoff. */
    readonly triggerIndex: number;
}
/**
 * Find the first tool result with a `handoffTarget` metadata field that
 * resolves to a declared handoff on `currentAgent`. Returns `undefined` if
 * no result carries a handoff target or if the target isn't declared.
 */
declare function detectHandoffSignal(currentAgent: Agent, _toolCalls: readonly RunnerToolCall[], toolResults: readonly RunnerToolResult[]): HandoffSignal | undefined;
/**
 * Replace the leading system message with `newAgent`'s instructions so the
 * next LLM turn runs under the new role. The rest of the transcript
 * (user, assistant tool_use, tool_result blocks) is preserved verbatim so
 * the new agent sees the full lead-up.
 */
declare function replaceSystemMessage(transcript: readonly AgentMessage[], newAgent: Agent): AgentMessage[];
/**
 * Emit a `HandoffSpan` as a child of the agent span. Ends immediately
 * because a handoff is a point-in-time event (unlike agent/tool spans
 * which wrap a duration).
 */
declare function emitHandoffSpan(parentSpan: Span | null, from: Agent, to: Agent, handoffKind: 'continuation' | 'as-tool', description?: string): void;

/**
 * FEATURE_101 (v0.7.31) admission runtime — patch reducer + invariant registry.
 *
 * Deterministic, side-effect-free helpers consumed by `Runner.admit()` (in
 * `./runner.ts`, added in the next 1A.3 increment).
 *
 *   - `applyManifestPatch(manifest, patch)`: produces a new manifest with the
 *     patch applied. Used when admission needs to clamp tools / budget /
 *     iterations to system caps.
 *   - `composePatches(patches)`: merges multiple patches (deterministic
 *     reducer; min wins for clamp values, union for collections).
 *   - `InvariantRegistry`: in-memory registry mapping `InvariantId` to
 *     `QualityInvariant` implementations. Open-ended — FEATURE_101 v1
 *     registers 7 closed-set invariants; FEATURE_106 registers 1 external
 *     invariant; future features may add more.
 *   - `resolveRequiredInvariants(role, toolScope, harnessTier)`: pure
 *     function returning the InvariantId set the admission layer enforces
 *     by default (caller's `manifest.declaredInvariants` is unioned on
 *     top — declared can only ADD, never remove from required).
 *
 * Pure data + pure functions. No I/O, no shared mutable state visible
 * outside the registry's own opaque object. Tests live in
 * `./admission-runtime.test.ts`.
 */

/**
 * Apply a patch to a manifest, returning a NEW manifest. Pure function;
 * input is not mutated.
 *
 * Semantics per field:
 *
 *   - `removeTools`:        manifest.tools filtered by `(t) => !patch.removeTools.includes(t.name)`
 *   - `clampMaxBudget`:     manifest.maxBudget = min(current, patch.clampMaxBudget) when current > clamp
 *   - `clampMaxIterations`: manifest.maxIterations = min(current, patch.clampMaxIterations) when current > clamp.
 *                           v0.7.31.2 added `AgentManifest.maxIterations` as a first-class
 *                           field (symmetric with maxBudget). Runner.run reads the post-
 *                           clamp manifest through `getAdmittedAgentBindings` and takes
 *                           min-wins against `RunOptions.maxToolLoopIterations`.
 *   - `addInvariants`:      union into manifest.declaredInvariants
 *   - `notes`:              ignored at the manifest level — surfaced
 *                           through AdmissionVerdict.clampNotes
 *
 * The patch is monotone: tools can only be REMOVED (admission can shrink,
 * never expand), budgets can only be CLAMPED DOWN, invariants can only be
 * ADDED. This invariant is what makes "clamp severity is safe to apply
 * automatically" — the manifest can't end up MORE permissive than what
 * the LLM submitted.
 */
declare function applyManifestPatch(manifest: AgentManifest, patch: ManifestPatch): AgentManifest;
/**
 * Compose multiple patches into one. Order is preserved for `notes`; numeric
 * clamp fields use min-wins (most restrictive); collections union.
 *
 * Used when several invariants each return clamp at admission time — the
 * Runner accumulates patches and applies them in one pass.
 */
declare function composePatches(patches: readonly ManifestPatch[]): ManifestPatch;
/**
 * Register an invariant implementation. Throws if the id is already
 * registered (overwrite would be a silent contract bug). Tests that
 * need a fresh registry call `_resetInvariantRegistry()` first.
 */
declare function registerInvariant(invariant: QualityInvariant): void;
/**
 * Look up a registered invariant by id. Returns undefined when not
 * registered — Runner.admit treats this as "skip this id silently"
 * because the closed-set guarantee belongs to the registry caller, not
 * to the runtime.
 */
declare function getInvariant(id: InvariantId): QualityInvariant | undefined;
/**
 * Snapshot of the currently-registered invariant ids. Read-only —
 * mutations on the returned array do NOT affect the registry.
 */
declare function listRegisteredInvariants(): readonly InvariantId[];
/**
 * Reset the registry to empty. **Tests only** — production code should
 * never invoke this. Module export name is prefixed with `_` to make
 * accidental imports stand out.
 */
declare function _resetInvariantRegistry(): void;
/**
 * Per-role / per-tool-scope / per-harness-tier required invariant set.
 *
 * Pure function — same inputs always return the same set. The admission
 * layer unions this with `manifest.declaredInvariants` to produce the
 * effective set. Declared can only ADD (it's an LLM voluntary commitment
 * on top of what the system requires).
 *
 * v1 default policy: every manifest gets the 7 admission-v1 closed-set
 * invariants. role / toolScope / harnessTier are accepted but currently
 * not used to differentiate — they're plumbed through so future
 * refinements can specialize without breaking the API.
 */
declare function resolveRequiredInvariants(_role: string, _toolScope: readonly string[], _harnessTier: string): readonly InvariantId[];
/**
 * Effective invariant set for a manifest = union of required (system)
 * and declared (LLM voluntary). Returned in stable order (required
 * first, then declared additions in insertion order).
 */
declare function resolveEffectiveInvariants(required: readonly InvariantId[], declared: readonly InvariantId[] | undefined): readonly InvariantId[];

/**
 * FEATURE_101 v0.7.31.1 — admission metrics counters.
 *
 * Closes the "admission decoration" risk called out in
 * docs/features/v0.7.31.md §dispatch eval 新增指标. v0.7.31 declared
 * three metrics in the design (`admission_reject_after_retry_rate`,
 * `admission_clamp_rate`, `invariant_violation_rate`) but never emitted
 * them at runtime — leaving operators with no signal on whether
 * admission was actually catching things or had become a no-op.
 *
 * The module exports an in-process counter table plus pure helpers to
 * read / reset / compute rates. Counters increment from:
 *
 *   - `runAdmissionAudit` on every verdict (ok / ok+clamp / reject /
 *     reject-final).
 *   - `InvariantSession.recordX` and `assertTerminal` on every
 *     observed violation.
 *
 * Reading the rates:
 *
 *   - `admission_clamp_rate`              = admitOkClamped / admitTotal
 *   - `admission_reject_after_retry_rate` = admitRejectFinal / admitTotal
 *   - `invariant_violation_rate`          = invariantViolations / admitTotal
 *
 * Counters are process-local — exporters (Prometheus, OpenTelemetry,
 * etc.) are expected to scrape `getAdmissionMetricsSnapshot()` on a
 * cadence. `_resetAdmissionMetrics` is for tests; production never
 * calls it.
 */
interface AdmissionMetricsSnapshot {
    readonly admitTotal: number;
    readonly admitOk: number;
    readonly admitOkClamped: number;
    readonly admitReject: number;
    readonly admitRejectFinal: number;
    readonly invariantViolationsObserved: number;
    readonly invariantViolationsTerminal: number;
    readonly admissionClampRate: number;
    readonly admissionRejectAfterRetryRate: number;
    readonly invariantViolationRate: number;
}
/**
 * Snapshot of current counters + computed rates. Returned object is a
 * fresh copy — mutating it does NOT affect the live counters.
 */
declare function getAdmissionMetricsSnapshot(): AdmissionMetricsSnapshot;
/**
 * Test-only reset. Production code MUST NOT call this — the counters
 * are designed to accumulate across the process lifetime.
 */
declare function _resetAdmissionMetrics(): void;
/**
 * Returns true when the admission debug flag is set in the environment.
 * Recognises `'1'`, `'true'`, `'yes'`, `'on'` (case-insensitive).
 * Falls through to false on unset / empty / any other value, so the
 * default is silent.
 */
declare function isAdmissionDebugEnabled(): boolean;

/**
 * FEATURE_101 invariant: `evidenceTrail`.
 *
 * Mutations must leave evidence; the terminal deliverable verifies the
 * evidence trail is complete.
 *
 * Hooks:
 *   - observe(mutation_recorded): no-op in v1 — the runtime mutation
 *     tracker already records the file. Reserved for future "did the
 *     evidence_added event arrive within N tool calls of the mutation"
 *     timing checks.
 *   - assertTerminal(deliverable): if the run produced any mutations
 *     (deliverable.mutationCount > 0), at least one evidence artifact
 *     must accompany them. Empty `evidenceArtifacts` for a mutating run
 *     is a reject — the deliverable is unauditable.
 *
 * The threshold is intentionally coarse (any > 0 works): per-file
 * evidence is the @kodax-ai/coding mutation tracker's job, not the Layer A
 * primitive's. We can tighten the rule once FEATURE_089 starts emitting
 * structured mutation→evidence pairings.
 */

declare const evidenceTrail: QualityInvariant;

/**
 * FEATURE_101 invariant: `finalOwner`.
 *
 * Admit-only check: the manifest must designate a final owner. v1 heuristic:
 *
 *   - manifest.name is non-empty (schema validation already enforces, but
 *     re-checking here keeps the invariant self-contained), and
 *   - if the manifest declares handoffs, the handoff graph (manifest +
 *     ctx.activatedAgents) must contain at least one terminal node — an
 *     agent with no outgoing handoffs. If every node has an outgoing
 *     handoff, the deliverable has no resting place; admit rejects.
 *
 * The check is intentionally lightweight: deeper graph properties (single
 * sink, dominator analysis) are noise for v1 and would burn invariant
 * budget on hypothetical multi-role topologies that don't ship in
 * v0.7.31. We can sharpen the rule when FEATURE_089 starts emitting
 * richer manifests.
 *
 * Pure function — no I/O, no shared mutable state.
 */

declare const finalOwner: QualityInvariant;

/**
 * FEATURE_101 invariant: `handoffLegality`.
 *
 * Admit-time DAG check: the handoff graph (manifest.handoffs + the
 * transitive closure of ctx.activatedAgents.handoffs) must be acyclic.
 * A cycle means the system can transfer ownership in a loop without
 * ever terminating — admission rejects.
 *
 * v1 algorithm: iterative DFS with explicit white/gray/black colouring.
 * Iterative (not recursive) because manifests with deep handoff chains
 * could blow the JS stack on certain runtimes — handing the search a
 * stack of our own keeps the bound predictable.
 *
 * Observe-time: no-op in v1. Cycle detection at admit time covers the
 * static graph; runtime handoff traversal is a separate concern handled
 * by the Runner's loop bound. We keep an `observe` stub registered so
 * future versions can add per-event bookkeeping (e.g. detect "agent X
 * already handed off this run, refusing second handoff") without a
 * registry migration.
 */

declare const handoffLegality: QualityInvariant;

/**
 * Pure-new invariant implementations bundled with @kodax-ai/agent.
 *
 * The admission contract types live in `../admission.ts`; the registry
 * runtime in `../admission-runtime.ts`. This module exports the three
 * invariant declarations plus a `registerCoreInvariants()` helper that
 * registers them in one call.
 *
 * Why this split:
 *   - These three (finalOwner, handoffLegality, evidenceTrail) are pure
 *     functions of the admission types — they have NO @kodax-ai/coding
 *     dependencies. Living in @kodax-ai/agent keeps the dependency direction
 *     clean and lets `Runner.admit` unit-test against real invariants
 *     without pulling the coding runtime into the test harness.
 *   - The four coupled invariants (budgetCeiling, toolPermission,
 *     boundedRevise, independentReview) wrap @kodax-ai/coding capabilities
 *     (mutation tracker, budget controller, ToolGuardrail tier resolver)
 *     and live in `@kodax-ai/coding/src/agent-runtime/invariants/`.
 *   - `harnessSelectionTiming` (FEATURE_106 external) was here in
 *     v0.7.31; v0.7.35.1 FEATURE_142 (A-R2) moved it back to
 *     `@kodax-ai/coding/src/agent-runtime/invariants/` because its body
 *     hardcoded `ctx.recorder.scout.payload.scout.confirmedHarness` —
 *     a coding-AMA Scout-role field reference (ADR-021).
 *
 * Registration is NOT side-effecting on import — consumers call
 * `registerCoreInvariants()` explicitly so test isolation
 * (`_resetInvariantRegistry()` followed by registering only the subset
 * a test needs) stays predictable.
 */

/**
 * The three pure invariants @kodax-ai/agent ships, in registration order.
 * Exposed as a constant so consumers can introspect the set without
 * registering (e.g. dispatch-eval metric setup that wants id labels).
 */
declare const CORE_INVARIANTS: readonly QualityInvariant[];
/**
 * Register the three pure-new invariants on the shared runtime registry.
 * Idempotent only when paired with `_resetInvariantRegistry()` first —
 * `registerInvariant` itself throws on duplicate registration, which is
 * the desired contract (silent overwrite would mask refactors).
 */
declare function registerCoreInvariants(): void;

/**
 * @kodax-ai/agent/messaging/queue — 2-tier agentId-scoped FIFO message queue.
 *
 * FEATURE_115 (v0.7.36).
 *
 * Invariants:
 *   - In-priority FIFO: messages of the same priority drain in enqueue order.
 *   - Cross-priority precedence: 'user' drains before 'background', regardless
 *     of enqueue order.
 *   - agentId routing: messages addressed to agentId X are only visible to
 *     consumers filtering for that exact agentId. undefined ≠ "any agent" —
 *     it specifically matches main-thread messages.
 *   - Not persistent: process restart loses queue state, by design (matches
 *     TodoStore semantics).
 *
 * The queue is process-global by default (`getMessageQueue()`); the class is
 * also exported for tests / isolated downstream use.
 */

declare class MessageQueue {
    private messages;
    private nextSeq;
    /**
     * FEATURE_159 (v0.7.40) — observable subscription set. Same pattern as
     * Claude Code's `messageQueueManager.ts` `createSignal()` substrate,
     * but the listener carries a structured `QueueEvent` so SDK
     * observability consumers (logger, tracer, metrics) can react per-
     * event without re-diffing snapshots. `useSyncExternalStore` consumers
     * still work — they ignore the event argument.
     *
     * Cached `snapshotRef` keeps reference identity stable across reads
     * when nothing changed — required by React 18's `useSyncExternalStore`
     * to avoid render loops.
     */
    private listeners;
    private snapshotRef;
    private notify;
    /**
     * Subscribe to queue mutations. Compatible with React 18's
     * `useSyncExternalStore(subscribe, getSnapshot)` — the hook passes a
     * `() => void` callback, which is structurally assignable to the
     * `QueueEventListener` parameter because TypeScript treats
     * callback parameter discards as compatible. SDK consumers that
     * declare a typed `(event: QueueEvent) => void` listener see the
     * structured event.
     *
     * Listener is called synchronously after every mutation; returns an
     * unsubscribe function.
     */
    subscribe: (listener: QueueEventListener) => (() => void);
    /**
     * Returns the current frozen queue snapshot. Reference identity is
     * stable across reads when the queue has not mutated, which is the
     * contract React's `useSyncExternalStore` relies on.
     */
    getSnapshot: () => readonly QueuedMessage[];
    /** Returns the assigned id of the enqueued message. */
    enqueue(input: EnqueueInput): string;
    /**
     * Drain matching messages, ordered by priority (user > background) then
     * FIFO within each priority. Removes drained messages from the queue.
     */
    dequeue(filter: DequeueFilter): QueuedMessage[];
    /**
     * Peek at matching messages without removing them. Returns messages in
     * the same priority + FIFO order that `dequeue(filter)` would return,
     * so callers can inspect what the next drain would yield.
     */
    peek(filter: DequeueFilter): QueuedMessage[];
    /** Total queue size across all priorities / agents. */
    size(): number;
    /** Count of messages matching the filter. */
    count(filter: DequeueFilter): number;
    /** True iff at least one message matches the filter. */
    has(filter: DequeueFilter): boolean;
    /** Remove all queued messages — used in tests / process abort scenarios. */
    clear(): void;
}
/**
 * Returns the process-global MessageQueue singleton, creating it lazily on
 * first call. Use this for production wiring; instantiate `MessageQueue`
 * directly in tests / isolated subsystems where a shared instance would
 * cause cross-test pollution.
 */
declare function getMessageQueue(): MessageQueue;
/**
 * Test-only reset hook. Production code MUST NOT call this. Underscored
 * prefix follows the same convention as `_resetInvariantRegistry` /
 * `_resetAdmittedAgentBindings` / `_resetAdmissionMetrics`.
 */
declare function _resetMessageQueueForTests(): void;

/**
 * @kodax-ai/agent/messaging/drain — mid-turn drain decision (FEATURE_115).
 *
 * Mid-turn drain pulls queued messages between tool execution and the
 * next LLM call. Default ceiling is `user` priority — user input
 * interrupts the agent loop; background-priority messages
 * (subagent task-notifications) wait for the next safe boundary.
 *
 * **FEATURE_155 v0.7.39 Slice C2 — yield-tool gate retired.** Before
 * v0.7.39 the drain widened to background priority when the agent had
 * just called `await_child_task` (FEATURE_119 Pattern B). With idle-
 * yield (the default since Slice B1.D), `await_child_task` is gone and
 * the runner's outer loop in
 * `coding/src/task-engine/_internal/managed-task/idle-yield.ts` owns
 * background-priority dequeue at the no-tool-calls exit. The mid-turn
 * drain therefore stays at `user` priority — that's the only path
 * where it makes sense to interrupt the agent without violating the
 * tool_use/tool_result pairing contract. `YIELD_TOOL_NAMES` and the
 * `lastTurnToolNames` parameter remain on the public surface as a
 * placeholder for any FUTURE yield tool (e.g. an explicit `sleep`),
 * but the set is empty so the gate is currently a no-op.
 */

/**
 * Tools that gate background-priority drain. Empty under FEATURE_155
 * idle-yield (v0.7.39+) — see file header. Adding an entry should
 * remain a deliberate decision: only tools that semantically
 * represent the agent yielding control should unlock background
 * priority, because background drain can interleave subagent
 * results into the main conversation in unexpected places.
 */
declare const YIELD_TOOL_NAMES: ReadonlySet<string>;
interface MaybeDrainMidTurnInput {
    /** Tool names invoked during the most recent iteration's tool_use blocks. */
    readonly lastTurnToolNames: readonly string[];
    /** Current agent's id (`undefined` for the main thread). */
    readonly agentId?: string;
    /** Optional cap on the number of drained messages. */
    readonly limit?: number;
}
/**
 * Returns the priority ceiling that mid-turn drain should use given the
 * tools the agent invoked in the most recent iteration.
 *
 * Under FEATURE_155 idle-yield (`YIELD_TOOL_NAMES` empty by default),
 * this always returns `'user'` — background-priority messages are
 * picked up by the runner-driven outer loop's `waitForWakeEvent` at
 * the no-tool-calls exit, not by the mid-turn drain.
 */
declare function midTurnDrainPriority(lastTurnToolNames: readonly string[]): MessagePriority;
/**
 * Drain queued messages destined for `agentId` (main-thread by default)
 * up to the priority ceiling decided by Sleep gating. Returns the drained
 * messages in `dequeue` order (priority-first FIFO).
 */
declare function maybeDrainMidTurn(input: MaybeDrainMidTurnInput): QueuedMessage[];
interface EnqueueChildTaskNotificationInput {
    /**
     * agentId of the parent / coordinator that should receive the
     * notification. `undefined` targets the main thread.
     */
    readonly parentAgentId?: string;
    /** Stable identifier of the completed child task (e.g. `child-...`). */
    readonly taskId: string;
    /** Human-readable summary appended after the task id banner. */
    readonly summary: string;
}
/**
 * Enqueue a `task-notification` message destined for the parent / main
 * thread when a backgrounded child task finishes (FEATURE_119 Pattern B).
 *
 * Goes in at `priority: 'background'`. Under FEATURE_155 idle-yield
 * (v0.7.39+), the runner's outer loop drains background priority at
 * the no-tool-calls exit (`waitForWakeEvent` →
 * `composeIdleYieldUserMessage`), so the notification surfaces in
 * the agent's next-turn user message as a `<task-completed
 * task_id="…">…</task-completed>` block. Pre-v0.7.39 a `yield tool`
 * (`await_child_task`) gated mid-turn drain to background priority —
 * that path is gone with the tool.
 *
 * Returns the enqueued message id (matches `MessageQueue.enqueue` contract).
 */
declare function enqueueChildTaskNotification(input: EnqueueChildTaskNotificationInput): string;

/**
 * Idle-yield primitives — async chat-while-waiting orchestration core.
 *
 * Originally shipped as `packages/coding/src/task-engine/_internal/
 * managed-task/idle-yield.ts` (v0.7.39 Slices A1-C3, FEATURE_155). The
 * v0.7.38 hotfix follow-up chain (Bug A-G) landed inside the same file.
 * v0.7.39 FEATURE_120 Step 0 (this slice) lifts the module to
 * `@kodax-ai/agent`'s `orchestration/` so any agent-flavor consumer
 * outside KodaX's coding stack can reuse the same async fan-out
 * wait-and-resume mechanic (ADR-021).
 *
 * The lifted module is **generic over the child-task result type**
 * (`TChildResult`). Coding's `KodaXChildExecutionResult` shape stays in
 * `@kodax-ai/coding`; only `taskId` + `error` are read here. The
 * `result` field is opaque — `composeIdleYieldUserMessage` never
 * inspects it (the fallback banner uses only `taskId` / error message).
 *
 * Replaces the blocking `await_child_task` semantics with a Claude-Code-
 * style "agent turn ends idle, runner waits for the next external event"
 * mechanism. When the agent has dispatched ≥1 children and has nothing
 * else to do, it outputs a brief status line (no tool calls), and
 * Runner.run returns. This module gives the runner layer the utilities
 * it needs to interpret that exit and resume:
 *
 *   1. `detectIdleYield(...)` — synchronous predicate over the run's exit
 *      state. Returns true when the agent turn ended without an
 *      `emit_handoff` AND there are still child tasks the agent is
 *      expected to wait on. False on every other path so legacy
 *      semantics stay untouched.
 *
 *   2. `waitForWakeEvent(...)` — async race between child-task
 *      completions and the MessageQueue. Returns the first event so the
 *      runner layer knows what to splice into the next-turn context.
 *      Cooperative with `AbortSignal` so REPL Esc tears it down promptly.
 *
 *   3. `composeIdleYieldUserMessage(...)` — given a resolved
 *      `WakeEvent`, builds the synthetic user message that the runner
 *      should splice into the next `Runner.run` input.
 *
 * Bug A-G hotfix invariants preserved verbatim from the v0.7.38
 * release:
 *
 *   - Bug B / D / `hasEmittedTerminalVerdict` field: outer loop gates
 *     on terminal Evaluator verdict, NOT on legacy
 *     `managedProtocolPayloadRef.verdict`. The agent layer carries
 *     the boolean as a snapshot field; callers compute it.
 *   - Bug E / `hasPendingBackgroundMessages` field: fast-child race
 *     recovery — keep the loop alive when either the registry OR the
 *     queue still has undelivered work.
 *   - Bug F / abort listener cleanup: explicit
 *     `removeEventListener` in `settle()` even on non-abort wakes.
 *   - Bug A registry cleanup: NOT this module's responsibility — owned
 *     by `registerChildTask` in `task-registry.ts`.
 */

/**
 * Env-flag gate for the runner outer-loop wiring.
 *
 * **Slice C3 (v0.7.39) — flag retired as a runtime gate.** With
 * `await_child_task` removed (Slice C1) there is no working "v0.7.38
 * emulation" path: the prompt + banner always teach idle-yield, so
 * gating only the outer loop would leave a flag-OFF deployment with
 * agents that exit text-only but no resumer to wake them. The
 * function is therefore hard-coded to `true` and exists only for
 * import compatibility with the Slice A1/A2 callers and
 * historical-test references; the env var has no effect.
 */
declare function isIdleYieldEnabled(): boolean;
/**
 * Count the `tool_use` blocks on the last assistant message of a Runner
 * transcript. Used to populate `IdleYieldSnapshot.lastAssistantToolCallCount`
 * — a 0 count is the marker for the no-tool-calls exit branch
 * `Runner.run` uses to terminate its tool loop.
 */
declare function countLastAssistantToolCalls(messages: readonly KodaXMessage[]): number;
/** Snapshot of the agent run's exit state, computed by the runner layer. */
interface IdleYieldSnapshot {
    /**
     * The last assistant message's tool-call count from the Runner.run
     * transcript. Idle-yield is signalled when this is 0 (Runner
     * exited via the no-tool-calls branch, not via a tool-driven
     * handoff).
     */
    readonly lastAssistantToolCallCount: number;
    /**
     * Number of child tasks still in the registry when Runner.run
     * returned. Reads `registry.size` at the boundary. Idle-yield only
     * fires when this is > 0 OR `hasPendingBackgroundMessages` is true
     * — otherwise there's nothing to wait for and the stop is a real
     * terminal event.
     */
    readonly pendingChildTaskCount: number;
    /**
     * True if the run's managed-protocol payload has been populated
     * with a handoff (typically `emit_handoff` for the worker→evaluator
     * boundary). False = the run ended without a handoff. Idle-yield
     * REQUIRES this to be false; otherwise the handoff target already
     * owns the next step.
     */
    readonly hasEmittedHandoff: boolean;
    /**
     * v0.7.38 FEATURE_155 Bug B+D hotfix — true if the run's managed-
     * protocol payload has been populated with a terminal verdict
     * (`accept` / `blocked`; `revise` triggers a chain re-run, not
     * idle-yield continuation). Without this gate the outer loop would
     * keep re-entering `Runner.run` after a terminal verdict — wasting
     * LLM turns on post-verdict child notifications. Idle-yield
     * REQUIRES this to be false; same reasoning as `hasEmittedHandoff`
     * but for the verdict side.
     */
    readonly hasEmittedTerminalVerdict: boolean;
    /**
     * v0.7.38 FEATURE_155 Bug E hotfix — true if the background-priority
     * message queue still has undelivered banners destined for the
     * caller agent. Set this alongside `pendingChildTaskCount` because
     * of the **fast-child race**: the dispatch IIFE may enqueue a
     * notification BEFORE its promise resolves, and the registry's
     * `.finally(delete)` cleanup runs in the same microtask burst.
     * When a child completes faster than the surrounding Runner.run
     * iteration (e.g. a sub-second probe vs a multi-second LLM call),
     * the registry entry is removed BEFORE the outer loop reads
     * `pendingChildTaskCount` — making the snapshot see `0`, breaking
     * the loop, and orphaning the banner in the background queue.
     * With this field, the loop stays in the wait state whenever
     * there's still something to deliver, regardless of which arm
     * (registry or queue) carries it.
     *
     * Drained only by the outer loop's `composeIdleYieldUserMessage`
     * call AFTER `waitForWakeEvent` returns. The mid-turn drain caps
     * at `user` priority post-FEATURE_155, so this is the **only**
     * consumer of background-priority messages — losing it strands
     * the banner.
     */
    readonly hasPendingBackgroundMessages: boolean;
}
/**
 * Pure predicate. True when the agent turn ended via the
 * "no tool calls + still has pending children" path that idle-yield
 * is designed to handle.
 *
 * The conjunction terms are deliberately independent — caller can mix
 * in additional gating (e.g. a feature flag) without rewriting this.
 * Returning false here means "treat the run as terminal / delegate to
 * legacy semantics" and is the safe default. The current term set is:
 * `lastAssistantToolCallCount`, `hasEmittedHandoff`,
 * `hasEmittedTerminalVerdict`, and (`pendingChildTaskCount` OR
 * `hasPendingBackgroundMessages`) — the last pair forms the wait-or-
 * resume gate (fast-child race recovery; see field docs).
 */
declare function detectIdleYield(snapshot: IdleYieldSnapshot): boolean;
/**
 * FEATURE_167 (v0.7.41) — terminal-verdict-missing predicate.
 *
 * Companion to `detectIdleYield`, gating the OPPOSITE half of the
 * outer-loop exit decision: when the inner Runner.run loop exits
 * with no tool calls AFTER a handoff has fired but BEFORE the
 * Evaluator has emitted a terminal verdict, the run is structurally
 * INCOMPLETE — the audit step is missing. `detectIdleYield` correctly
 * returns false in this state (the gate at line 174 short-circuits on
 * `hasEmittedHandoff`), so the outer loop currently terminates with
 * `recorder.verdict === undefined`. Downstream `deriveFinalStatus`
 * then falls back to `signal:'COMPLETE'`, falsely reporting success
 * for a failed audit (production session 20260515_185354).
 *
 * This predicate identifies that exact missing-verdict state so the
 * outer loop can branch into a retry path (inject a "call emit_verdict"
 * prompt and re-invoke the Evaluator) before falling through to a
 * synthesized fallback verdict.
 *
 * **Disjoint from `detectIdleYield`** by construction:
 *
 *   - `detectIdleYield` requires `!hasEmittedHandoff`
 *   - `detectMissingTerminalVerdict` requires `hasEmittedHandoff`
 *
 * Both also require `lastAssistantToolCallCount === 0`. Both gate on
 * `!hasEmittedTerminalVerdict`. The two predicates partition the
 * "Evaluator turn just exited text-only" space cleanly — no run can
 * satisfy both.
 *
 * **Pending children take precedence over verdict retry.** Predicate
 * is intentionally `pendingChildTaskCount <= 0 && !hasPendingBackgroundMessages`
 * so that if Evaluator dispatched audit children and is correctly
 * idle-yielding for them (FEATURE_155 Bug C discipline), the
 * verdict-missing retry does NOT fire — `detectIdleYield` handles
 * that path instead. Only when there's nothing left to wait on does
 * the verdict-missing branch take over.
 */
declare function detectMissingTerminalVerdict(snapshot: IdleYieldSnapshot): boolean;
/**
 * Discriminated union surfacing the reason a wake completed.
 *
 * Generic over `TChildResult` so coding-flavor consumers can carry
 * their `KodaXChildExecutionResult` shape through `child-completed`
 * wakes without the agent layer naming the type. This module only
 * reads `taskId` (for the fallback banner) and `error` — `result` is
 * opaque pass-through.
 */
type WakeEvent<TChildResult = unknown> = {
    readonly kind: 'child-completed';
    readonly taskId: string;
    readonly result: TChildResult;
} | {
    readonly kind: 'child-failed';
    readonly taskId: string;
    readonly error: Error;
} | {
    readonly kind: 'messages-arrived';
    readonly messages: readonly QueuedMessage[];
} | {
    readonly kind: 'aborted';
};
interface WaitForWakeEventOptions<TChildResult = unknown> {
    /**
     * Live ChildTaskRegistry snapshot. The waiter wraps each entry's
     * promise so the FIRST settling child wins the race.
     *
     * **NOTE**: the waiter does NOT delete entries on settlement — the
     * registry's normal cleanup path (`registerChildTask`'s built-in
     * `.finally` chain) owns deletion. Wrapping doesn't double-consume.
     */
    readonly registry: ChildTaskRegistry<TChildResult>;
    /** Process-global message queue surface (FEATURE_115 substrate). */
    readonly messageQueue: MessageQueue;
    /**
     * AgentId filter for queue dequeues. Use `undefined` to match
     * main-thread messages (the standard queue scope).
     */
    readonly agentId: string | undefined;
    /**
     * Optional cancellation. When fired, the waiter resolves with
     * `{ kind: 'aborted' }` and tears down its poll timer.
     */
    readonly abortSignal?: AbortSignal;
    /**
     * Queue poll interval. The MessageQueue is poll-based; this is the
     * granularity at which user input becomes visible to the waiter.
     * 100 ms keeps perceived REPL responsiveness < 1 frame at 60 fps
     * for the human eye and stays well below typical LLM-call latency.
     * Tests can pass smaller values (e.g. 10 ms) to keep them fast.
     */
    readonly pollIntervalMs?: number;
}
/**
 * Race child completions against MessageQueue arrivals. Returns the
 * first wake event. Guarantees:
 *
 *   - Cleanup: the poll timer is cleared on resolution regardless of
 *     which arm wins.
 *   - At-most-once dequeue: when the queue arm wins, the messages it
 *     drained are returned to the caller AND removed from the queue
 *     (the caller is now responsible for splicing them into the
 *     agent's next-turn context).
 *   - Abort-safe: if `abortSignal` fires before any other event, the
 *     waiter resolves with `{ kind: 'aborted' }`. Already-settled
 *     child promises are NOT cancelled — the registry's owner handles
 *     them on the next turn.
 *
 * Caller responsibilities:
 *   - Pass the EXACT registry snapshot (not a copy) so subsequent
 *     dispatches the agent performs after wake are visible to the
 *     next `waitForWakeEvent` call.
 *   - Splice the returned messages / child result into the agent's
 *     next Runner.run input. The waiter does not itself construct
 *     synthetic user-message bytes — that's the runner-layer's job.
 */
declare function waitForWakeEvent<TChildResult = unknown>(options: WaitForWakeEventOptions<TChildResult>): Promise<WakeEvent<TChildResult>>;
/**
 * Compose the synthetic user message spliced after an agent idle-yield
 * resume. The runner outer loop calls this with the resolved
 * `WakeEvent` plus a function that drains any pending background
 * messages (typically `() => getMessageQueue().dequeue(...)`).
 *
 *   - `messages-arrived` wake: the queue arm already drained the
 *     QueuedMessage(s); pass their content through verbatim. Then
 *     drain anything that arrived between settle and this call (a
 *     tight race with the dispatch handler's enqueue is possible) and
 *     concatenate.
 *
 *   - `child-completed` / `child-failed` wake: the dispatch handler's
 *     in-IIFE `enqueueChildTaskNotification` is a precondition of the
 *     promise settling, so the queue holds the canonical
 *     `<task-completed>` banner. Drain to capture it. If for any
 *     reason the banner is missing (defensive — a misbehaving
 *     dispatch path that resolved without enqueuing), synthesize a
 *     minimal one from the wake event so the agent still observes
 *     the resolution rather than silently looping again.
 *
 *   - `aborted`: caller is expected to break out before reaching this
 *     helper. If reached anyway, returns `undefined` so the outer
 *     loop treats it as a terminal exit.
 *
 * Returns `undefined` when the wake yields no spliceable content —
 * the outer loop treats that as a real terminal exit.
 */
/**
 * FEATURE_121 (v0.7.40) — Envelope aggregate budget enforcer.
 *
 * Pure `string[] → string[]` transform applied to drained envelope
 * fragments before they're joined into a single synthetic user
 * message. The coding layer provides the implementation that knows
 * how to spill oversized fragments to disk and replace them with
 * preview + path markers (see `@kodax-ai/coding`
 * `createEnvelopeAggregateBudgetEnforcer`). The agent layer only
 * sees this opaque function type — **no `@kodax-ai/coding` symbols
 * may leak into this signature**, otherwise ADR-021 layer
 * independence breaks and `@kodax/agent` cannot build standalone.
 */
type EnvelopeAggregateEnforcer = (fragments: readonly string[]) => readonly string[] | Promise<readonly string[]>;
/**
 * FEATURE_159 (v0.7.40) — mode-split synthetic.
 *
 * Pre-FEATURE_159: every wake-drained message was wrapped in a single
 * `_synthetic: true` user message. This was correct for child-task
 * notifications (the agent needs to see them; the human doesn't), but
 * WRONG for user-typed prompts that arrived via chat-while-waiting —
 * those got hidden from the transcript so users couldn't see their own
 * messages echoed in the conversation history.
 *
 * Post-FEATURE_159: fragments are partitioned by `msg.mode`. Two
 * separate messages may be emitted:
 *   1. Synthetic banner (`_synthetic: true`) — concatenates
 *      `task-notification` + `system-reminder` content. Hidden from
 *      REPL display; the agent sees it as context. Spliced FIRST so it
 *      reads as the "tail of the prior turn" before the new prompt.
 *   2. Real user message (no `_synthetic`) — concatenates `prompt`
 *      content from chat-while-waiting. Renders as a normal user
 *      bubble in transcript. Spliced AFTER the banner so the chain
 *      reads naturally as "previous turn outputs → user follow-up".
 *
 * Aggregate budget enforcer applies ONLY to the synthetic banner
 * fragments (the side that can carry child-task envelopes of arbitrary
 * size). User prompts pass through unchanged — the user's intent must
 * never be silently truncated.
 *
 * Return type changed from `KodaXMessage | undefined` to
 * `readonly KodaXMessage[]` (possibly empty). Callers must spread the
 * result into their next-iteration input.
 */
declare function composeIdleYieldUserMessage<TChildResult = unknown>(wakeEvent: WakeEvent<TChildResult>, drainBackgroundQueue: () => readonly QueuedMessage[], enforceAggregate?: EnvelopeAggregateEnforcer): Promise<readonly KodaXMessage[]>;

/**
 * Generic outer loop for async fan-out + idle-yield resume.
 *
 * FEATURE_120 v0.7.39 Step 0c. Wraps the `while (true) { Runner.run; if
 * (detectIdleYield) waitForWakeEvent + compose + resume; else break }`
 * control flow so that any agent flavor consuming `@kodax-ai/agent` as
 * a standalone framework can adopt the FEATURE_155 chat-while-waiting
 * pattern without re-implementing the loop and re-discovering the
 * v0.7.38 Bug A-G hotfix invariants.
 *
 * The wrapper does NOT take ownership of any agent-flavor-specific
 * state — recorder access, role mapping, status-bar emission,
 * checkpoint cleanup, chain-reset-on-resume — those flow in through
 * callbacks. The wrapper owns only the universal pieces:
 *
 *   1. Iteration cap (default 64) — defensive against prompt bugs.
 *   2. Per-iteration `runOnce` invocation (callee owns Runner.run
 *      options closure + error-path cleanup chain).
 *   3. Snapshot computation via callback, then `detectIdleYield` gate.
 *   4. Optional `onIdleWaiting` hook fired AFTER the gate passes but
 *      BEFORE the wake wait.
 *   5. `waitForWakeEvent` with the registry / queue / abort plumbing.
 *   6. `composeIdleYieldUserMessage` to splice synthetic input.
 *   7. `resumeAgent` callback to pick the agent for the next iteration.
 *
 * Order is significant — see Risk R4 in v0.7.39 Phase 1c design notes.
 * Tests in `runner-with-idle-yield.test.ts` pin every boundary.
 *
 * The wrapper has zero inbound dependency on coding-flavor types; all
 * agent-flavor specifics flow through `TRunResult` / `TChildResult` /
 * the callbacks (ADR-021).
 */

/** Default iteration cap matches the legacy `IDLE_YIELD_MAX_ITERATIONS` constant. */
declare const DEFAULT_IDLE_YIELD_MAX_ITERATIONS = 64;
/**
 * Minimal shape requirement on the run result the caller's `runOnce`
 * returns. The wrapper reads `messages` to replay the transcript into
 * the next iteration after a wake; everything else on the result is
 * opaque pass-through.
 */
interface RunWithIdleYieldRunResult {
    readonly messages: readonly AgentMessage[];
}
interface RunWithIdleYieldOptions<TRunResult extends RunWithIdleYieldRunResult, TChildResult> {
    /** Agent that executes the first iteration of the loop. */
    readonly initialAgent: Agent;
    /** Initial input messages for the first `Runner.run`. */
    readonly initialInput: readonly AgentMessage[];
    /**
     * Per-iteration Runner invocation. Caller closes over its Runner
     * options (llm, guardrails, toolObserver, maxToolLoopIterations,
     * abortSignal, compactionHook, error-path cleanup). The wrapper
     * passes the current `agent` and `input` and awaits the result.
     *
     * **Error-path note**: if `runOnce` rejects, the rejection
     * propagates out of `runWithIdleYield` verbatim — wrapper does not
     * swallow. Caller's `.catch` (if any) must run inside the
     * `runOnce` closure to keep cleanup ordering observable.
     */
    readonly runOnce: (agent: Agent, input: readonly AgentMessage[]) => Promise<TRunResult>;
    /**
     * Compute the `IdleYieldSnapshot` after each `runOnce` returns.
     * Caller has access to the full run result + any external state
     * via closure (recorder, registry size, queue inspection).
     */
    readonly computeSnapshot: (runResult: TRunResult) => IdleYieldSnapshot;
    /**
     * Live child-task registry. Passed verbatim to `waitForWakeEvent`'s
     * `registry` arm. Mutations to this map between iterations are
     * visible to the next wake.
     */
    readonly registry: ChildTaskRegistry<TChildResult>;
    /** Process-global message queue. Passed verbatim to `waitForWakeEvent`. */
    readonly messageQueue: MessageQueue;
    /**
     * AgentId scope for the queue arm. `undefined` matches main-thread
     * messages (the default scope a parent agent's dispatch handler
     * targets).
     */
    readonly agentId: string | undefined;
    /** Optional cancellation. Tears the loop down on the next wait boundary. */
    readonly abortSignal?: AbortSignal;
    /**
     * Choose the agent for the next iteration after a wake. Caller has
     * access to the just-finished run result; coding-flavor consumers
     * typically return their `chain.worker` regardless of the result.
     */
    readonly resumeAgent: (runResult: TRunResult) => Agent;
    /**
     * Optional hook fired AFTER `detectIdleYield` returns true but BEFORE
     * `waitForWakeEvent` parks. Used by coding for FEATURE_156 status-bar
     * emission. The `currentAgent` arg is the agent that just ran (so
     * role lookups read the right name on every iteration).
     */
    readonly onIdleWaiting?: (currentAgent: Agent, runResult: TRunResult) => void;
    /**
     * Optional hook fired when the iteration cap is hit. Coding does not
     * currently log here (matches v0.7.38 behavior — silent break) but
     * the hook exists so SDK consumers can record the prompt-bug signal.
     */
    readonly onIterationCap?: () => void;
    /**
     * Defensive ceiling on outer-loop iterations. Default 64 matches the
     * legacy `IDLE_YIELD_MAX_ITERATIONS` constant. Set lower in tests to
     * exercise the cap branch quickly.
     */
    readonly maxIterations?: number;
    /**
     * FEATURE_121 (v0.7.40): optional aggregate budget enforcer for the
     * synthetic user message built from drained background banners. When
     * provided, it transforms the fragment array before they're joined
     * (per-banner per-`<task-completed>` summary chunks remain unchanged
     * by this wrapper — that's the caller's responsibility at enqueue
     * time via `applyToolResultGuardrail`). The aggregate hook only kicks
     * in when N banners' total exceeds the limit set by the coding-layer
     * implementation (default 200KB per claudecode parity).
     *
     * Type is `string[] → string[] | Promise<string[]>` so the agent
     * layer carries no `@kodax-ai/coding` symbols. See
     * `EnvelopeAggregateEnforcer` in idle-yield.ts.
     */
    readonly envelopeAggregateEnforcer?: EnvelopeAggregateEnforcer;
}
/**
 * Run the agent chain with idle-yield resume.
 *
 * On each iteration:
 *   1. Invoke `runOnce(currentAgent, currentInput)`.
 *   2. Increment the iteration counter. If it exceeds
 *      `maxIterations`, call `onIterationCap?.()` and break.
 *   3. Compute the snapshot via `computeSnapshot(runResult)`.
 *   4. If `detectIdleYield(snapshot)` is false (run terminal or
 *      handoff/verdict already emitted), break.
 *   5. Fire `onIdleWaiting?.(currentAgent, runResult)`.
 *   6. Park in `waitForWakeEvent({registry, messageQueue, agentId, abortSignal})`.
 *   7. If wake is `aborted`, break.
 *   8. Build synthetic user message via `composeIdleYieldUserMessage`.
 *      If undefined (truly empty wake), break.
 *   9. Replay: `currentInput = [...runResult.messages, syntheticUserMessage]`,
 *      `currentAgent = resumeAgent(runResult)`, loop.
 *
 * Returns the last `runResult` (the one that broke the loop).
 *
 * Bug A-G hotfix invariants preserved:
 *   - Bug A (registry cleanup): owned by `registerChildTask` —
 *     unaffected by this wrapper.
 *   - Bug B/D (terminal-verdict + handoff gates): caller's
 *     `computeSnapshot` must populate `hasEmittedTerminalVerdict`
 *     and `hasEmittedHandoff` from the canonical recorder source.
 *   - Bug E (fast-child race): caller's `computeSnapshot` must read
 *     `hasPendingBackgroundMessages` alongside the registry size.
 *   - Bug F (abort listener leak): owned by `waitForWakeEvent` —
 *     unaffected by this wrapper.
 */
declare function runWithIdleYield<TRunResult extends RunWithIdleYieldRunResult, TChildResult>(opts: RunWithIdleYieldOptions<TRunResult, TChildResult>): Promise<TRunResult>;

/**
 * Generic concurrency-bounded fan-out — `runFanOut`.
 *
 * FEATURE_120 v0.7.39 Step 0d (Option D scope). Lifts the truly
 * agent-flavor-agnostic part of `@kodax-ai/coding`'s `executeChildAgents`
 * orchestrator: bounded-concurrency `Promise.allSettled` + abort-pre-
 * check + structured progress events + cancelled-bundles tracking.
 *
 * What stays at `@kodax-ai/coding`'s `executeChildAgents`:
 *   - `KodaXChildContextBundle` / `KodaXChildExecutionResult` shapes
 *   - read vs write child differentiation
 *   - `validateWriteBundles` role policy
 *   - worktree isolation + cleanup
 *   - briefing + `CHILD_AGENT_SYSTEM_PROMPT` injection
 *
 * What lives here:
 *   - Bounded concurrency via private semaphore
 *   - Pre-execution abort check (cancelled bundles collected)
 *   - Promise.allSettled-style rejection capture
 *   - Per-bundle structured progress events (`start` / `item-done` /
 *     `item-failed`) with stable bundle reference + completed/total
 *     counter via a second context argument
 *
 * The wrapper has zero inbound dependency on coding-flavor types —
 * `TBundle` and `TResult` are fully opaque to the module (ADR-021).
 */
/** Discriminated union for `onProgress` event payloads. */
type FanOutProgressEvent<TBundle, TResult> = {
    readonly kind: 'start';
    readonly bundle: TBundle;
    readonly bundleIndex: number;
} | {
    readonly kind: 'item-done';
    readonly bundle: TBundle;
    readonly bundleIndex: number;
    readonly result: TResult;
} | {
    readonly kind: 'item-failed';
    readonly bundle: TBundle;
    readonly bundleIndex: number;
    readonly error: Error;
};
interface RunFanOutOptions<TBundle, TResult> {
    /**
     * The bundles to execute. Order is preserved as the canonical
     * "bundle index" for progress events; result order is **completion
     * order**, not bundle order (mirror callers use the bundle reference
     * carried in each event or each result to attribute outcomes).
     */
    readonly bundles: readonly TBundle[];
    /**
     * Per-bundle executor. The wrapper invokes this after acquiring a
     * concurrency slot AND after passing the abort pre-check. If the
     * promise rejects, the rejection is captured in the result
     * `{status: 'rejected', bundle, reason}` and onProgress's
     * `item-failed` event fires; otherwise `{status: 'fulfilled', bundle,
     * value}` and `item-done` fires.
     */
    readonly runOne: (bundle: TBundle) => Promise<TResult>;
    /**
     * Maximum concurrent in-flight `runOne` invocations. Must be ≥ 1;
     * a value of 1 collapses the fan-out to strict serial execution.
     */
    readonly maxParallel: number;
    /**
     * Optional cancellation signal. Checked AFTER each semaphore acquire
     * but BEFORE invoking `runOne`. Bundles whose abort check fires are
     * added to `cancelled` and never see their `runOne` call. In-flight
     * `runOne` invocations are NOT interrupted — abort acts as a "stop
     * scheduling new work" signal.
     */
    readonly abortSignal?: AbortSignal;
    /**
     * Optional progress hook. The first argument is the event; the
     * second is a shared snapshot of `{completedCount, totalCount}`
     * captured at the moment the event fires (so callers don't need
     * to maintain their own counter).
     */
    readonly onProgress?: (event: FanOutProgressEvent<TBundle, TResult>, ctx: {
        readonly completedCount: number;
        readonly totalCount: number;
    }) => void;
}
/**
 * Per-bundle outcome carried in the final result. Mirrors
 * `PromiseSettledResult` but adds the originating `bundle` for easy
 * mapping back to caller-owned state.
 */
type FanOutOutcome<TBundle, TResult> = {
    readonly status: 'fulfilled';
    readonly bundle: TBundle;
    readonly value: TResult;
} | {
    readonly status: 'rejected';
    readonly bundle: TBundle;
    readonly reason: Error;
};
interface RunFanOutResult<TBundle, TResult> {
    /**
     * Per-bundle outcomes in **completion order** (NOT input bundle
     * order). Use the embedded `bundle` reference to map outcomes back
     * to caller state — index-based access is order-fragile.
     */
    readonly results: ReadonlyArray<FanOutOutcome<TBundle, TResult>>;
    /**
     * Bundles that were skipped due to abort firing before their
     * `runOne` call. Preserves input bundle reference so callers can
     * map back to their own per-bundle state.
     */
    readonly cancelled: readonly TBundle[];
}
/**
 * Run `runOne` over each bundle with bounded concurrency. Returns
 * after every bundle has either settled (`results`) or been skipped
 * due to abort (`cancelled`).
 *
 * Behavior:
 *   - Empty `bundles` → returns `{results: [], cancelled: []}`
 *     immediately without firing any events.
 *   - `maxParallel ≥ bundles.length` collapses to native
 *     `Promise.allSettled` semantics (no semaphore contention).
 *   - `maxParallel === 1` collapses to strict serial execution.
 *   - Each successful `runOne` fires `onProgress({kind: 'item-done',
 *     ..., result})` AFTER `completedCount` is incremented (so the
 *     `ctx.completedCount` in the event reflects "including this
 *     one").
 *   - Each failed `runOne` fires `onProgress({kind: 'item-failed',
 *     ..., error})` with `completedCount` updated the same way —
 *     the counter counts settled items regardless of success.
 *   - Abort firing AFTER a bundle has entered `runOne` does NOT
 *     cancel that bundle's promise — it completes normally and
 *     joins `results`. Only bundles still waiting for a semaphore
 *     slot (or those whose semaphore-acquired callback runs after
 *     abort) get marked cancelled.
 */
declare function runFanOut<TBundle, TResult>(opts: RunFanOutOptions<TBundle, TResult>): Promise<RunFanOutResult<TBundle, TResult>>;

/**
 * Generic cross-agent send-message router primitive.
 *
 * FEATURE_120 v0.7.39 Phase 2a (ADR-021). Coordinator-style agents need
 * to dispatch instructions to running peer/child agents whose execution
 * is gated by an agentId-scoped `MessageQueue`. This module owns the
 * minimal "validate target exists, enqueue addressed message, report
 * outcome" trio so the @kodax-ai/agent package can ship the substrate
 * without inheriting any coding-flavor framing.
 *
 * Caller responsibilities (NOT done here):
 *   - Content framing (e.g., `<coordinator-instruction>` tag wrapping)
 *     — this is a tool-layer / flavor concern.
 *   - Priority choice — the caller decides whether a route is
 *     `'user'` (interrupts) or `'background'` (queued for next yield).
 *   - Mode choice — `'prompt'` for new instructions,
 *     `'system-reminder'` for advisory metadata, etc.
 *   - Sentinel target handling (e.g., broadcast `'*'`) — the router
 *     rejects them as `unknown-target` because they aren't registry
 *     keys; callers can intercept upstream if they need fan-out
 *     semantics.
 *
 * What this primitive owns:
 *   - Existence check against a `ReadonlyMap<string, unknown>`
 *     registry — the value type is opaque; we only care about key
 *     membership.
 *   - Enqueue via `MessageQueue.enqueue` with `agentId` set to `to`.
 *   - Structured result so callers can render success / error UX
 *     without re-parsing strings.
 */

interface RouteMessageOptions {
    /** Target agentId. Must exist as a key in `registry`. */
    readonly to: string;
    /** Priority class — `'user'` interrupts, `'background'` waits. */
    readonly priority: MessagePriority;
    /** Message mode — caller selects based on intent. */
    readonly mode: MessageMode;
    /**
     * Pre-formatted message body. The router does NOT wrap this — any
     * framing (e.g. tags) must be applied by the caller before invoking.
     */
    readonly content: string;
    /**
     * Registry the target must appear in. The value type is opaque; the
     * router only calls `.has(to)`. Pass a `ChildTaskRegistry<T>` for the
     * standard child-task case, or any other `ReadonlyMap<string, ?>`.
     */
    readonly registry: ReadonlyMap<string, unknown>;
    /** Queue to enqueue into when the target is known. */
    readonly queue: MessageQueue;
}
type RouteMessageResult = {
    readonly ok: true;
    readonly messageId: string;
} | {
    readonly ok: false;
    readonly reason: 'unknown-target';
    readonly to: string;
};
/**
 * Validate that `to` is registered, then enqueue an addressed message.
 *
 * Returns `{ok: true, messageId}` on success; `{ok: false, reason:
 * 'unknown-target', to}` when the target is missing from `registry`.
 * On failure the queue is not mutated.
 *
 * Synchronous because `MessageQueue.enqueue` is synchronous — the
 * routing decision is a pure function of registry membership.
 */
declare function routeMessage(opts: RouteMessageOptions): RouteMessageResult;

/**
 * FEATURE_125 (v0.7.41) — Team Mode Layer 2b: system-prompt injection.
 *
 * Renders the `=== Other active KodaX sessions ===` block that the
 * coding-side system-prompt builder splices into the worker system
 * prompt when sibling instances are alive. Pure formatter — no fs,
 * no clock, no globals.
 *
 * Contract:
 *   - Input: a list of `DiscoveredInstance` (from S2) + `nowMs`.
 *   - Output: a string block (or empty string when input is empty).
 *   - When the list is empty, returns `''` so the caller can splice
 *     unconditionally without an `if (block)` branch.
 *   - When the list is non-empty, the rendered block is bookended by
 *     a single header line and a single coordination-guidance paragraph
 *     so the LLM has clear context for the data it just received.
 *
 * The block deliberately does NOT prescribe a specific action (no
 * "you MUST avoid editing X"); it surfaces context and lets the LLM
 * self-decide per the FEATURE_125 LLM-First philosophy. The prompt
 * eval at S7 verifies LLM behavior under this block.
 */

interface RenderOptions {
    /**
     * Defaults to `Date.now()`. Tests pass a controllable clock.
     * Affects only the "(started N min ago)" / "(M min ago)" relative
     * timestamps; absolute fields are passed through verbatim.
     */
    readonly nowMs?: number;
    /**
     * Maximum number of sibling instances to render. Defaults to 5 —
     * if a user has >5 sessions open we summarize the rest with a
     * "+N more" hint rather than blowing up the system prompt. Per
     * EVAL_GUIDELINES, prompt context budget is finite; cap before
     * the LLM-call site (not after).
     */
    readonly maxRendered?: number;
    /**
     * Cap on `recentlyModifiedFiles` per peer. Defaults to 3 — keeps
     * the block scannable when one peer has touched many files.
     */
    readonly maxRecentFilesPerPeer?: number;
}
/**
 * Build the system-prompt block describing currently-active sibling
 * KodaX sessions. Pure function — same inputs always produce the same
 * output.
 *
 * Returns `''` (empty string) when `instances.length === 0`. Callers
 * splice with template-literal concatenation; the empty-string default
 * means no conditional is needed.
 */
declare function buildOtherInstancesPromptBlock(instances: readonly DiscoveredInstance[], options?: RenderOptions): string;

/**
 * FEATURE_125 (v0.7.41) — Team Mode bootstrap helper.
 *
 * One-call entry point invoked from the REPL bootstrap (`kodax_cli.ts`
 * / `repl.ts`) once per process. Wires the four moving parts:
 *
 *   1. Reaps stale instance directories left by crashed peers
 *      (acceptance criterion 7 in v0.7.41.md).
 *   2. Constructs the `StateWriter` (S1) using sensible defaults.
 *   3. Registers the writer in the process-level singleton (S3
 *      consumers + tool-result paths use `getActiveTeamModeWriter`).
 *   4. Returns a small handle exposing the writer, a sibling-snapshot
 *      function (used by the runner-driven adapter once per LLM
 *      round), and an idempotent `shutdown()`.
 *
 * Disabled via `KODAX_DISABLE_MULTI_INSTANCE=1` — the helper returns
 * `null` and the singleton stays empty so every caller silently falls
 * back to solo-mode behavior. The env var is the project-spec escape
 * hatch for failure diagnosis; do NOT use it as a daily-driver opt-out.
 *
 * DI-clean: optional `fs`, `clock`, `instancesRoot` overrides so tests
 * can exercise the full lifecycle without touching `~/.kodax`.
 */

interface TeamModeBootstrapOptions {
    /** Static session meta. Required because cwd / startedAt are essential. */
    readonly meta: SessionMeta;
    /**
     * Initial published state. Defaults to `{ agentPhase: 'idle' }` —
     * callers typically update this immediately when work begins.
     */
    readonly initialState?: SessionStateSnapshot;
    /**
     * pid override; defaults to `process.pid`. Tests inject a stable
     * pid; production never passes this.
     */
    readonly pid?: number;
    /**
     * Override the instances root directory. Defaults to
     * `getAgentConfigPath('instances')` via the underlying
     * `createStateWriter` / `discoverInstances`. Tests pass a temp dir.
     */
    readonly instancesRoot?: string;
    /** Inject an in-memory fs for both the writer and the discovery scan. Tests only. */
    readonly fs?: StateWriterFs & InstanceDiscoveryFs;
    readonly clock?: () => number;
    readonly heartbeatIntervalMs?: number;
    /**
     * Pass `false` to skip the initial reap of stale peer directories.
     * Defaults to `true` — every session that bootstraps Team Mode is
     * also a candidate cleaner for crashed peers.
     */
    readonly reapStaleOnStart?: boolean;
    /** Forwarded to discoverInstances for per-instance failure logs. */
    readonly logger?: (message: string) => void;
}
interface TeamModeHandle {
    readonly writer: StateWriter;
    /**
     * Get the current sibling snapshot. Cheap (a single readdir + N
     * stat). Caller wires this into the runner-driven LLM-call prefix
     * so each round sees a fresh sibling list — Team Mode block is
     * intentionally NOT cached in the stable system-prompt prefix.
     */
    discoverSiblings(): DiscoveredInstance[];
    /**
     * Tear down the writer + clear the singleton. Idempotent. Safe to
     * call from a process-exit handler, an Ink unmount, or an explicit
     * `/exit` slash command.
     */
    shutdown(): Promise<void>;
}
declare function bootstrapTeamMode(options: TeamModeBootstrapOptions): TeamModeHandle | null;

/**
 * FEATURE_125 (v0.7.41) — Process-level singleton for Team Mode.
 *
 * One KodaX process owns at most one `StateWriter` instance. Consumers
 * scattered across the codebase (REPL bootstrap, tool execution
 * contexts, runner-driven adapter, todo store) need a shared handle
 * without threading the writer through every signature. This module
 * is the canonical accessor:
 *
 *   - `setActiveTeamModeWriter(writer)` — REPL bootstrap calls this
 *     once after `createStateWriter`.
 *   - `getActiveTeamModeWriter()` — any module asks the singleton for
 *     the live writer (or null when Team Mode is disabled / hasn't
 *     bootstrapped yet).
 *   - `updateActiveTeamMode(patch)` — convenience for "I want to
 *     bump current_intent / active_files; do nothing if no writer".
 *
 * Mirrors the `activeExtensionRuntime` singleton pattern in
 * `packages/coding/src/extensions/runtime.ts` so familiarity is
 * preserved.
 */

declare function setActiveTeamModeWriter(writer: StateWriter | null): void;
declare function getActiveTeamModeWriter(): StateWriter | null;
/**
 * Convenience: if a writer is active, merge `patch` into its state +
 * flush. No-op when Team Mode is disabled (no writer was bootstrapped,
 * or `KODAX_DISABLE_MULTI_INSTANCE=1` short-circuited the bootstrap).
 */
declare function updateActiveTeamMode(patch: Partial<SessionStateSnapshot>): void;

export { Agent, AgentManifest, AgentMessage, CORE_INVARIANTS, ChildTaskRegistry, DEFAULT_IDLE_YIELD_MAX_ITERATIONS, DequeueFilter, DiscoveredInstance, EnqueueInput, Handoff, InstanceDiscoveryFs, InvariantId, KodaXMessage, ManifestPatch, MessageMode, MessagePriority, MessageQueue, QualityInvariant, QueuedMessage, RunnerToolCall, RunnerToolResult, SessionMeta, SessionStateSnapshot, StateWriter, StateWriterFs, YIELD_TOOL_NAMES, _resetAdmissionMetrics, _resetInvariantRegistry, _resetMessageQueueForTests, applyManifestPatch, bootstrapTeamMode, buildOtherInstancesPromptBlock, composeIdleYieldUserMessage, composePatches, countLastAssistantToolCalls, detectHandoffSignal, detectIdleYield, detectMissingTerminalVerdict, emitHandoffSpan, enqueueChildTaskNotification, evidenceTrail, finalOwner, getActiveTeamModeWriter, getAdmissionMetricsSnapshot, getInvariant, getMessageQueue, handoffLegality, isAdmissionDebugEnabled, isIdleYieldEnabled, listRegisteredInvariants, maybeDrainMidTurn, midTurnDrainPriority, registerCoreInvariants, registerInvariant, replaceSystemMessage, resolveEffectiveInvariants, resolveRequiredInvariants, routeMessage, runFanOut, runWithIdleYield, setActiveTeamModeWriter, updateActiveTeamMode, waitForWakeEvent };
export type { AdmissionMetricsSnapshot, EnqueueChildTaskNotificationInput, EnvelopeAggregateEnforcer, FanOutOutcome, FanOutProgressEvent, HandoffSignal, IdleYieldSnapshot, MaybeDrainMidTurnInput, RenderOptions, RouteMessageOptions, RouteMessageResult, RunFanOutOptions, RunFanOutResult, RunWithIdleYieldOptions, RunWithIdleYieldRunResult, TeamModeBootstrapOptions, TeamModeHandle, WaitForWakeEventOptions, WakeEvent };
