import { type A2aActionPolicy, type A2aTurnOutcome, type A2aTurnService } from '../a2a/turn.js';
import type { Actor } from '../types.js';
import type { PoppyPrincipal } from './auth.js';
import { type PoppyEvent, type PoppyEventMessage, type PoppyResponder, type PoppySendBody, type PoppySender, type PoppyStatus } from './protocol.js';
import { type PoppyConversationRecord, type PoppyStore } from './store.js';
/** What the hooks are told about a conversation. */
export interface PoppyHookContext {
    conversationId: string;
    conversation: PoppyConversationRecord;
    /** Who the conversation's turns run as (its latest request); `null` before any. */
    actor: Actor | null;
}
/**
 * What {@link PoppyHandoffHooks.request} decided:
 *  - `'queued'` — someone will join: call {@link PoppyConversations.humanJoined} when they do, or
 *    {@link PoppyConversations.handoffUnavailable} if nobody can.
 *  - `'joined'` — a person took it now.
 *  - `{ unavailable }` — nobody can; the text is what the Company Agent says (§7.9).
 */
export type PoppyHandoffDecision = 'queued' | 'joined' | {
    unavailable: string;
};
/**
 * How the app brings a person in (§7.9). Without these, a handoff is answered by the Company Agent
 * saying no one is available — the conversation stays with the agent.
 */
export interface PoppyHandoffHooks {
    /** A person was asked for — by the Personal Agent (`requested`) or by the app (`company`). */
    request(ctx: PoppyHookContext & {
        by: 'requested' | 'company';
    }): PoppyHandoffDecision | Promise<PoppyHandoffDecision>;
    /**
     * A message from the Personal Agent while a person handles the conversation or is being found —
     * the agent does not answer those. Route it to your support tool.
     */
    message?(ctx: PoppyHookContext & {
        message: PoppyEventMessage;
    }): void | Promise<void>;
    /** The conversation closed while a person was handling it or being found (§7.12). */
    cancel?(ctx: PoppyHookContext): void | Promise<void>;
}
/** Notified when the Personal Agent opens or closes a Direct Conversation (§7.10). */
export interface PoppyDirectHooks {
    opened?(ctx: PoppyHookContext & {
        parentId: string;
    }): void | Promise<void>;
    closed?(ctx: PoppyHookContext & {
        parentId: string;
    }): void | Promise<void>;
}
/** What the Company Agent says on its own. */
export interface PoppyTexts {
    /** A handoff with no one to take it (§7.9). */
    handoffUnavailable: string;
    /** A turn that failed before saying anything. */
    failed: string;
    /** Asked in a Direct Conversation alongside an `authorization` event (§7.11 SHOULD). */
    signIn: string;
    /** An action that ran — `{title}` is the app's confirmation title (default {@link formatPoppyAction}). */
    actionSucceeded: string;
    /** An approved action that did not run. `{title}`, `{error}`. */
    actionFailed: string;
    /** An action the policy refused. `{title}`. */
    actionRejected: string;
}
export declare const DEFAULT_POPPY_TEXTS: PoppyTexts;
/** An action of the turn, as the reply's `data.actions` carries it. */
export type PoppyActionOutcome = A2aTurnOutcome;
/**
 * Words an action for the reply's text (§7: the message must make sense without `data`). Return
 * `null` to leave it out. Default {@link formatPoppyAction}.
 */
export type PoppyActionFormatter = (action: PoppyActionOutcome, texts: PoppyTexts) => string | null | undefined;
/**
 * Default wording: the status line from `texts` with the confirmation title (a question like
 * "Log this dose?" loses its `?`), then the confirmation detail.
 */
export declare function formatPoppyAction(action: PoppyActionOutcome, texts: PoppyTexts): string;
export interface PoppyConversationsOptions {
    store: PoppyStore;
    /** What runs a turn — `AgentService`, or an app's adapter (the A2A surface's contract). */
    service: A2aTurnService & {
        drive?(runId: string): Promise<void>;
    };
    /** The roles a tool declares, for matching the token's scopes. */
    toolRoles: (toolName: string) => string[] | undefined;
    /** The registered agent that answers. Omitted → the agent provider's default. */
    agentName?: string;
    /** What happens to `action` calls that park for approval. Default `'approve-delegated'`. */
    actions?: A2aActionPolicy;
    /** Give up on a turn after this many ms. Default 120 000. */
    timeoutMs?: number;
    /** Drive a durable run left pending, in this process (see `AgentService.drive`). Default `true`. */
    drive?: boolean;
    /** Map a principal without an actor to the app's actor. Default: `poppy:<hash>`. */
    actorFor?: (principal: PoppyPrincipal, defaults: Actor) => Actor | Promise<Actor>;
    /** Words each action of a reply. Default {@link formatPoppyAction}. */
    formatAction?: PoppyActionFormatter;
    handoff?: PoppyHandoffHooks;
    direct?: PoppyDirectHooks;
    texts?: Partial<PoppyTexts>;
    /** Keep events this long, then prune them (a cursor there is `cursor_expired`). Default: forever. */
    retentionMs?: number;
    /** How often a waiting read looks for events another replica appended. Default 1000 ms. */
    pollMs?: number;
    /** Logs what fails outside a request (a turn, a hook). */
    onError?: (error: unknown, context: string) => void;
}
/** What a read answers (§7.5). */
export interface PoppyReadResult {
    conversation_id: string;
    events: PoppyEvent[];
    cursor: string | null;
    has_more: boolean;
    status: PoppyStatus;
    responder: PoppyResponder;
}
/** What a stream yields: a stored event, or a provisional piece of text (§7.6). */
export type PoppyStreamItem = {
    kind: 'event';
    event: PoppyEvent;
} | {
    kind: 'delta';
    messageId: string;
    text: string;
} | {
    kind: 'state';
    status: PoppyStatus;
};
/** The actor of a principal the resolver gave none: stable per (Personal Agent, its User). */
export declare function poppyActorId(clientId: string, userId: string): string;
/**
 * Poppy conversations (§7) over the agent runtime: the state machine, the event log and the turns.
 * HTTP-free — `createPoppyHandler` puts the protocol's requests on it, and the app drives the
 * Company side through it (a person joining, their messages, `user_requested`).
 *
 * A conversation is an agent thread owned by the principal's actor. A user message is appended to
 * the event log, and the log is the turn queue: a pump per conversation (one replica at a time,
 * by lease) answers the messages after `turnSeq` in one turn, streams its text as `text-delta`,
 * then appends the reply as a `message` event. A replica that finds a conversation `working` with
 * no pump picks it up, so a reply survives the process that started it.
 *
 * @experimental Tracks Personal Agent Protocol Draft 0.1 (https://personalagentprotocol.org/docs/spec),
 * a spec still in development: this API WILL change as the spec evolves — possibly in breaking
 * ways, outside semver majors while it is a draft.
 */
export declare class PoppyConversations {
    #private;
    private readonly options;
    constructor(options: PoppyConversationsOptions);
    /**
     * The actor a principal's turns run as: the resolver's (`toActor`), else the app's `actorFor`,
     * else — signed in — the ACCOUNT, `{ id: accountId }`, the way a PACT delegation runs as the
     * account; signed out, `poppy:<hash>` (stable per Personal Agent and User, never an account).
     * It ALWAYS carries `personal_agent` (what puts it behind `personalAgentGate`) and one
     * `scope:<id>` role per account scope of a signed-in token — the roles a PACT delegation gives,
     * so a tool written for personal agents gates both surfaces alike.
     */
    actorOf(principal: PoppyPrincipal): Promise<Actor>;
    /** `POST {endpoint}` — start a conversation (or a Direct Conversation) with its first message. */
    start(principal: PoppyPrincipal, body: PoppySendBody): Promise<{
        status: number;
        body: Record<string, unknown>;
        conversationId: string;
    }>;
    /** `POST {endpoint}/{id}/messages` — another message (§7.3). */
    send(principal: PoppyPrincipal, conversationId: string, body: PoppySendBody): Promise<{
        status: number;
        body: Record<string, unknown>;
    }>;
    /** `GET {endpoint}/{id}/events` without streaming — read (and wait for) events (§7.5). */
    read(principal: PoppyPrincipal, conversationId: string, options: {
        cursor?: string;
        waitMs?: number;
    }): Promise<PoppyReadResult>;
    /** A read of a conversation already checked — also what a POST with `wait` answers (§7.3). */
    readOwned(conversation: PoppyConversationRecord, options: {
        cursor?: string;
        waitMs?: number;
    }): Promise<PoppyReadResult>;
    /** Check a conversation is the principal's, for a caller that reads it afterwards. */
    owned(principal: PoppyPrincipal, conversationId: string): Promise<PoppyConversationRecord>;
    /**
     * `GET {endpoint}/{id}/events` as SSE (§7.6): the events after `cursor`, then new ones as they
     * come, with `text-delta` pieces of a reply being written in this process. Ends when `signal`
     * aborts, or once the conversation is closed and every event was sent.
     */
    stream(conversation: PoppyConversationRecord, cursor: string | undefined, signal: AbortSignal): AsyncGenerator<PoppyStreamItem>;
    /** `POST {endpoint}/{id}/handoff` — ask for a person at the Company (§7.9). */
    requestHandoff(principal: PoppyPrincipal, conversationId: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /** `POST {endpoint}/{id}/close` — close the conversation (§7.12). */
    closeByAgent(principal: PoppyPrincipal, conversationId: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /** Look a conversation up — for the app's own routing (a support tool, an admin page). */
    get(conversationId: string): Promise<PoppyConversationRecord | null>;
    /**
     * Close a conversation (§7.12): its open Direct Conversation first, a pending handoff is
     * cancelled, and a `closed` state event added. Nothing it started is undone. Idempotent.
     */
    close(conversationId: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /** The Company Agent hands off to a person on its own (§7.9) — e.g. from one of your tools. */
    handoff(conversationId: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /** A person at the Company joined: `responder` becomes `human` (§7.7). */
    humanJoined(conversationId: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /** The person left: the Company Agent answers again. */
    humanLeft(conversationId: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /**
     * No one could take a queued handoff: the Company Agent says why, and the conversation goes back
     * to `idle` with the agent (§7.9).
     */
    handoffUnavailable(conversationId: string, reason?: string): Promise<{
        status: PoppyStatus;
        responder: PoppyResponder;
    }>;
    /**
     * Add a Company message — a person's (`sender: 'human'`, while they handle the conversation) or
     * an automated one. Answers the message's id.
     */
    postMessage(conversationId: string, message: {
        text?: string;
        data?: Record<string, unknown>;
        sender: PoppySender;
    }): Promise<string>;
    /**
     * Ask to talk with the User directly (§7.10): a `user_requested` event. Only the Personal Agent
     * opens the Direct Conversation, once the User agrees.
     */
    requestUser(conversationId: string, reason: string): Promise<void>;
    /** Stop pumping and waiting in this process (shutdown). */
    shutdown(): void;
}
//# sourceMappingURL=conversations.d.ts.map