import type { RejectedUsageReport, UsageStatus, WakeCycleUsageReport } from "../agent/usage/usage-report-types.js";
/**
 * Globally-shared keys delivered by the heartbeat. These are tier-2
 * in the credential resolution stack:
 *
 *   1. Per-agent bundle (`credentialBundle.body.*`) — authoritative.
 *   2. `sharedKeys.*` (this object) — shared in-memory cache.
 *   3. Local `config.*` — manual/per-agent persisted fallback.
 *
 * Heartbeat-manager applies non-empty shared keys by calling the relevant
 * `setSharedXyzApiKey` setter (tier 2). It also seeds the matching
 * `config.json` field, but **only when the slot is currently empty**, so
 * shared keys never overwrite a value set by per-agent bundle apply,
 * `reconfigure`, or operator edits. The per-agent bundle path
 * (`runtime-credentials.ts`) overwrites non-empty values unconditionally
 * because it owns the agent's authoritative credentials. Null/empty
 * server-issued values are ignored rather than treated as deletions.
 */
export interface SharedKeys {
    geminiApiKey?: string;
    serpApiKey?: string;
    phonecallApiKey?: string;
    financialToolApiKey?: string;
    tosAccessKeyId?: string;
    tosAccessKeySecret?: string;
    anthropicApiKey?: string;
    ninerouterApiKey?: string;
    /**
     * Shared base URL for the 9Router provider. Lets the onboarding service
     * redirect agents to a different Anthropic-compatible 9Router endpoint
     * without local reconfiguration.
     */
    ninerouterBaseUrl?: string;
    /**
     * Shared OpenAI API key distributed by the onboarding service.
     * The agent applies the same precedence as `anthropicApiKey`:
     * shared in-memory cache > local `config.openaiApiKey` (offline
     * write-through). The heartbeat path mirrors this value into
     * `config.openaiApiKey` so the agent survives an offline server
     * across a restart.
     */
    openaiApiKey?: string;
}
export type SubscriptionStatus = "active" | "expired" | "skip";
export interface HeartbeatBillingPlan {
    id: string;
    name: string;
    amount: number;
    currency: string;
    description: string;
}
/**
 * Server-delivered tunnel credential. `credentialsJson` is the raw
 * `{UUID}.json` blob that `cloudflared` expects on disk; the agent
 * materialises it to its private profile tunnel directory.
 *
 * `configVersion` is an optional opaque version/fingerprint so the agent can
 * decide whether to rewrite local files. It should change whenever the server
 * rotates credentials or re-issues the tunnel identity.
 */
export interface TunnelRuntimeCredential {
    tunnelId: string;
    tunnelName: string;
    baseHostname: string;
    credentialsJson: string;
    configVersion?: string;
}
/**
 * Google Workspace credentials delivered to the lobster via heartbeat.
 * Available from onboarding_phase >= google_activated.
 * oauthTokensJson is only present from google_ready onwards.
 */
export interface GoogleRuntimeCredential {
    email: string;
    password: string;
    oauthTokensJson?: string;
}
export interface SerpApiRuntimeCredential {
    apiKey: string;
}
export interface GeminiRuntimeCredential {
    apiKey: string;
}
export interface BedrockRuntimeCredential {
    awsRegion: string;
    awsAccessKeyId: string;
    awsSecretAccessKey: string;
    awsSessionToken?: string;
    awsBearerToken?: string;
    username?: string;
}
export interface NinerouterRuntimeCredential {
    apiKey: string;
    baseUrl?: string;
}
/**
 * Body of a server-issued credential bundle. Forward-compatible umbrella
 * for all credential kinds.
 */
export interface TunnelRotationCommand {
    operationId: string;
    phase: "prepare" | "finalize" | "rollback" | "cleanup";
    pending?: TunnelRuntimeCredential;
    oldTunnelId?: string;
    newTunnelId?: string;
    targetHostname?: string;
    targetWildcardHostname?: string;
    soakUntil?: string;
}
export interface TunnelRuntimeStatus {
    currentTunnelId?: string;
    currentConnectorManagedByProcess?: boolean;
    currentConnectorSource?: "runtime_current" | "legacy_adopted" | "legacy_cert" | "unknown";
    currentConnectorPid?: number;
}
export interface TunnelRotationStatus {
    operationId: string;
    phase: "prepare_applied" | "pending_started" | "pending_failed" | "finalize_applied" | "finalize_failed" | "rollback_applied" | "cleanup_applied";
    currentTunnelId?: string;
    pendingTunnelId?: string;
    error?: string;
    reportedAt?: string;
}
export interface CredentialBundleBody {
    tunnel?: TunnelRuntimeCredential;
    tunnelRotation?: TunnelRotationCommand;
    google?: GoogleRuntimeCredential;
    serpapi?: SerpApiRuntimeCredential | null;
    gemini?: GeminiRuntimeCredential | null;
    bedrock?: BedrockRuntimeCredential | null;
    ninerouter?: NinerouterRuntimeCredential | null;
}
/**
 * A signed credential bundle returned by the onboarding service. The
 * server includes this in the heartbeat response only when its signature
 * differs from the `appliedCredentialSignature` the agent sent in the
 * request — so on the steady-state path this field is absent and the
 * heartbeat stays small.
 *
 * `signature` is opaque to the agent (server side computes it as a sha256
 * of canonicalised `body`). Agents only do string equality on it.
 */
export interface CredentialBundle {
    signature: string;
    body: CredentialBundleBody;
}
export type UsagePdfPeriod = "current" | "previous";
export interface UsagePeriodSummary {
    status: "active" | "exhausted" | "skip";
    wuUsed: number;
    wuLimit: number | null;
    bundleWuRemaining: number;
    periodStart: string | null;
    periodEnd: string | null;
    activeSeconds: number;
    meteredCycleCount: number;
    availableWu: number | null;
}
export interface UsagePeriodAvailability {
    period: UsagePdfPeriod;
    available: boolean;
    summary: UsagePeriodSummary;
}
export interface HeartbeatResponse {
    /**
     * Canonical agent name from the server's `agents.agent_name` column.
     * The agent uses this to detect a divergence between its local
     * `config.agentName` and the server's source of truth. On mismatch,
     * the agent moves its old local agentName into `config.displayName`
     * (only if displayName is currently unset) and overwrites
     * `config.agentName` with this value.
     *
     * Optional in the type so older servers that don't yet ship the field
     * still typecheck; clients treat absence as "no opinion, keep local".
     */
    agentName?: string;
    ownerEmail: string | null;
    ownerName: string | null;
    dualSessionEnabled: boolean;
    resendRequested: boolean;
    pendingCommands?: PendingCommand[];
    sharedKeys?: SharedKeys;
    subscriptionStatus?: SubscriptionStatus;
    billingPlans?: HeartbeatBillingPlan[];
    billingMessage?: string;
    /**
     * Server-issued credential bundle, present only when the server's
     * current signature differs from the agent's last-applied signature
     * (or when the agent omitted one — typically a fresh startup).
     */
    credentialBundle?: CredentialBundle;
    llmProviderPriority?: string[];
    /** Additive v2 provider route metadata. Old clients ignore this and keep using llmProviderPriority. */
    llmProviderRoutes?: {
        provider: string;
        enabled?: boolean;
        api_protocols: {
            api_protocol: string;
            enabled: boolean;
            models: {
                heavy: string;
                balanced: string;
                fast: string;
            };
            lastVerifiedAt?: string | null;
            lastError?: string | null;
        }[];
    }[];
    cardAvailable?: boolean;
    ackedUsageReportIds?: string[];
    rejectedUsageReports?: RejectedUsageReport[];
    usageStatus?: UsageStatus;
}
export interface PendingCommand {
    id: number;
    command: string;
    payload: unknown;
}
export interface CommandAck {
    commandId: number;
    status: "completed" | "failed";
    result?: string;
}
export interface HeartbeatHealthEvent {
    eventType: string;
    severity: string;
    message: string;
    details?: Record<string, unknown> | null;
}
export interface HeartbeatPayload {
    version?: string;
    model?: string;
    provider?: string;
    uptime?: number;
    busy?: boolean;
    onboardingComplete?: boolean;
    ownerEmail?: string;
    ownerName?: string;
    /**
     * Owner's Telegram chat ID, as a string (chat IDs can exceed 2^53 on
     * some clients so we avoid JS `number` here). Sent opportunistically
     * from the agent's local OwnerConfig so the server can store it on
     * the agent row and use it for direct owner notifications when the
     * agent is offline.
     */
    ownerChatId?: string;
    commandAcks?: CommandAck[];
    /**
     * Opaque signature (`sha256:<hex>`) of the credential bundle the agent
     * has currently materialised on disk. The server compares it against
     * its own current signature; on mismatch the response includes a fresh
     * `credentialBundle`, otherwise the response omits credentials entirely.
     *
     * Absent on the very first heartbeat after install (no manifest yet) or
     * when the agent fails to read its manifest — which is treated as
     * "unknown" and forces the server to send the bundle.
     */
    appliedCredentialSignature?: string;
    clientCapabilities?: string[];
    tunnelRuntimeStatus?: TunnelRuntimeStatus;
    tunnelRotationStatus?: TunnelRotationStatus;
    machineSerial?: string;
    /** Currently active LLM provider (may differ from config default due to fallback). */
    activeProvider?: string;
    /** Providers currently disabled by the fallback manager, with reason and cooldown expiry. */
    disabledProviders?: {
        provider: string;
        reason: string;
        disabledUntil: string;
    }[];
    usageReports?: WakeCycleUsageReport[];
    /** Agent-originated health events to record in onboarding Health Events. */
    healthEvents?: HeartbeatHealthEvent[];
}
/**
 * HTTP client for the VisionClaw onboarding service.
 * All methods are non-fatal: errors are logged but never thrown,
 * so a downed onboarding service never blocks the agent.
 */
export declare class OnboardingServiceClient {
    private readonly baseUrl;
    private readonly agentName;
    private readonly apiKey;
    constructor(baseUrl: string, agentName: string, apiKey: string);
    heartbeat(payload?: HeartbeatPayload): Promise<HeartbeatResponse | null>;
    /**
     * Heartbeat variant that throws on auth errors (401/403) instead of
     * silently returning null. Used for the startup key-validation heartbeat.
     */
    heartbeatStrict(payload?: HeartbeatPayload): Promise<HeartbeatResponse | null>;
    /**
     * Ask the onboarding service to reset the owner for this agent.
     * Returns true if the server confirmed the reset, false otherwise.
     * Non-fatal: a failed call logs a warning but never throws.
     */
    resetOwner(): Promise<boolean>;
    /**
     * Report Google OAuth tokens to the server after runGoogleOAuth() completes.
     * The server stores the tokens and advances the profile's onboarding_phase
     * from google_activated -> google_ready.
     *
     * Non-fatal: a network failure only logs a warning and does not block setup.
     * The tokens are already on local disk at this point.
     */
    reportGoogleTokens(oauthTokensJson: string): Promise<boolean>;
    notifyEmailSent(): Promise<void>;
    sendUsageBackfill(usageReports: WakeCycleUsageReport[]): Promise<boolean>;
    getUsagePeriods(): Promise<{
        success: boolean;
        periods: UsagePeriodAvailability[];
    }>;
    downloadUsagePdf(localPath: string, period?: UsagePdfPeriod): Promise<{
        success: boolean;
        finalPath: string;
        periodStart?: string;
        periodEnd?: string;
    }>;
    /**
     * Request a Stripe Checkout Session from the backend.
     * Returns the checkout URL for the owner to complete payment.
     */
    createCheckoutSession(planId: string, ownerChatId?: number): Promise<{
        checkoutUrl: string;
    } | null>;
    /**
     * Request a one-time Stripe Checkout Session for a bundle purchase (top-up).
     * Returns the checkout URL for the owner to make a one-time payment.
     */
    createBundlePurchase(amount: number, ownerChatId?: number): Promise<{
        checkoutUrl: string;
    } | null>;
    /**
     * Request a Stripe Billing Portal session from the backend.
     * Returns subscription info and a portal URL for the owner to manage billing.
     */
    getBillingPortal(): Promise<{
        status: string;
        planName: string | null;
        currentPeriodEnd: string | null;
        portalUrl?: string;
    } | null>;
    notifyComplete(ownerInfo?: {
        ownerEmail?: string;
        ownerName?: string;
        ownerChatId?: string;
    }): Promise<void>;
}
//# sourceMappingURL=onboarding-service-client.d.ts.map