import { type FleetWireJsonValue, type NodeRegisterReplyData } from '@relaycast/types';
/**
 * A node provider client: it attaches a process to a node, registers a subset
 * of that node's capabilities against the engine's `/v1/node/ws`, and executes
 * their invokes. It is the language-neutral equivalent of the broker's Rust
 * provider — connection, registration, heartbeats, invoke dispatch, and the
 * handler-context helpers — with no local-broker dependency.
 *
 * Enrollment (reading the node token/URL from disk) layers on top of this in a
 * thin wrapper; the client itself takes an explicit token and base URL.
 */
type JsonObject = Record<string, FleetWireJsonValue>;
/** A capability's declaration alongside its handler. */
export interface NodeCapabilityOptions {
    /**
     * `action` (default) materializes an invokable handler; `capacity`
     * (`spawn:<harness>`, `release`) describes what the node can run and is never
     * materialized. Omit to let the engine classify by name.
     */
    kind?: 'action' | 'capacity';
    /** Claim a workspace-global alias for this action name. */
    global?: boolean;
    /** Queue invokes while this provider is offline instead of failing fast. */
    queue?: boolean;
    metadata?: JsonObject;
}
/** Context passed to every capability handler. */
export interface NodeHandlerContext {
    /** Informational view of the node this provider is attached to. */
    node: {
        name: string;
        capabilities: string[];
    };
    /** The invocation being handled. */
    invocationId: string;
    /**
     * Post a channel message, attributed to `from` (an agent name resolved in the
     * workspace). Resolves with the posted message.
     */
    sendMessage(input: NodeSendMessageInput): Promise<unknown>;
    /**
     * Spawn an agent through the node's capacity executor. Capacity-direct: it
     * never re-enters action dispatch, so a `spawn:<harness>` shadow handler that
     * delegates cannot recurse into itself. Resolves with the spawn placement.
     */
    spawnAgent(input: JsonObject): Promise<unknown>;
}
export interface NodeSendMessageInput {
    to: string;
    from: string;
    text: string;
    mode?: 'wait' | 'steer';
    data?: JsonObject;
}
export type NodeCapabilityHandler = (input: FleetWireJsonValue, ctx: NodeHandlerContext) => unknown | Promise<unknown>;
export interface NodeProviderOptions {
    /** Engine base URL; defaults to `https://cast.agentrelay.com`. */
    baseUrl?: string;
    /** The node's shared `nt_live_` token. */
    nodeToken: string;
    /** The enrolled node id. */
    nodeId: string;
    /** The node's name (the target others address). */
    nodeName: string;
    /**
     * Provider identity. `name` is stable across reconnects; `instanceId` is the
     * connection epoch and is regenerated on every connection when omitted (the
     * replace semantic).
     */
    provider: {
        name: string;
        instanceId?: string;
    };
    /** Capabilities and their handlers, keyed by capability name. */
    capabilities?: Record<string, NodeCapabilityHandler | (NodeCapabilityOptions & {
        handler: NodeCapabilityHandler;
    })>;
    /** Provider-level agent capacity reported at registration. */
    maxAgents?: number;
    tags?: string[];
    version?: string;
    machineId?: string;
    heartbeatIntervalMs?: number;
    reconnectBaseDelayMs?: number;
    reconnectMaxDelayMs?: number;
    reconnectJitter?: boolean;
    /** Max reconnect attempts after an unexpected drop; defaults to unbounded. */
    maxReconnectAttempts?: number;
    onError?: (err: Error) => void;
    debug?: boolean;
}
/** Thrown when the engine rejects the provider's registration. */
export declare class NodeRegistrationError extends Error {
    readonly code: string;
    constructor(message: string, code: string);
}
export declare class NodeProviderClient {
    private readonly baseUrl;
    private readonly nodeToken;
    private readonly nodeId;
    private readonly nodeName;
    private readonly providerName;
    private readonly initialInstanceId?;
    private readonly maxAgents;
    private readonly tags;
    private readonly version;
    private readonly machineId?;
    private readonly heartbeatIntervalMs;
    private readonly reconnectBaseDelayMs;
    private readonly reconnectMaxDelayMs;
    private readonly reconnectJitter;
    private readonly maxReconnectAttempts;
    private readonly onError?;
    private readonly debug;
    private readonly capabilities;
    private readonly pending;
    private readonly invokeTasks;
    private ws;
    private instanceId;
    private heartbeatTimer;
    private reconnectTimer;
    private reconnectAttempt;
    private stopped;
    private registered;
    private servePromise;
    private resolveServe;
    private rejectServe;
    private registerPromise;
    private resolveRegister;
    private rejectRegister;
    constructor(options: NodeProviderOptions);
    /** Register a capability and its handler. */
    capability(name: string, handler: NodeCapabilityHandler): this;
    capability(name: string, options: NodeCapabilityOptions, handler: NodeCapabilityHandler): this;
    get connected(): boolean;
    /** Resolves once the provider is registered and its capabilities accepted. */
    whenRegistered(): Promise<NodeRegisterReplyData>;
    /**
     * Connect, register, and dispatch invokes until {@link stop} is called.
     * Reconnects with backoff on unexpected drops, re-registering with a fresh
     * instance id. The returned promise resolves on graceful {@link stop} and
     * rejects if the initial registration is rejected by the engine.
     */
    serve(): Promise<void>;
    private settleServe;
    /** Gracefully deregister the provider and close the connection. */
    stop(): Promise<void>;
    private providerIdentity;
    private openSocket;
    private registrationRejected;
    private sendRegister;
    private onRegistered;
    private onRegisterFailed;
    private handleFrame;
    private dispatchInvoke;
    private makeContext;
    /**
     * Post a channel message through the canonical message route with the node
     * token, attributed to `input.from`. Node-attributed posts share the route's
     * delivery routing, observer events, and triggers by construction.
     */
    private postChannelMessage;
    /** Send a request frame keyed by `id` and await its reply/error. */
    private request;
    private sendFrame;
    private startHeartbeat;
    private stopHeartbeat;
    private scheduleReconnect;
    private clearReconnect;
    private rejectPending;
    private closeSocket;
    private reportError;
}
export {};
//# sourceMappingURL=node-provider.d.ts.map