import { Type } from "typebox";
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
import { type TaskNotificationPayload } from "../core/task-notification.js";
import { type ToolCtxEnricher } from "../core/tools.js";
import { type TaskAccess } from "../core/task-registry.js";
import type { PermissionModeClass } from "./cross-session-envelope.js";
import { type PeerDirectory } from "./peer-directory.js";
import { SubagentRetainLedger } from "./retain-ledger.js";
import { type SubagentSteerHandle } from "./subagent.js";
import { type PeerLaneConfig, type PeerInboundChainRef, type PeerSelfRef } from "./peer-admission.js";
import { type SubagentTranscriptTier } from "../core/wiring-manifest.js";
/** Model-facing name of the background-agent continuation tool (CC 2.1.2xx `SendMessage`). */
export declare const SEND_MESSAGE_TOOL_NAME = "SendMessage";
export interface SendMessageToolOptions {
    /** Runner used to execute the resumed child run (the design/122 resume face's delegation runner). */
    runner: RunnerSelfSeat;
    /** The unified task registry the background Agent lane registered its a* handles in. */
    registry: import("../core/task-registry.js").TaskRegistry;
    /** design/122 D1 — the parent run's retain ledger (present only when `TaskSpec.retainSubagentSessions`
     *  opted in). Absent ⇒ the tool stays mounted but every call returns the honest not-retained text. */
    retain?: SubagentRetainLedger;
    /** Registry access identity (mirrors TaskOutput's closure identity — the mount fills these). */
    owner?: string;
    scope?: string;
    sessionId?: string;
    /** SESSION RETAIN LEDGER key only — never an access axis. `sessionId` above wears two hats
     *  (row-reach predicate axis AND the process-global retain-ledger map key); a caller that must
     *  strip the predicate axes (the continuation verb: access IS the identity) still needs the
     *  ledger route, because the ledger is a STORE seat consulted for an already-gated row by its
     *  own toolUseId — routing through it cannot widen reach. Consulted after ctx/options sessionId. */
    sessionRetainLedgerKey?: string;
    /** Completion-notify sink for the resumed run. The Runner mount wires the SENDING run's own
     *  notification injector here (its runtask-wrapped `injectTaskNotification`), so the completion
     *  notice lands in the sender's live injection queue at a turn boundary; a direct mount may wire a
     *  deployment-level background-notify sink instead. Absent ⇒ completion is silent. */
    notify?: (n: TaskNotificationPayload, opts?: {
        priority?: "now" | "next" | "later";
    }) => void;
    /** Whether a completion notification really reaches the sender — drives every "you will be notified"
     *  sentence on this face (description + four receipts), mirroring TaskOutput's `notificationWired`.
     *  Default = `notify !== undefined`, which is the truth on both the first-party mount and a direct
     *  mount that wires its own sink here. Pass `true` only when the deployment announces a finished
     *  agent through a channel of its own (this tool then keeps the wired wording); `false` states the
     *  degraded truth explicitly. */
    notificationWired?: boolean;
    /** RB-220 mirror of {@link import("../core/types.js").TaskSpec.oneShot} (the Runner mount fills it):
     *  this run's process exits when the turn ends, so no completion notification can ever land — checked
     *  AHEAD of {@link notificationWired}, since no amount of wiring makes a later turn exist. */
    oneShot?: boolean;
    /**
     * Whether a RETRIEVAL tool (`TaskOutput`) is mounted beside this tool on the same face. Every
     * degraded completion promise on this face (the one-shot and silent arms of the description and
     * the receipt/refusal texts) tells the model how to collect a continued agent's result; naming
     * `TaskOutput(task_id, block: true)` as an imperative is only true where that tool exists. Since
     * design/385 §1.5 this tool also mounts on the delegated-child arm WITHOUT the background door
     * TaskOutput/TaskStop keep, so the two can no longer be assumed to travel together. Three states:
     * `true` — the advice names TaskOutput plainly; `false` — this face has no retrieval tool, and the
     * advice says the result cannot be collected by this run instead of naming a tool the model cannot
     * call (an unknown-tool error on a one-shot run is the turn where the result is lost); absent — the
     * mount did not say, and the advice is hedged ("where that tool is mounted").
     */
    retrievalToolMounted?: boolean;
    /** Steer-handle sink: the revived run re-emits a FRESH handle (design/122 risk-table contract). */
    sink?: (handle: SubagentSteerHandle) => void;
    /**
     * design/147 S1a — the PARENT run's notification injector (RunInternals.parentNotify), present only
     * when THIS run is a delegated child. Enables the "main" uplink: SendMessage("main", …) lands in the
     * parent's injection queue as a `background_agent`/`event` frame at a turn boundary. Absent ⇒ the
     * honest placeholder text stays.
     */
    uplink?: (n: TaskNotificationPayload, opts?: {
        priority?: "now" | "next" | "later";
    }) => unknown;
    /**
     * The session `"main"` names for this run ({@link import("../core/runner/contracts.js").RunInternals.uplinkSessionId}
     * — the spawner's, or the reviver's, or on a sibling/host revival the tree root's). The uplink
     * receipt names it so the model knows WHICH conversation "main" is; its presence without
     * {@link uplink} marks a delegated child whose main has no live lane from here (the honest
     * not-deliverable text names the session). Absent on a top-level run.
     */
    uplinkSessionId?: string;
    /** design/147 S1a — this run's own spawn name (teammate identity) for uplink attribution. */
    senderName?: string;
    /** design/147 S1c — the deployment's durable roster, consulted after the live registry misses. */
    roster?: import("./roster-store.js").RosterStore;
    /** design/147 S3a — the PARENT run's retain ledger (RunInternals.parentRetainLedger):
     *  the sibling leg's retain entries live there. Consulted AFTER the own-run and session ledgers. */
    siblingRetain?: SubagentRetainLedger;
    /** RB-390 — the SPAWNING run's taskId when THIS run is a delegated child (RunInternals.parentTaskId,
     *  mount-filled from the trusted internals chain — never a model argument). Historically the ONLY
     *  way this fact could reach a first-party mount: the adapter handed a `defineTool` product's body
     *  just `{toolCallId, signal}`, so `ctx.parentTaskId` never arrived and the design/147 S3a sibling
     *  legs (byName parent-view retry, tier-3 parent view) were dead on every auto-mounted child run —
     *  teammates could not reach each other by name ("no agent matches" while the parent's view
     *  resolved fine). RB-409 opened the ctx route as well ({@link enrichCtx}), and the Runner mount
     *  fills BOTH from the same internals chain; this seat remains the fallback (and the only route for
     *  a host that wires the tool itself). A `ctx.parentTaskId` wins when present. SendMessage ONLY —
     *  the TaskStop/TaskOutput mounts deliberately have no such seat (no widening of the kill/read
     *  surface). */
    parentTaskId?: string;
    /** RB-390 — companion session axis of {@link parentTaskId} (RunInternals.parentSessionId): a
     *  session-scoped sibling registers with owner = the parent's sessionId, which the parent's
     *  taskId alone cannot satisfy when the two differ (same rationale as ToolExecuteContext.parentSessionId). */
    parentSessionId?: string;
    /** the process-level background-child observer (RunnerDeps.onBackgroundChildEvent) — the
     *  mount fills this so a SendMessage resume re-emits the spawn→tick→terminal family (fleet row
     *  revival). Rides the OPTS closure like notify; RB-409's {@link enrichCtx} feeds the ctx twin. */
    onBackgroundChildEvent?: (event: import("../core/types.js").BackgroundChildEvent) => void;
    /** design/151 §7 S3c — the durable execution-row ledger ({@link RunnerDeps.backgroundAgentStore}):
     *  the tier-3 resolution rung (exact a* handle / roster name → durable row) and the claim-CAS
     *  target. Tier-3 activates only when THIS + {@link mailbox} + {@link reviveSpawn} are all
     *  present; anything less keeps the pre-S3c honest refusal texts byte for byte. */
    agentStore?: import("../core/background-agent-store.js").BackgroundAgentStore;
    /** design/151 §7.1 — the durable mailbox ({@link RunnerDeps.mailboxStore}): a message is parked
     *  here ONLY on the claim-winner path (append after the row CAS is won), consumed via
     *  claim/lease + ack at spawn success — never a destructive drain. */
    mailbox?: import("../core/mailbox-store.js").MailboxStore;
    /** design/151 §6.3 案 B — the trusted revival spawner: prepare-task wraps the MOUNTED delegation
     *  tool's execute (object identity via the `agentListing` marker — never wire-name lookup, so a
     *  caller's same-named shadow tool can never receive the trusted claim) with a fresh toolCallId
     *  and `ctx.reviveClaim`. The revival is thereby the FULL spawn chain (observer frames, durable
     *  lane re-arm, notify, park semantics) — nothing re-implemented here. */
    reviveSpawn?: (req: {
        row: import("../core/background-agent-store.js").BackgroundAgentRecord;
        rev: number;
        prompt: string;
        peerSeed?: {
            hopChain: string[];
        };
    }) => Promise<{
        isError?: boolean;
        content: string;
        details?: unknown;
    }>;
    /** RB-473 batch 2b — bounded disclosure for a deployment sink throwing inside the resume face's
     *  isolation scope (threaded into {@link createSubagentResume}); absent = counted only. */
    onNotifyError?: (failure: import("../core/safe-notify.js").SafeNotifyFailure) => void;
    /**
     * RB-409 — the mount's per-call ctx builder, forwarded to {@link defineTool} (see
     * {@link ToolCtxEnricher}). This tool is a `defineTool` PRODUCT, so before this seat existed its
     * body could only ever see `{toolCallId, signal}` and every `ctx.*` read below fell to its `opts`
     * fallback — the ctx-first arms were structurally dead on the first-party mount. The Runner mount
     * now passes its own trusted ctx builder here (the SAME one it applies to `spec.tools` tools), so
     * the two sources agree by construction rather than by a copied table. Absent ⇒ unchanged
     * behavior: the opts closure alone supplies the identity axes.
     */
    enrichCtx?: ToolCtxEnricher;
    /** design/176 — caller tuning for the always-on peer-message admission gate (per-field
     *  range-validated; a value outside its range — or one that is not a finite number — falls back to
     *  that field's default and is ANNOUNCED once per process through {@link onNotice}; there is no off
     *  switch). The Runner mount threads {@link import("../core/types.js").RunnerDeps.peerLane}
     *  here. Read per call — a changed value governs the next message. */
    lane?: Partial<PeerLaneConfig>;
    /** #551 — the deployment's structured notice sink, used by this face for ONE fact: a
     *  {@link lane} field the resolver could not use falls back to its default and announces
     *  `config.peer_admission_out_of_range` through here. The Runner mount threads
     *  {@link import("../core/types.js").RunnerDeps.onNotice}; a direct mount that leaves it absent
     *  still gets the line on `console.warn` (the shared delivery throat's unwired arm). */
    onNotice?: (notice: import("../core/types.js").EngineNotice) => void;
    /** design/176 — the SENDING run's peer-identity carrier (trusted internals chain; ctx twin
     *  {@link import("../core/types.js").ToolExecuteContext.peerSelfRef} wins when present). Supplies
     *  the sender's bucket key and the hop token appended to every outbound chain. A direct mount
     *  without it degrades to axis synthesis from `sessionId`/`owner`; with no axes at all the sender
     *  is identity-less (rate/dedup skipped — hop and queue bounds still apply). */
    peerSelf?: PeerSelfRef;
    /** design/176 — the SENDING run's inbound peer-chain ref (ctx twin wins): the chain of the most
     *  recently consumed peer message, which this run's outbound sends extend. */
    peerInbound?: PeerInboundChainRef;
    /** design/176 — the RECIPIENT identity of the {@link uplink} callback, PAIR-MINTED at the same
     *  trust point that bound the callback (spawn internals assembly / the resume face's
     *  currentParentNotify replacement): `uplink` is an opaque void callback and the parent axes
     *  deliberately keep the ORIGINAL spawner on the revive arm while the callback points at the
     *  WAKER — so the uplink's admission identity can only travel WITH the binding, never be derived.
     *  A direct mount that wires `uplink` without this leaves L1 ungated (recorded honest boundary:
     *  the library does not fabricate an identity on the host's behalf). */
    uplinkRecipient?: PeerSelfRef;
    /**
     * Subagent transcript persistence — the "declared durability contradicted by reality" disclosure
     * sink: called (at most once per (scope, handle) per process, {@link announceTranscriptIntegrityGapOnce})
     * when a durable row with a bound sessionId meets a session store that attests `not_found`. The
     * first-party mount wires an EngineNotice (`delegation.transcript_integrity`); absent ⇒ the
     * per-call honest refusal is the only loudness (unchanged behavior).
     */
    onTranscriptIntegrityGap?: (handle: string, scope: string | undefined) => void;
    /**
     * design/385 §2 — the peer-session DIRECTORY ({@link import("../core/types.js").RunnerDeps.peerDirectory}):
     * opens the cross-session lane's two rungs on this face — the explicit `session.<id>` address arm
     * (ranked beside the precise a* id) and the LAST name rung (`name [ref]` over the directory's full
     * set, after every agent rung missed). Needs {@link mailbox} beside it AND that store's
     * `crossProcessSafe: true` declaration: with the directory wired but either missing, the lane stays
     * closed and every peer-addressed send refuses with the named reason (never a silent fall-through to
     * "no agent matches"). Absent ⇒ byte-identical pre-385 behavior.
     */
    peerDirectory?: PeerDirectory;
    /**
     * design/385 — THIS session's own identity on the cross-session lane: its session id (the sender's
     * `from-session` / reply address, and the self-target guard), the scope its directory rows live in,
     * its display name (the `from-name` attestation), and the live fold of its own permission-mode class
     * ({@link import("./cross-session-judge.js").foldPermissionModeClass} over the wiring manifest's
     * `ask.effective`) — read at SEND time, attested on the parked record's typed `peerMeta.fromMode`.
     * The Runner mount fills it; a direct mount without it sends with no session attestation (the
     * recipient then judges it as "no class asserted").
     */
    peerSelfSession?: {
        sessionId: string;
        scope?: string;
        name?: string;
        modeClass?: () => PermissionModeClass | "unknown";
    };
    /** design/385 §5.1 — is `ListAgents` mounted beside this tool? Drives the "list them with ListAgents"
     *  phrase (a face never names a tool the roster does not carry — an `excludeTools` may drop one of the
     *  pair). Absent = unknown ⇒ the phrase is hedged. */
    peerListingMounted?: boolean;
}
/** RB-382 — max chars of the `summary` arg (the short recap label, distinct from `message`'s much
 *  larger {@link UPLINK_RESULT_MAX}) before ITS OWN truncation. Exported for direct unit-testing only
 *  (module-internal path, same convention as MONITOR_SPILL_CAP_BYTES — not part of the src/index.ts
 *  public surface): the tool's OWN schema already declares `summary: Type.String({ maxLength: 200 })`,
 *  so a call arriving through the normal `AgentTool.execute` gate (`defineTool`'s `Value.Check`, see
 *  core/tools.ts) can never carry a summary longer than this — the clip below is a defense-in-depth
 *  belt for any caller that reaches this function body without going through that gate, not a live
 *  truncation a model-facing call can trigger today. */
export declare const SEND_MESSAGE_SUMMARY_MAX = 200;
/** RB-382 — clip a trimmed, non-empty `summary` to {@link SEND_MESSAGE_SUMMARY_MAX} chars, appending
 *  the SAME "[… truncated: N chars total]" marker style every `message` truncation site in this file
 *  already uses (the four delivery legs each silently did `slice(0, 200)` with no marker at all — a
 *  double standard against `message`'s disclosed truncation in the same file, at least on paper — see
 *  this constant's own doc comment for why the schema gate makes the branch unreachable in practice
 *  today). The cap itself is unchanged; only the missing disclosure is added. RB-419 then folded those
 *  four re-derivations into a SINGLE call site, immediately after the gate that makes the argument
 *  non-empty — so this helper now has exactly one caller in the tool body. */
export declare function clipSendMessageSummary(raw: string): string;
/**
 * design/276 (direct-mount guidance): the engine's first-party auto-mount declares this tool's safety
 * axes itself (`effect:"write"`, explicit `egress:false`). A host mounting this factory's product via
 * `spec.tools` suppresses that auto-mount, so its own ToolSpec declaration is what the safety scan
 * reads — declare `effect:"write"` there (a message is repeat-unsafe: replay = second delivery /
 * second revive). The auto-mode peer-referral tighten keys on the WIRE NAME and applies to a direct
 * mount all the same.
 */
/**
 * The continuation promise's REACH — how far "continue a finished agent" goes on a SendMessage mount — by the
 * deployment's subagent transcript tier: the ONE derivation (`resolveSubagentTranscriptTier`, the wiring
 * manifest's `subagentTranscripts` cell) over the mount's own seats. Without all three tier-3 seats (row
 * store, mailbox, reviver) there is no durable revival at all — session retention is the only lane (`none`).
 * With them, the session store the revival runs through (`runner.sessions`) decides: `full` keeps the
 * conversation across a restart, `rows` keeps the record but not the conversation (a process-local
 * transcript store), so only `full` may say "across restarts". Exported so every face that describes the
 * same reach (the ListAgents mount beside this tool) reads the same answer from the same seats.
 */
export declare function sendMessageContinuationTier(seats: {
    agentStore?: unknown;
    mailbox?: unknown;
    reviveSpawn?: unknown;
    runner: Pick<RunnerSelfSeat, "sessions">;
}): SubagentTranscriptTier;
export declare function createSendMessageTool(opts: SendMessageToolOptions): import("../internal/harness.js").AgentTool<Type.TObject<{
    to: Type.TString;
    message: Type.TString;
    summary: Type.TOptional<Type.TString>;
}>, unknown>;
/** The receipt {@link createAgentContinuationVerb} resolves with — the SendMessage tool's own
 *  receipt family, flattened to one text (same content, same `details.error` code vocabulary). */
export interface AgentContinuationReceipt {
    content: string;
    details?: unknown;
    isError?: boolean;
}
/**
 * Subagent transcript persistence — the OPERATOR continuation verb: the SendMessage delivery ladder
 * as a reusable, non-model face for a deployment's own continuation endpoint. SINGLE-SOURCE by
 * construction: the verb routes THROUGH `createSendMessageTool`'s product (status arms, admission
 * gates, preflight order, claim CAS + rollback, parked/running refusals and the whole refusal-code
 * family are the tool's own, byte-shared — never a twin implementation). The one fork is the
 * `userInitiated` mode bit ({@link OPERATOR_CONTINUATION_CTX}): `true` waives BOTH user-stop gates —
 * the durable row's `stoppedBy === "user"` arm and the live registry's stop-attribution arm — so an
 * explicit human "continue it" overrides an earlier human "stop it" (the winning claim's
 * clear-terminal-payload erases the durable mark; the model-facing tool NEVER softens).
 *
 * Authorization is three-layered and this verb owns only the first: ① the same
 * `canAccessAgentRecord` row predicate the tool runs, against the caller's `access` argument and
 * NOTHING ELSE (an out-of-scope handle reads not_found — non-leaking); ② "this really is an explicit
 * human instruction" is the DEPLOYMENT's obligation —
 * the same trust seat that stamps `stopSource:"user"` on the stop side (a server exposes this only
 * through a verified interactive-user principal endpoint, never to unattended machine clients); ③ the model
 * tool face has no such parameter (the bit travels on a module-private symbol — zero forgeable
 * surface from arguments).
 *
 * ACCESS TOTALITY: the `access` argument is the WHOLE row-reach identity of the call — a partially
 * specified one leaves the axes it omits UNDECLARED (default-deny), never backfilled from the mount.
 * See the identity-strip note in the body for why that has to be spelled at the options seat too.
 *
 * Store-conditional like every continuation face: with no durable stores wired the live-gate waiver
 * still works for same-process handles, and the durable leg refuses honestly.
 */
export declare function createAgentContinuationVerb(opts: SendMessageToolOptions): (handle: string, content: string, access: TaskAccess, o?: {
    userInitiated?: true;
    summary?: string;
}) => Promise<AgentContinuationReceipt>;
