/**
 * Public agent types and live-runtime events. Durable transcript facts and
 * turn/step boundaries remain `@deepseek-ai/dsh-session` events.
 *
 * @module @deepseek-ai/dsh-agent
 */
import type { Context } from '@deepseek-ai/cordis';
import type { Scoped } from '@deepseek-ai/dsh-scope';
import type { LlmCallConfig, LlmFailure, ResolvedRetryPolicy } from '@deepseek-ai/dsh-llm';
import type { AgentCancelCause, Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
export type { AgentCancelCause } from '@deepseek-ai/dsh-session';
import type { Inbox } from './inbox.ts';
import type { InboxTarget } from './types.ts';
declare module '@deepseek-ai/dsh-system-prompt' {
    interface AssembleContext {
        /** Agent for this assembly; absent on diagnostics. When present, `scope` must identify the same agent. */
        agent?: Agent;
    }
}
/** Merge-extensible agent creation options. Persona belongs to system-prompt sections. */
export interface AgentOptions {
    /** Provider route (must have a registered adapter at call time). */
    provider?: string;
    /** Model id interpreted by the selected provider adapter. */
    model?: string;
    /** Maximum output tokens for each conversation-model request. */
    maxTokens?: number;
}
/** Options for {@link Agent.cancel}. */
export interface CancelOptions {
    /**
     * Preserve queued and steering inbox items instead of discarding them. The
     * active turn is still aborted, but un-started and pending work survives for a
     * later turn and no canceled inbox splice is logged.
     */
    keepInbox?: boolean | undefined;
}
/**
 * An agent's lifecycle state, emitted on every transition as `agent/status`:
 * `idle` means no driver is active; `running` begins when waking input starts
 * cancellable pre-step processing and lasts while the driver drains,
 * closes, or checkpoints turns. Disposal removes the agent from its registry;
 * it is not a third observable status.
 */
export type AgentStatus = 'idle' | 'running';
/** Whether and with which messages the loop enters a proposed step. */
export type PreStepDecision = {
    kind: 'reject';
} | {
    kind: 'enter';
    messages: UserMessage[];
};
/** Action returned by a listener that owns model-request recovery. */
export type RequestErrorAction = {
    kind: 'retry';
} | undefined;
/** Why a session lifecycle began; seeded creates are `startup`, while persisted loads are `resume`. */
export type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact';
/** Public live-agent handle. */
export interface Agent {
    /** The single identity shared with {@link session}. */
    readonly id: SessionId;
    /** The provider route and model this agent's requests use. */
    readonly options: AgentOptions;
    /** The live session this agent drives; its log is the durable source of truth. */
    readonly session: Session;
    /** The agent-owned projection of durable pending work. */
    readonly inbox: Inbox;
    /** The current lifecycle state, mirrored on every `agent/status` transition. */
    readonly status: AgentStatus;
    /** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */
    readonly ctx: Context;
    /**
     * Clear queued and steering work — unless `keepInbox` — and abort the active
     * turn or between-turn task. The first cause wins for that activity. With no
     * active activity, cancellation is a no-op and does not arm later work.
     * @param cause - the stable caller intent carried by the active operation signal.
     * @param options - cancellation options; `keepInbox` preserves pending work.
     */
    cancel(cause: AgentCancelCause, options?: CancelOptions): void;
    /**
     * Resolve after the current whole-agent activity reaches quiescence. This
     * follows replacement work started before the observed driver retires,
     * but does not identify the settlement of any particular message.
     * @returns fulfillment after no active driver or maintenance task remains.
     */
    whenIdle(): Promise<void>;
    /**
     * Run one non-turn maintenance task from the true idle phase. The task starts
     * synchronously after claiming that phase; later waking input remains in the
     * inbox until the task settles, while public status stays `idle`.
     * `whenIdle()` follows both the task and any waking work released behind it.
     * @param task - operation whose fulfillment or rejection is preserved, with a signal aborted by {@link cancel}.
     * @throws synchronously when turn-driving or another maintenance task already owns the agent.
     * @returns the task promise.
     */
    runMaintenance<T>(task: (signal: AbortSignal) => Promise<T>): Promise<T>;
    /**
     * Route identified input to an inbox boundary and optionally wake the driver.
     * Waking input submitted after active cancellation is queued for the next
     * turn and runs when the aborted activity converges to idle; a `disposed`
     * cancel leaves it parked. A wake submitted while already idle always opens
     * its turn boundary, even when its message is cleared before the driver
     * claims ([cancel-convergence wake latch](../../../../.agents/notes/implemented/bug-fix/2026-08-07-cancel-convergence-wake-latch.md)).
     * @param message - identified content and the source that supplied it.
     * @param target - the preferred next-turn or next-step inbox boundary.
     * @param wakeup - whether delivery may wake the driver.
     */
    send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;
    /**
     * Queue an ordinary follow-up turn and wake the driver. The item becomes the
     * sole ordinary message of its own turn.
     * @param message - identified prompt content and the source that supplied it.
     */
    followup(message: UserMessage): void;
    /**
     * Submit steering for the nearest step. An idle driver starts a turn;
     * a running driver consumes it at its next step boundary.
     * A rejected step leaves steering parked in the inbox until the next
     * wake; cancellation or disposal may discard pending steering.
     * @param message - identified steering content and the source that supplied it.
     */
    steer(message: UserMessage): void;
    /**
     * Queue model-facing context for the next pre-step without waking the
     * driver. A running driver claims it at the nearest later step boundary;
     * idle drivers leave it pending until follow-up or steering
     * wakes them. It may miss a request whose pre-step already claimed its
     * batch. Cancellation or disposal may discard pending context.
     * @param message - identified injected context and the source that supplied it.
     */
    inject(message: UserMessage): void;
}
declare module '@deepseek-ai/cordis' {
    interface Events {
        /**
         * A fully configured agent and live session were published. Setup is
         * composition-only; `agent/session-start` is the first startup-driving extension point.
         * Synchronous listener failure vetoes publication, while returned-promise
         * rejection is reported. Detach requested during dispatch waits until every
         * creation listener has observed the stable entry.
         * @param payload.agent - the newly registered agent with its live session and completed setup.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/created'(this: Scoped<Agent>, payload: {
            agent: Agent;
        }): void;
        /**
         * An agent left the registry; AgentLoop emits this after driver quiescence
         * and scoped-registration unwind, but before session detachment. Custom
         * registry users own their driver-ordering contract.
         * @param payload.agent - the exact agent removed from the registry.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/disposed'(this: Scoped<Agent>, payload: {
            agent: Agent;
        }): void;
        /**
         * Agent status changed (`idle` ⇄ `running`). A waking delivery enters
         * `running` synchronously after reserving cancellation; `idle` means no
         * driver remains scheduled or active.
         * @param payload.agent - the agent whose status flipped.
         * @param payload.status - the status just entered (the transition's destination).
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/status'(this: Scoped<Agent>, payload: {
            agent: Agent;
            status: AgentStatus;
        }): void;
        /**
         * One message entered the live inbox.
         * @param payload.agent - the agent whose inbox changed.
         * @param payload.message - the inserted message.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/inbox/inserted'(this: Scoped<Agent>, payload: {
            agent: Agent;
            message: UserMessage;
        }): void;
        /**
         * One message left the inbox inside its open turn. If the proposed step
         * is rejected, the claimed message ends here: it is neither discarded nor
         * re-emitted as a user/message, and the turn closes without a step.
         * @param payload.agent - the agent whose inbox changed.
         * @param payload.message - the claimed message.
         * @param payload.turn - the owning turn.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/inbox/claimed'(this: Scoped<Agent>, payload: {
            agent: Agent;
            message: UserMessage;
            turn: number;
        }): void;
        /**
         * One message was discarded from the live inbox.
         * @param payload.agent - the agent whose inbox changed.
         * @param payload.message - the discarded message.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/inbox/discarded'(this: Scoped<Agent>, payload: {
            agent: Agent;
            message: UserMessage;
        }): void;
        /**
         * The session lifecycle began, once before the first turn. Use
         * `agent.inject()` to seed model-facing context. This is a notification, not
         * a veto; disposal requested by a lifecycle owner is rechecked before the
         * driver starts.
         * @param payload.agent - the agent whose session lifecycle began.
         * @param payload.source - why the session started (fresh startup, resume, …).
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/session-start'(this: Scoped<Agent>, payload: {
            agent: Agent;
            source: SessionStartSource;
        }): void;
        /**
         * Reject a proposed step or replace the messages that enter it. Calling
         * `next()` preserves the current messages.
         * @param payload.agent - the agent proposing the step.
         * @param payload.messages - messages removed from the inbox for this step.
         * @param payload.turn - the turn that will own the step.
         * @param payload.step - the step proposed by the loop.
         * @param payload.signal - the current turn's cancellation signal.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode waterfall
         */
        'agent/pre-step'(this: Scoped<Agent>, payload: {
            agent: Agent;
            messages: UserMessage[];
            turn: number;
            step: number;
            signal: AbortSignal;
        }, next: () => Promise<PreStepDecision>): Promise<PreStepDecision>;
        /**
         * Replace the frozen call configuration. `await next()` yields the config
         * the machine would use (agent options on the first request, the logged
         * header afterwards); return a replacement to switch. Model-visible
         * content must use logged channels; this waterfall cannot mutate messages.
         * @param payload.agent - the agent making the model call.
         * @param payload.turn - the open turn number.
         * @param payload.step - the step whose request this is.
         * @param payload.signal - the current turn's explicit abort signal.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode waterfall
        */
        'agent/request'(this: Scoped<Agent>, payload: {
            agent: Agent;
            turn: number;
            step: number;
            signal: AbortSignal;
        }, next: () => Promise<LlmCallConfig>): Promise<LlmCallConfig>;
        /**
         * Handle one failed model-request attempt before the loop retries or closes
         * its step. A listener returns `{ kind: 'retry' }` without calling `next()`
         * when it owns recovery, or calls `next()` to delegate. The default
         * `undefined` leaves the failure terminal.
         * @param payload.agent - the agent whose request failed.
         * @param payload.turn - the turn containing the failed request.
         * @param payload.step - the step containing the failed request attempt.
         * @param payload.provider - the provider selected for the failed request.
         * @param payload.failure - serializable facts normalized at the final adapter boundary.
         * @param payload.retryPolicy - the policy of the adapter registration that served the failed request.
         * @param payload.signal - the turn abort signal.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode waterfall
         */
        'agent/request-error'(this: Scoped<Agent>, payload: {
            agent: Agent;
            turn: number;
            step: number;
            provider: string;
            failure: LlmFailure;
            retryPolicy: ResolvedRetryPolicy | undefined;
            signal: AbortSignal;
        }, next: () => Promise<RequestErrorAction>): Promise<RequestErrorAction>;
        /**
         * The turn is about to close: the model owes no response (no live tool
         * calls, no fresh steering). Awaited before the boundary commits — a
         * listener that objects steers (`agent.steer(...)`) and the machine
         * re-reads its inbox: fresh steering runs another step, none closes the
         * turn. Data decides, so listener order cannot change the outcome. The
         * inverse control (stop a tool loop early) is data too: a tool result
         * carrying `concludesTurn` ends the turn at its step. The conclusion
         * never short-circuits already-submitted next-step work: same-step
         * `additionalContexts` or racing steering still runs, and the turn
         * closes only when that inbox drains.
         * @param payload.agent - the agent whose turn is at its stop boundary.
         * @param payload.turn - the turn about to close.
         * @param payload.signal - the current turn's explicit abort signal.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode serial
         */
        'agent/turn-stopping'(this: Scoped<Agent>, payload: {
            agent: Agent;
            turn: number;
            signal: AbortSignal;
        }): Promise<void> | void;
        /**
         * A step or turn errored. The machine reports a failure here even when
         * the error has no in-turn position for a durable record.
         * @param payload.agent - the agent whose turn errored.
         * @param payload.turn - the turn in which the failure surfaced.
         * @param payload.step - the step at which the failure surfaced.
         * @param payload.error - the failure, verbatim.
         * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
         * @mode emit
         */
        'agent/error'(this: Scoped<Agent>, payload: {
            agent: Agent;
            turn: number;
            step: number;
            error: unknown;
        }): void;
    }
}
//# sourceMappingURL=runtime-types.d.ts.map