/**
 * High-level facade for the Agent Relay SDK.
 *
 * Provides a clean, property-based API on top of the lower-level
 * {@link AgentRelayClient} protocol client.
 *
 * @example
 * ```ts
 * import { AgentRelay } from "@agent-relay/sdk";
 *
 * const relay = new AgentRelay();
 *
 * relay.onMessageReceived = (message) => console.log(message);
 * relay.onAgentSpawned = (agent) => console.log("spawned", agent.name);
 *
 * const codex = await relay.codex.spawn();
 * const human = relay.human({ name: "System" });
 * await human.sendMessage({ to: codex.name, text: "Hello!" });
 *
 * const agents = await relay.listAgents();
 * for (const a of agents) await a.release();
 * await relay.shutdown();
 * ```
 */
import { type SendMessageInput, type SpawnPtyInput } from './client.js';
import type { AgentRuntime, BrokerEvent, BrokerStatus, RestartPolicy } from './protocol.js';
import { type FollowLogsOptions, type LogFollowHandle, type LogsResult } from './logs.js';
export interface Message {
    eventId: string;
    from: string;
    to: string;
    text: string;
    threadId?: string;
    data?: Record<string, unknown>;
}
export type AgentStatus = 'spawning' | 'ready' | 'idle' | 'exited';
export type DeliveryWaitStatus = 'ack' | 'failed' | 'timeout';
export type DeliveryStateStatus = 'queued' | 'injected' | 'active' | 'verified' | 'failed';
export interface DeliveryWaitResult {
    eventId: string;
    status: DeliveryWaitStatus;
    targets: string[];
}
export interface DeliveryState {
    eventId: string;
    to: string;
    status: DeliveryStateStatus;
    updatedAt: number;
}
export interface SpawnLifecycleContext {
    name: string;
    cli: string;
    channels: string[];
    task?: string;
}
export interface SpawnLifecycleSuccessContext extends SpawnLifecycleContext {
    runtime: AgentRuntime;
}
export interface SpawnLifecycleErrorContext extends SpawnLifecycleContext {
    error: unknown;
}
export interface SpawnLifecycleHooks {
    onStart?: (context: SpawnLifecycleContext) => void | Promise<void>;
    onSuccess?: (context: SpawnLifecycleSuccessContext) => void | Promise<void>;
    onError?: (context: SpawnLifecycleErrorContext) => void | Promise<void>;
}
export interface ReleaseLifecycleContext {
    name: string;
    reason?: string;
}
export interface ReleaseLifecycleErrorContext extends ReleaseLifecycleContext {
    error: unknown;
}
export interface ReleaseLifecycleHooks {
    onStart?: (context: ReleaseLifecycleContext) => void | Promise<void>;
    onSuccess?: (context: ReleaseLifecycleContext) => void | Promise<void>;
    onError?: (context: ReleaseLifecycleErrorContext) => void | Promise<void>;
}
export interface ReleaseOptions extends ReleaseLifecycleHooks {
    reason?: string;
}
export interface SpawnOptions extends SpawnLifecycleHooks {
    args?: string[];
    channels?: string[];
    model?: string;
    cwd?: string;
    team?: string;
    shadowOf?: string;
    shadowMode?: string;
    idleThresholdSecs?: number;
    restartPolicy?: RestartPolicy;
}
export interface SpawnAndWaitOptions extends SpawnOptions {
    timeoutMs?: number;
    waitForMessage?: boolean;
}
type AgentOutputPayload = {
    stream: string;
    chunk: string;
};
type AgentOutputCallback = ((chunk: string) => void) | ((data: AgentOutputPayload) => void);
export interface Agent {
    readonly name: string;
    readonly runtime: AgentRuntime;
    readonly channels: string[];
    /** Current lifecycle status of the agent. */
    readonly status: AgentStatus;
    /** Set when the agent exits. Available after `onAgentExited` fires. */
    exitCode?: number;
    /** Set when the agent exits via signal. Available after `onAgentExited` fires. */
    exitSignal?: string;
    /** Set when the agent requests exit via /exit. Available after `onAgentExitRequested` fires. */
    exitReason?: string;
    release(reasonOrOptions?: string | ReleaseOptions): Promise<void>;
    waitForReady(timeoutMs?: number): Promise<void>;
    /** Wait for the agent process to exit on its own.
     *  @param timeoutMs — optional timeout in ms. Resolves with `"timeout"` if exceeded,
     *  `"exited"` if the agent exited naturally, or `"released"` if released externally. */
    waitForExit(timeoutMs?: number): Promise<'exited' | 'timeout' | 'released'>;
    /** Wait for the agent to go idle (no PTY output for the configured threshold).
     *  @param timeoutMs — optional timeout in ms. Resolves with `"idle"` when first idle event fires,
     *  `"timeout"` if timeoutMs elapses first, or `"exited"` if the agent exits. */
    waitForIdle(timeoutMs?: number): Promise<'idle' | 'timeout' | 'exited'>;
    sendMessage(input: {
        to: string;
        text: string;
        threadId?: string;
        priority?: number;
        data?: Record<string, unknown>;
    }): Promise<Message>;
    /** Register a callback for PTY output from this agent. Returns an unsubscribe function. */
    onOutput(callback: AgentOutputCallback): () => void;
}
export interface HumanHandle {
    readonly name: string;
    sendMessage(input: {
        to: string;
        text: string;
        threadId?: string;
        priority?: number;
        data?: Record<string, unknown>;
    }): Promise<Message>;
}
export interface AgentSpawner {
    spawn(options?: SpawnerSpawnOptions): Promise<Agent>;
}
export interface SpawnerSpawnOptions extends SpawnLifecycleHooks {
    name?: string;
    args?: string[];
    channels?: string[];
    task?: string;
    model?: string;
    cwd?: string;
}
export type EventHook<T> = ((value: T) => void) | null;
export interface AgentRelayOptions {
    binaryPath?: string;
    binaryArgs?: string[];
    brokerName?: string;
    channels?: string[];
    cwd?: string;
    env?: NodeJS.ProcessEnv;
    requestTimeoutMs?: number;
    shutdownTimeoutMs?: number;
    /**
     * Name for the auto-created Relaycast workspace.
     * If omitted, a random name is generated.
     * Ignored when RELAY_API_KEY is already set in env or process.env.
     */
    workspaceName?: string;
    /**
     * Base URL for the Relaycast API.
     * Defaults to RELAYCAST_BASE_URL env var or https://api.relaycast.dev.
     */
    relaycastBaseUrl?: string;
}
export declare class AgentRelay {
    onMessageReceived: EventHook<Message>;
    onMessageSent: EventHook<Message>;
    onAgentSpawned: EventHook<Agent>;
    onAgentReleased: EventHook<Agent>;
    onAgentExited: EventHook<Agent>;
    onAgentReady: EventHook<Agent>;
    onWorkerOutput: EventHook<{
        name: string;
        stream: string;
        chunk: string;
    }>;
    onDeliveryUpdate: EventHook<BrokerEvent>;
    onAgentExitRequested: EventHook<{
        name: string;
        reason: string;
    }>;
    onAgentIdle: EventHook<{
        name: string;
        idleSecs: number;
    }>;
    /** The resolved Relaycast workspace API key (available after first spawn). */
    get workspaceKey(): string | undefined;
    /** Observer URL for the auto-created workspace (available after first spawn). */
    get observerUrl(): string | undefined;
    readonly codex: AgentSpawner;
    readonly claude: AgentSpawner;
    readonly gemini: AgentSpawner;
    private readonly clientOptions;
    private readonly defaultChannels;
    private readonly workspaceName?;
    private readonly relaycastBaseUrl?;
    private relayApiKey?;
    private client?;
    private startPromise?;
    private unsubEvent?;
    private readonly knownAgents;
    private readonly readyAgents;
    private readonly messageReadyAgents;
    private readonly exitedAgents;
    private readonly idleAgents;
    private readonly deliveryStates;
    private readonly outputListeners;
    private readonly exitResolvers;
    private exitResolverSeq;
    private readonly idleResolvers;
    private idleResolverSeq;
    constructor(options?: AgentRelayOptions);
    /**
     * Subscribe to broker stderr output. Listener is wired immediately if the
     * client is already started, otherwise it is attached when the client starts.
     * Returns an unsubscribe function.
     */
    onBrokerStderr(listener: (line: string) => void): () => void;
    spawnPty(input: SpawnPtyInput & SpawnLifecycleHooks): Promise<Agent>;
    spawn(name: string, cli: string, task?: string, options?: SpawnOptions): Promise<Agent>;
    spawnAndWait(name: string, cli: string, task: string, options?: SpawnAndWaitOptions): Promise<Agent>;
    human(opts: {
        name: string;
    }): HumanHandle;
    system(): HumanHandle;
    /**
     * Broadcast a message to all connected agents.
     * @param text — the message body
     * @param options — optional sender name (defaults to "human:orchestrator")
     */
    broadcast(text: string, options?: {
        from?: string;
    }): Promise<Message>;
    sendAndWaitForDelivery(input: SendMessageInput, timeoutMs?: number): Promise<DeliveryWaitResult>;
    listAgents(): Promise<Agent[]>;
    /** Pre-register a batch of agents with Relaycast before steps execute. */
    preflightAgents(agents: Array<{
        name: string;
        cli: string;
    }>): Promise<void>;
    /** List agents with PIDs from the broker (for worker registration). */
    listAgentsRaw(): Promise<Array<{
        name: string;
        pid?: number;
    }>>;
    getStatus(): Promise<BrokerStatus>;
    getDeliveryState(eventId: string): DeliveryState | undefined;
    /**
     * Read the last N lines of an agent's log file.
     *
     * @example
     * ```ts
     * const logs = await relay.getLogs("Worker1", { lines: 100 });
     * if (logs.found) console.log(logs.content);
     * ```
     */
    getLogs(agentName: string, options?: {
        lines?: number;
    }): Promise<LogsResult>;
    /** List all agents that have log files. */
    listLoggedAgents(): Promise<string[]>;
    /**
     * Follow an agent's local log file with history bootstrap + incremental updates.
     *
     * @example
     * ```ts
     * const handle = relay.followLogs("Worker1", {
     *   historyLines: 100,
     *   onEvent(event) {
     *     if (event.type === "log") console.log(event.content);
     *   },
     * });
     *
     * // Later:
     * handle.unsubscribe();
     * ```
     */
    followLogs(agentName: string, options: Omit<FollowLogsOptions, 'logsDir'>): LogFollowHandle;
    /**
     * Wait for any one of the given agents to exit. Returns the first agent
     * that exits along with its exit reason.
     *
     * @example
     * ```ts
     * const { agent, result } = await AgentRelay.waitForAny([worker1, worker2], 60_000);
     * console.log(`${agent.name} finished: ${result}`);
     * ```
     */
    static waitForAny(agents: Agent[], timeoutMs?: number): Promise<{
        agent: Agent;
        result: 'exited' | 'timeout' | 'released';
    }>;
    /**
     * Resolves when the agent process has started and connected to the broker.
     * The agent's CLI may not yet be ready to receive messages.
     * Use `waitForAgentMessage()` for full readiness.
     */
    waitForAgentReady(name: string, timeoutMs?: number): Promise<Agent>;
    waitForAgentMessage(name: string, timeoutMs?: number): Promise<Agent>;
    shutdown(): Promise<void>;
    private ensureAgentHandle;
    private updateDeliveryState;
    private resolveEventTimestamp;
    /** Resolve a target to a channel name. If `to` is `#channel`, use that
     *  channel. If it's a known agent name, use the agent's first channel.
     *  Otherwise fall back to the relay's default channel. */
    private resolveChannel;
    private inferOutputMode;
    private dispatchOutput;
    /**
     * Ensure a Relaycast workspace API key is available.
     * Resolution order:
     *   1. Already resolved (cached from a previous call)
     *   2. RELAY_API_KEY in options.env
     *   3. RELAY_API_KEY in process.env
     *   4. Auto-create a fresh workspace via the Relaycast REST API
     */
    private ensureRelaycastApiKey;
    private ensureStarted;
    private wireEvents;
    private makeAgent;
    private createSpawner;
    private invokeLifecycleHook;
    private resetAgentLifecycleState;
    private normalizeReleaseOptions;
}
export {};
//# sourceMappingURL=relay.d.ts.map