/**
 * hosting/standingAgent — an agent that stays up and remembers.
 *
 *   await standingAgent({
 *     agent,
 *     sessions: memorySessions(),
 *     host: nodeHost({ port: 8080 }),
 *     durability: 'sync',          // optional; 'exit' is the default
 *   });
 *
 * One request at a time it does four things: wake and hydrate the session,
 * continue that session or start a fresh one, persist what the run leaves
 * behind, then reply. Everything else is somebody else's job — the host carries
 * bytes, the store keeps them, the agent thinks.
 *
 * ── A run has three ends, and this composer honours all three ────────────────
 * It answered, it asked a person something, or it failed. An answer completes
 * the reply and stores a conversation. A QUESTION stores the paused run as
 * `'flowchart-v1'` and leaves through `reply.awaiting(...)` — its own terminal,
 * never `fail`, because a pause is unfinished work and reporting it as a failure
 * tells every dashboard downstream something untrue. A later request for that
 * session carrying `decision` continues the run from exactly where it stopped.
 *
 * ── "Start a fresh one" is an answer it must EARN ───────────────────────────
 * A session with nothing stored is answered fresh, and that is right. A session
 * whose stored conversation cannot be READ is not: an unreadable stored
 * conversation and an absent one are different facts, and only one of them is
 * safe to answer with a fresh start. So an `UnreadableEnvelopeError` out of the
 * store fails THIS REQUEST, naming the session, and the fresh-start path is
 * never reached. The alternative is a reply that looks perfect to everyone
 * involved while a user's conversation quietly stops existing.
 *
 * ── Resuming a CONVERSATION is a REPLAY, and that has a cost ─────────────────
 * A stored conversation is restored through `agent.run({ message, continueFrom })`
 * — the public conversation door since 9.2.0. This composer used to assemble the
 * continuation by hand (append the turn, rewrite `originalInput`, hand the result
 * to `resumeOnError`); that hand-assembly IS the door now, so a server and a
 * script continue a conversation the same way and the identity travels with it.
 * The caveat below is stated here in the words the Agent states it in, because a
 * composition that hides the caveat of the thing it composes is worse than no
 * composition at all:
 *
 *   > **Tool re-execution / idempotency**: tool side effects from the FAILED
 *   > iteration are not in the checkpoint. The model re-decides from the
 *   > restored history and may re-issue those tool calls — they WILL execute
 *   > again (there is no built-in toolCallId dedup). Mutating tools (payments,
 *   > emails, DB writes) must be idempotent — key on stable call content, not
 *   > `ctx.toolCallId` (a re-issued call gets a new id).
 *
 * `durability` is the dial that bounds how much of that a crash can cost you.
 * Resuming a PAUSED run is different in kind: it is not a replay at all — the
 * engine continues from its own checkpoint, and no earlier tool call re-runs.
 *
 * ── Why one run at a time, and where that bound actually is ─────────────────
 * An Agent instance holds per-run state on itself. Two runs overlapping on ONE
 * instance do not crash — which is precisely the danger. They both finish, and
 * the state the composer reads afterwards belongs to whichever started last, so
 * one session's envelope can end up holding another session's conversation.
 * Nothing in the recording would say so. **Runs on one instance are therefore
 * serialized, and that is a correctness requirement rather than a tuning
 * choice.**
 *
 * What CHANGED in 9.10.0 is not that rule but its scope. `{ agent }` hands this
 * composer one instance to share, so the serialization is global — the shape
 * every earlier release had, unchanged to the byte. `{ agentFactory }` hands it
 * a way to MAKE instances, so each session gets its own and the same rule binds
 * per session: sessions run in parallel, each session's turns queue behind that
 * session's own instance.
 *
 *   standingAgent({ agent })          → one instance,  global queue
 *   standingAgent({ agentFactory })   → one per session, a queue each
 *
 * Everything else is identical between the two: the same stores, the same
 * durability modes, the same pause/resume contract, the same refusals. The
 * session store is keyed per session already, which is why the pool can evict a
 * session's instance without the person on the other end noticing — the
 * CONVERSATION was never in the instance.
 *
 * `onConcurrentInvoke` is the separate question of what to do when a second
 * turn of the SAME conversation arrives while the first is running: refuse it
 * (default) or queue it. It means the same thing in both shapes. A request for
 * a DIFFERENT session is never refused — there is nothing wrong with it; in the
 * shared shape it waits its turn, and in the pooled shape it does not have to.
 *
 * ── The pool, in one paragraph ──────────────────────────────────────────────
 * One instance per ACTIVE session, built on first sight by the factory, bounded
 * by `maxActiveSessions` (default 100) and evicted least-recently-used. An
 * evicted session's agent has its tool sessions closed with reason `'evicted'`
 * — the 9.7.0 vocabulary, not a new one — and is then shut down; its
 * conversation stays in the store, so its next request re-hydrates onto a fresh
 * instance and nothing was lost. A session that is RUNNING is never evicted:
 * the bound is on retained idle instances, and a cache policy does not get to
 * end somebody's turn. Requests with NO session share one fallback instance,
 * because there is no conversation to isolate and an instance per anonymous
 * request would be an instance per request.
 *
 * Pattern: Composition root. It owns wiring and ordering; it invents no
 * mechanism of its own.
 */
import type { HostHandle, StandingAgentHandle, StandingAgentOptions } from './types.js';
/**
 * Serve an agent, with per-session conversation memory, on any
 * {@link AgentHost}.
 *
 * Resolves once the host is live. Closing the returned handle closes the host,
 * detaches the listeners this composer added, and removes its durability
 * wiring.
 *
 * Two shapes, one composer — see the file header for the full comparison:
 *
 *  - `{ agent }` — one instance for every session, runs serialized globally.
 *    Correct, and unchanged from every earlier release.
 *  - `{ agentFactory }` — one instance per active session, sessions in
 *    PARALLEL, each session's turns serialized on its own instance.
 *
 * @example  One agent, every session
 *   const handle = await standingAgent({
 *     agent,
 *     sessions: memorySessions(),
 *     host: nodeHost({ port: 0 }),
 *     onConcurrentInvoke: 'enqueue',
 *     durability: 'sync',
 *   });
 *   process.on('SIGTERM', () => void handle.close());
 *
 * @example  One agent per session — they answer at the same time
 *   const handle = await standingAgent({
 *     agentFactory: () => Agent.create({ provider, model }).system('…').build(),
 *     sessions: sqliteSessions({ file: './sessions.db' }),
 *     host: nodeHost({ port: 8080 }),
 *     maxActiveSessions: 200,
 *   });
 */
export declare function standingAgent<TH extends HostHandle>(options: StandingAgentOptions<TH>): Promise<TH & StandingAgentHandle>;
