import type { CachePolicy, ChatMessage, ChatToolChoice, ChatToolDefinition, ChatToolHandlers } from '@genesislcap/foundation-ai';
import type { AgentConfig, AgentLifecycleContext, AgentPersistenceContext, ChatInputDuringExecutionMode, ManualSelectionConfig, SystemPromptContext, UnresolvedToolContext } from './config';
/**
 * Context passed to per-turn resolvers on a stateful agent — the standard
 * {@link SystemPromptContext} plus the live `state` value. Used by
 * `systemPrompt`, `displayName`, and the function form of `toolDefinitions`.
 *
 * Exported so consumers can lift resolvers into separate files without
 * re-deriving the shape.
 *
 * @beta
 */
export type StatefulAgentContext<S> = SystemPromptContext & {
    state: S;
};
/**
 * Context passed to a stateful agent's `resumable` predicate (GENC-1351 §5.9) —
 * the standard {@link AgentPersistenceContext} but with `state` as the **live**
 * state bag `S` (not the serialized image), so a machine agent can gate on its
 * current step directly.
 *
 * @beta
 */
export type StatefulAgentPersistenceContext<S> = Omit<AgentPersistenceContext, 'state'> & {
    state: S;
};
/**
 * Init options for {@link defineStatefulAgent}. Generic over the state shape `S`
 * the agent owns (a state machine, an observable controller, anything).
 *
 * The helper threads `state` through `systemPrompt`, `toolDefinitions`, and the
 * `toolHandlers` factory so consumer code never has to reach for a closure or
 * a module-level mutable.
 *
 * @beta
 */
export interface StatefulAgentInit<S> {
    /** Display name — must be unique within the agents array. */
    name: string;
    /** Plain-language description used by the classifier. Required: stateful agents are always specialists. */
    description: string;
    /**
     * Hide this agent from the classifier — only reachable via manual pinning.
     * Stateful agents are always specialists; they cannot be the fallback (a
     * fallback is a leaf invoked when no specialist matches, with no flow to
     * own state for).
     */
    excludeFromClassifier?: boolean;
    /** Static primer history prepended to every call (not visible to the user). */
    primerHistory?: ChatMessage[];
    /** Sub-agents available to this agent's tool handlers via `requestSubAgent`. */
    subAgents?: AgentConfig[];
    /** Opt this agent in to manual picker selection. */
    manualSelection?: ManualSelectionConfig;
    /** How the main chat input behaves while this agent is executing. */
    chatInputDuringExecution?: ChatInputDuringExecutionMode;
    /**
     * Construct the agent-scoped state. Called by the framework when this agent
     * becomes active (`onActivate`). Awaited before the agent's first turn runs.
     *
     * On a persisted-session restore, `ctx.restored` carries this agent's previous
     * `serialize` output — rebuild from it (e.g. via `restoreMachine`), or start
     * fresh when it is `undefined`.
     */
    init: (ctx: AgentLifecycleContext) => S | Promise<S>;
    /**
     * Tear down the agent-scoped state. Called when the agent is being replaced.
     * Awaited before the incoming agent's `init` runs.
     */
    dispose?: (ctx: AgentLifecycleContext & {
        state: S;
    }) => void | Promise<void>;
    /**
     * System prompt composed from current state. Resolved each tool-loop
     * iteration. Use this to feed the LLM whatever the current state implies
     * (e.g. a state machine's `meta.systemPrompt` plus captured context).
     */
    systemPrompt?: (ctx: StatefulAgentContext<S>) => string | Promise<string>;
    /**
     * Per-turn display label, e.g. "Guided Booking (Counterparties)". Resolved
     * each tool-loop iteration and stamped onto outgoing messages and the
     * debug-log timeline — display only. The agent's `name` stays as the
     * canonical identity used for routing/history filtering.
     */
    displayName?: (ctx: StatefulAgentContext<S>) => string | Promise<string>;
    /**
     * Tool definitions the LLM sees. Either a static array (resolved once) or a
     * function resolved each tool-loop iteration. The function form is how a
     * machine-driven agent narrows the surface per state.
     *
     * **Constraint:** the resolved handlers (returned from {@link StatefulAgentInit.toolHandlers})
     * must not include fold facades. Folds are an LLM-driven UX optimisation
     * that competes with the machine for control of the tool view; one of them
     * has to be in charge. Helper throws at init time if a fold-tagged handler
     * is detected.
     */
    toolDefinitions?: ChatToolDefinition[] | ((ctx: StatefulAgentContext<S>) => ChatToolDefinition[] | Promise<ChatToolDefinition[]>);
    /**
     * Factory returning the handler map for the **current state**. Called each
     * tool-loop iteration with the live `state` value, so the handler set the
     * driver dispatches against matches what `toolDefinitions` exposes to the
     * LLM that turn. Return only the handlers valid right now — no need to
     * advertise every handler the agent might ever expose, and no defensive
     * `if (!machine.matches(...))` guards inside each handler.
     *
     * Pair with the function form of `toolDefinitions` so the visible tools and
     * the dispatchable handlers stay in lockstep.
     *
     * **Constraint:** resolved handlers must not include fold facades. Folds and
     * state-machine-driven tool filtering both try to control the LLM's tool
     * view — pick one. Helper samples once on activation (init state) and
     * throws if a fold-tagged handler is detected; subsequent resolves also
     * validate, so misuse on a non-init state surfaces when that state is
     * reached.
     */
    toolHandlers?: (state: S) => ChatToolHandlers | Promise<ChatToolHandlers>;
    /**
     * Which registered AI provider this agent uses, by name. Either a static
     * string or a function resolved each tool-loop iteration with the current
     * `state` — pick the function form to vary provider per machine state
     * (e.g. swap to a heavier model only for the planning step).
     *
     * Omit to use the registry's default provider. Unknown names hard-error.
     */
    provider?: string | ((ctx: StatefulAgentContext<S>) => string | Promise<string>);
    /**
     * Sampling temperature, normalized to `0`–`1`. Either a static number or a
     * function resolved each tool-loop iteration with the current `state` — pick
     * the function form to vary it per machine state (e.g. low for a precise
     * extraction step, higher for free-form drafting). Omit for the default.
     */
    temperature?: number | ((ctx: StatefulAgentContext<S>) => number | Promise<number>);
    /**
     * Tool-call mode. Either a static `ChatToolChoice` or a function
     * resolved each tool-loop iteration with the current `state` — pick the
     * function form to force a specific tool in one state (e.g. a classifier in
     * intake) and leave `'auto'` in states where multi-step work happens. Omit
     * for the default.
     */
    toolChoice?: ChatToolChoice | ((ctx: StatefulAgentContext<S>) => ChatToolChoice | Promise<ChatToolChoice>);
    /**
     * Prompt-cache policy. Either a static `CachePolicy` or a function resolved each tool-loop
     * iteration with the current `state` — pick the function form to vary it per machine state
     * (e.g. `'history'` in a long generating phase, `'default'` in short low-touch ones). Omit to
     * request no caching.
     */
    cachePolicy?: CachePolicy | ((ctx: StatefulAgentContext<S>) => CachePolicy | Promise<CachePolicy>);
    /**
     * Volatile per-turn tail context (current file/spec, diagnostics, live state). Either a static
     * string or a function resolved each tool-loop iteration with the current `state`. Provide raw
     * content; the framework frames it. Omit, or return an empty string, for none.
     */
    tailContext?: string | ((ctx: StatefulAgentContext<S>) => string | Promise<string>);
    /**
     * Hook consulted when the model calls a tool that isn't dispatchable in the
     * current state — a *stale* tool (valid in an earlier state of this agent) or
     * an *unknown* one. Receives the current `state` alongside the attempted tool
     * name and the currently dispatchable tools, so a machine-driven agent can
     * return a step-aware redirect (e.g. "that belongs to a later step — finish
     * this one first"). Return `undefined` to keep the framework default; a
     * pre-init call also degrades to the default rather than throwing.
     * See {@link UnresolvedToolContext}.
     */
    onUnresolvedTool?: (ctx: UnresolvedToolContext & {
        state: S;
    }) => string | undefined | Promise<string | undefined>;
    /**
     * Optional getter for the debug-log snapshot. Defaults to auto-snapshotting
     * any property on `state` that looks like a foundation-state-machine
     * instance (has `state`, `context`, and `complete` fields). Override when
     * the default doesn't capture what you need — e.g. multiple machines, or
     * non-machine state worth recording.
     *
     * Return value must be JSON-serializable.
     */
    getDebugSnapshot?: (state: S) => unknown;
    /**
     * Lossless serializer for session persistence — infra-agnostic. Return any
     * JSON/structured-clone-safe image of `state`.
     *   • Machine agents (`{ machine }`): omit — the default snapshots every
     *     machine-shaped property via `getPersistedSnapshot()`.
     *   • Plain-data agents (e.g. `{ plan, cursor }`): omit too — the default
     *     returns plain state as-is. Provide one only when the state holds
     *     something the default can't capture.
     * Distinct from `getDebugSnapshot` (which may be lossy by design). Pair with
     * `init` reading `ctx.restored` to rebuild.
     */
    serialize?: (state: S) => unknown;
    /**
     * Whether the agent's current state is resumable — worth persisting so the
     * session restores mid-flow (GENC-1351 §5.9). Receives the **live** state bag
     * `S` (like the other per-turn resolvers), so a machine agent gates on its step
     * directly: `resumable: ({ state }) => state.machine.state !== 'confirm'`.
     * Return `false` for a point that shouldn't resume — the session isn't persisted,
     * and on return the assistant shows {@link StatefulAgentInit.notResumableMessage}
     * (or a default) and pre-fills the composer with the prompt that started the flow.
     * Only consulted with persistence enabled; a thrown error is treated as `true`
     * (fail-safe — never drop a resumable chat on a predicate bug).
     */
    resumable?: (ctx: StatefulAgentPersistenceContext<S>) => boolean | Promise<boolean>;
    /**
     * Message shown on return when {@link StatefulAgentInit.resumable} returned
     * `false`. Falls back to a built-in default when omitted.
     */
    notResumableMessage?: string;
}
/**
 * Restore a foundation-state-machine instance from a snapshot produced by the
 * default serializer (or `machine.getPersistedSnapshot()`). Call inside a
 * stateful agent's `init` to resume the machine in its exact prior place:
 *
 * ```ts
 * init: ({ restored }) => {
 *   const machine = new MyMachine();
 *   restoreMachine(machine, restored); // resume, or no-op on a fresh start
 *   return { machine };
 * }
 * ```
 *
 * No-ops when there is nothing to restore (a fresh session), leaving the
 * freshly-constructed machine in its initial state.
 *
 * @param machine - the machine to restore (already constructed/started).
 * @param restored - the agent's serialized image (`ctx.restored` in `init`).
 * @param key - the property the machine occupies in the snapshot; defaults to
 *   `'machine'` to match the conventional `{ machine }` state bag.
 * @beta
 */
export declare function restoreMachine(machine: {
    stop: () => void;
    start: (options?: {
        state?: unknown;
    }) => void;
}, restored: unknown, key?: string): void;
/**
 * Build an `AgentConfig` whose `systemPrompt`, `toolDefinitions`, and tool
 * handlers all close over a long-lived state object created on activation.
 *
 * The framework wires the lifecycle: `init` on `onActivate`, `dispose` on
 * `onDeactivate`. State is held inside the helper's closure — never exposed on
 * the resulting `AgentConfig` — so the redux serializer doesn't see it.
 *
 * @example
 * ```ts
 * const guidedBooking = defineStatefulAgent<{ machine: GuidedBookingMachine }>({
 *   name: 'Guided Booking',
 *   description: 'Books a trade via a guided wizard.',
 *   excludeFromClassifier: true,
 *   manualSelection: { enabled: true, hint: 'Step-by-step trade booking' },
 *   init: () => ({ machine: new GuidedBookingMachine() }),
 *   dispose: ({ state }) => state.machine.stop(),
 *   systemPrompt: ({ state }) => composeFromMachine(state.machine),
 *   toolDefinitions: ({ state }) => toolsForState(state.machine.state),
 *   toolHandlers: ({ machine }) => ({ ... }),
 * });
 * ```
 *
 * @beta
 */
export declare function defineStatefulAgent<S>(opts: StatefulAgentInit<S>): AgentConfig;
//# sourceMappingURL=define-stateful-agent.d.ts.map