import type { FetchFileResult } from "#channel/adapter.js";
import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js";
import type { TypedReceiveTarget } from "#channel/receive-target.js";
import type { SessionAuthContext } from "#channel/types.js";
import type { HandleMessageStreamEvent } from "#protocol/message.js";
import type { SessionContext } from "#public/definitions/callback-context.js";
import type { RouteDefinition, SendFn } from "#channel/routes.js";
import type { Session, SessionHandle } from "#channel/session.js";
declare const CHANNEL_METADATA_TYPE: unique symbol;
export type { Session, SessionHandle } from "#channel/session.js";
export { GET, POST, PUT, PATCH, DELETE, WS } from "#channel/routes.js";
export type { HttpRouteDefinition, RouteDefinition, RouteHandlerArgs, SendFn, SendOptions, SendPayload, GetSessionFn, WebSocketMessage, WebSocketPeer, WebSocketRouteDefinition, WebSocketRouteHandler, WebSocketRouteHooks, WebSocketUpgradeRequest, WebSocketUpgradeResult, } from "#channel/routes.js";
type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, {
    type: T;
}> extends {
    data: infer D;
} ? D : undefined;
/**
 * Session operations on the `channel` argument of every channel event handler.
 */
export interface ChannelSessionOps {
    readonly continuationToken: string;
    setContinuationToken(token: string): void;
}
/**
 * Channel context passed to event handlers: `TCtx` intersected with
 * {@link ChannelSessionOps}.
 */
export type ChannelContext<TCtx> = TCtx & ChannelSessionOps;
type ChannelEventHandler<T extends HandleMessageStreamEvent["type"], TCtx> = (data: EventData<T>, channel: ChannelContext<TCtx>, ctx: SessionContext) => void | Promise<void>;
type ChannelSessionFailedHandler<TCtx> = (data: EventData<"session.failed">, channel: ChannelContext<TCtx>) => void | Promise<void>;
/**
 * Optional handlers keyed by session lifecycle event name. Each handler receives
 * the event `data`, the {@link ChannelContext}, and a {@link SessionContext}
 * `ctx`. The `session.failed` handler is the exception: it receives only `data`
 * and the channel context, with no `ctx`.
 */
export interface ChannelEvents<TCtx = void> {
    readonly "turn.started"?: ChannelEventHandler<"turn.started", TCtx>;
    readonly "actions.requested"?: ChannelEventHandler<"actions.requested", TCtx>;
    readonly "action.result"?: ChannelEventHandler<"action.result", TCtx>;
    readonly "message.completed"?: ChannelEventHandler<"message.completed", TCtx>;
    readonly "message.appended"?: ChannelEventHandler<"message.appended", TCtx>;
    readonly "input.requested"?: ChannelEventHandler<"input.requested", TCtx>;
    readonly "turn.failed"?: ChannelEventHandler<"turn.failed", TCtx>;
    readonly "turn.completed"?: ChannelEventHandler<"turn.completed", TCtx>;
    readonly "session.failed"?: ChannelSessionFailedHandler<TCtx>;
    readonly "session.completed"?: ChannelEventHandler<"session.completed", TCtx>;
    readonly "session.waiting"?: ChannelEventHandler<"session.waiting", TCtx>;
    readonly "authorization.required"?: ChannelEventHandler<"authorization.required", TCtx>;
    readonly "authorization.completed"?: ChannelEventHandler<"authorization.completed", TCtx>;
}
/**
 * Input passed to a channel's `receive` callback when another channel or
 * schedule proactively routes a message to it.
 */
export interface ReceiveInput<TReceiveTarget = Record<string, unknown>> {
    readonly message: string;
    readonly target: Readonly<TReceiveTarget>;
    readonly auth: SessionAuthContext | null;
}
/**
 * The object passed to {@link defineChannel}. `routes` is required; `state`
 * seeds durable adapter state, `context` builds the per-step `channel` argument
 * for `events` and `deliver`, `events` handle session lifecycle, `receive`
 * accepts cross-channel handoffs, `fetchFile` stages remote file URLs, and
 * `metadata` projects observability data.
 *
 * Generics: `TState` (adapter state), `TCtx` (context factory return type),
 * `TReceiveTarget` (cross-channel target shape), `TMetadata` (instrumentation
 * projection).
 */
export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
    readonly state?: TState;
    /**
     * Builds the per-step channel context handed to `events` and `deliver`.
     * Receives the live {@link SessionHandle}, so a factory can close over it to
     * register late-bound callbacks. Eve writes state mutations made inside the
     * returned context back through `adapter.state`.
     *
     * Return the channel-owned context (thread handles, API clients, etc.). The
     * framework passes it as the `channel` argument to event handlers (with
     * {@link ChannelSessionOps} injected) and passes {@link SessionContext} as a
     * separate `ctx` argument.
     */
    context?(state: NonNullable<TState>, session: SessionHandle): TCtx;
    readonly routes: readonly RouteDefinition<TState>[];
    receive?(input: ReceiveInput<TReceiveTarget>, args: {
        send: SendFn<TState>;
    }): Promise<Session>;
    readonly events?: ChannelEvents<TCtx>;
    /**
     * Fetches bytes for a `URL` object encountered on a `FilePart.data` by the
     * staging pipeline. Return `null` to pass the URL through to the model
     * provider unchanged, or bytes / {@link FetchFileResult} to stage the file to
     * the sandbox.
     */
    readonly fetchFile?: (url: string) => Promise<Buffer | FetchFileResult | null>;
    /**
     * Channel-owned metadata exposed to instrumentation callbacks. This is the
     * channel's public observability surface, not a dump of durable adapter state,
     * so keep it small. Return an object of JSON primitives, arrays, and plain
     * objects: Eve omits `undefined` properties and drops projections containing
     * values such as `Date` or `Map`.
     */
    readonly metadata?: (state: NonNullable<TState>) => TMetadata;
    /**
     * Identifier of the adapter family this channel belongs to. Set by
     * higher-level wrappers (e.g. `slackChannel` passes `"slack"`) so downstream
     * consumers can render typed channel chips instead of bucketing everything
     * under "unknown".
     *
     * Authors calling `defineChannel` directly do not need to set this; the
     * framework defaults to `"http"` for stateless channels and `"defineChannel"`
     * for stateful ones.
     */
    readonly kindHint?: string;
}
/**
 * Opaque channel value produced by {@link defineChannel} and exported from
 * `agent/channels/<name>.ts`. Exposes the channel's routes, an optional
 * `receive` hook, and (via a phantom property) its metadata shape. Unlike
 * {@link ChannelDefinition} it has no `TCtx` parameter: the context type is
 * internal to the definition.
 */
export interface Channel<TState = undefined, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> extends TypedReceiveTarget<TReceiveTarget> {
    readonly __kind: typeof CHANNEL_SENTINEL;
    readonly [CHANNEL_METADATA_TYPE]?: TMetadata;
    readonly routes: readonly RouteDefinition<TState>[];
    readonly receive?: (input: ReceiveInput<TReceiveTarget>, args: {
        send: SendFn<TState>;
    }) => Promise<Session>;
}
/**
 * Extracts the metadata projection type (`TMetadata`) from a {@link Channel}.
 * Resolves to `Record<string, unknown>` when the value is not a Channel.
 */
export type InferChannelMetadata<TChannel> = TChannel extends Channel<any, any, infer TMetadata> ? TMetadata : Record<string, unknown>;
/**
 * Builds a {@link Channel} from a {@link ChannelDefinition}. Returns a value
 * placed at `agent/channels/<name>.ts`; the file path supplies the channel name
 * (do not add a `name` field). `TCtx` (the context factory's return type) is
 * internal to the definition and is not part of the returned Channel signature.
 */
export declare function defineChannel<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>>(definition: ChannelDefinition<TState, TCtx, TReceiveTarget, TMetadata>): Channel<TState, TReceiveTarget, TMetadata>;
