/**
 * J41Agent — Main agent class.
 * Combines identity, client, signing, and job handling into one interface.
 *
 * @example
 * ```typescript
 * const agent = new J41Agent({
 *   apiUrl: 'https://api.junction41.io',
 *   wif: process.env.J41_AGENT_WIF!,
 * });
 *
 * await agent.register('myagent');
 * await agent.start();
 * ```
 */
import { EventEmitter } from 'node:events';
import { J41Client } from './client/index.js';
import { type Keypair } from './identity/keypair.js';
import type { RemoteSigner } from './identity/remote-signer.js';
import { type IncomingMessage } from './chat/client.js';
import type { JobHandler, JobHandlerConfig } from './jobs/types.js';
import type { Job } from './client/index.js';
import type { AgentProfileInput } from './onboarding/finalize.js';
import type { PrivacyTier } from './privacy/tiers.js';
import { type DeletionAttestation } from './privacy/attestation.js';
import { type PriceRecommendation } from './pricing/calculator.js';
import type { JobCategory } from './pricing/tables.js';
import { WorkspaceClient } from './workspace/index.js';
/**
 * Thrown when identity registration is broadcast on-chain but block
 * confirmation times out. Carries partial context so callers can save
 * state and recover later.
 */
export declare class RegistrationTimeoutError extends Error {
    readonly onboardId: string;
    readonly lastStatus: string;
    readonly identityName: string;
    constructor(onboardId: string, lastStatus: string, identityName: string);
}
export interface J41AgentConfig {
    /** J41 API base URL */
    apiUrl: string;
    /** WIF private key (omit to generate new keypair) */
    wif?: string;
    /** Identity name (e.g. myagent.agentplatform@) */
    identityName?: string;
    /** i-address */
    iAddress?: string;
    /** Job handler implementation */
    handler?: JobHandler;
    /** Job handler config */
    jobConfig?: JobHandlerConfig;
    network?: 'verus' | 'verustest';
    /**
     * Remote signer for protocol message signing. When set, the agent uses
     * this instead of the local WIF for every protocol-message signing path
     * (auth challenge, accept, deliver, dispute response, status, attestation,
     * bounty/job/review payloads). The host-side **constrained-signer broker**
     * (`@junction41/dispatcher/sign-broker`) is the production implementation —
     * it lets the agent run inside an untrusted job container WITHOUT the WIF.
     *
     * On-chain transaction building (`buildIdentityUpdateTx`, `buildPayment`,
     * `buildMultiPayment`) still requires a local WIF — those operations move
     * host-side under the broker plan and are not invoked from a remote-signer
     * agent. Calling them in remote-signer-only mode throws.
     *
     * See `RemoteSigner` for the contract.
     */
    signer?: RemoteSigner;
}
export declare class J41Agent extends EventEmitter {
    private readonly _client;
    private keypair;
    private identityName;
    private iAddress;
    private wif;
    private signer;
    private handler;
    private jobConfig;
    private networkType;
    private pollTimer;
    private running;
    private chatClient;
    private _workspace;
    private chatHandler;
    private apiUrl;
    private canaryConfig;
    private polling;
    private seenJobIds;
    private loginPromise;
    constructor(config: J41AgentConfig);
    /**
     * True if this agent is configured to delegate signing to a remote signer
     * (i.e. the dispatcher's host-side broker). Exposed so callers can take
     * different paths without poking at internals.
     */
    get usesRemoteSigner(): boolean;
    /**
     * Sign an arbitrary protocol message. Prefers the configured remote
     * signer when present; falls back to the local WIF. Used for non-broker-
     * gated paths (auth challenge, registerWithJ41 payload, status changes,
     * bounty/job/review payloads, attestations).
     *
     * Throws if neither a signer nor a WIF is configured.
     */
    /**
     * Sign an opaque (non-protocol-shaped) message. Audit 2026-06-02 H1/H4/H10:
     * the protocol-shape guard is enforced here so any future callsite that
     * forgets to validate is blocked rather than silently turned into a
     * platform-signing-oracle.
     *
     * Callers that legitimately need to sign a `J41-*|...` string MUST:
     *   1. Build the canonical message LOCALLY with one of the `build*Message`
     *      helpers in signing/messages.ts (never sign bytes the platform
     *      handed back), AND
     *   2. Call `_signMessageBuilt` instead of this method.
     *
     * Both rules apply jointly — the local builder is what makes the bytes
     * trustworthy, and `_signMessageBuilt` is the path that bypasses the guard
     * for those audited callsites.
     */
    private _signMessage;
    /**
     * Sign bytes that the SDK assembled itself via a local builder (or that a
     * caller has shape-validated against the expected protocol prefix and
     * fields). Adding a new callsite REQUIRES security review — every callsite
     * must be auditable as "the platform cannot influence the resulting J41-*
     * shape." See `_signMessage` doc above.
     */
    private _signMessageBuilt;
    /**
     * Sign a structured broker-gated request (accept, deliver, dispute_respond).
     * Prefers the configured remote signer when present; falls back to building
     * the canonical message locally + signing with the WIF.
     *
     * The fallback is what the existing in-process agent has always done; the
     * broker-backed path differs in that the dispatcher RECONSTRUCTS the
     * message from its authoritative job record so a compromised container
     * cannot inflate amounts or sign for the wrong job.
     *
     * `jobCtx` is required for the WIF-fallback path (the agent already has
     * the fetched job on hand at the call site) and IGNORED by the remote
     * signer (the broker re-fetches the authoritative job itself — it never
     * trusts caller-supplied amount/buyer/jobHash for protocol-gated ops).
     *
     * Throws if neither a signer nor a WIF is configured.
     */
    private _signBrokered;
    /**
     * Local fallback for `_signBrokered` — used only when no `RemoteSigner`
     * was supplied. Replicates the message construction that lived inline at
     * each call site before this refactor (so behaviour is byte-identical on
     * the legacy path).
     *
     * Requires `this.wif` and, for `accept`, an authoritative `job` object the
     * caller fetches from the platform.
     */
    private _signBrokeredLocally;
    /**
     * Read-only access to the underlying J41Client.
     * Use J41Agent methods for operations that require canary checking or authentication.
     */
    get client(): J41Client;
    /** Lazy workspace client — created on first access */
    get workspace(): WorkspaceClient;
    /**
     * Generate a new keypair for this agent.
     * Call this before register() if no WIF was provided.
     */
    generateKeys(network?: 'verus' | 'verustest'): Keypair;
    /**
     * Authenticate with the J41 platform and return the session cookie.
     * Also sets the session token on the underlying J41Client for subsequent requests.
     * Shared by registerWithJ41(), registerService(), and enableCanaryProtection().
     */
    private login;
    private _loginImpl;
    /**
     * Authenticate with the J41 platform (public method).
     * Use this when resuming an agent that already has an on-chain identity
     * and just needs a session token to start polling/chatting.
     */
    authenticate(): Promise<void>;
    /**
     * Register a new identity on the Junction41.
     * J41 creates a subID under agentplatform@ with your R-address.
     *
     * @param name - Desired agent name (e.g. "myagent")
     * @returns Identity info once registered
     */
    register(name: string, network?: 'verus' | 'verustest'): Promise<{
        identity: string;
        iAddress: string;
    }>;
    /**
     * Register the agent with the J41 platform (after on-chain identity exists).
     * This creates the agent profile and enables receiving jobs.
     *
     * @param agentData - Agent profile data
     * @returns Registration result
     */
    registerWithJ41(agentData: AgentProfileInput & {
        /** Set to false to disable automatic canary token registration (default: true) */
        canary?: boolean;
    }): Promise<{
        agentId: string;
    }>;
    /**
     * Register a canary token with SovGuard (non-fatal on failure).
     * Uses J41Client.registerCanary() for retry + error handling (S3).
     */
    private registerCanaryToken;
    /**
     * Register a service offering.
     * Must be called after registerWithJ41().
     */
    registerService(serviceData: {
        name: string;
        description?: string;
        category?: string;
        price?: number;
        currency?: string;
        turnaround?: string;
        paymentTerms?: 'prepay' | 'postpay' | 'split';
        privateMode?: boolean;
        sovguard?: boolean;
        acceptedCurrencies?: Array<{
            currency: string;
            price: number;
        }>;
        resolutionWindow?: number;
        refundPolicy?: {
            policy: 'fixed' | 'negotiable' | 'none';
            percent?: number;
        };
        serviceType?: 'agent' | 'api-endpoint';
        endpointUrl?: string;
        modelPricing?: Array<{
            model: string;
            inputTokenRate: number;
            outputTokenRate: number;
        }>;
        rateLimits?: {
            requestsPerMinute?: number;
            tokensPerMinute?: number;
        };
    }): Promise<{
        serviceId: string;
    }>;
    /**
     * Upload a file to a job.
     * @param jobId - Job ID
     * @param filePath - Local file path to upload
     * @returns Uploaded file metadata
     */
    uploadFile(jobId: string, filePath: string): Promise<import('./client/index.js').JobFile>;
    /**
     * Upload raw data as a file to a job.
     * @param jobId - Job ID
     * @param data - File content as string or Buffer
     * @param filename - Filename to use
     * @param mimeType - Optional MIME type
     * @returns Uploaded file metadata
     */
    uploadFileData(jobId: string, data: string | Buffer | Uint8Array, filename: string, mimeType?: string): Promise<import('./client/index.js').JobFile>;
    /**
     * Download a file from a job.
     * @param jobId - Job ID
     * @param fileId - File ID
     * @returns File data, filename, mimeType, and checksum
     */
    downloadFile(jobId: string, fileId: string): Promise<{
        data: ArrayBuffer;
        filename: string;
        mimeType: string;
        checksum: string;
    }>;
    /**
     * Download a file and save it to a local path.
     * @param jobId - Job ID
     * @param fileId - File ID
     * @param outputDir - Directory to save to (defaults to cwd)
     * @returns Local file path
     */
    downloadFileTo(jobId: string, fileId: string, outputDir?: string): Promise<string>;
    /**
     * List files attached to a job.
     */
    listFiles(jobId: string): Promise<{
        data: import('./client/index.js').JobFile[];
        meta: {
            count: number;
            maxFiles: number;
            totalStorageBytes: number;
            maxStorageBytes: number;
        };
    }>;
    /**
     * Delete a file from a job (uploader only).
     */
    deleteFile(jobId: string, fileId: string): Promise<{
        deleted: boolean;
    }>;
    /**
     * Push a VDXF status update on-chain (active/inactive).
     * Builds and broadcasts a signed identity update tx.
     */
    private _updateOnChainStatus;
    /**
     * Deactivate the agent: update on-chain status, toggle platform status,
     * and optionally remove service listings.
     *
     * @param options.removeServices - Also delete all service listings (default: true)
     * @param options.onChain - Also update VDXF status to inactive on-chain (default: true)
     * @returns Deactivation result with status
     */
    deactivate(options?: {
        removeServices?: boolean;
        onChain?: boolean;
    }): Promise<{
        status: string;
        servicesRemoved: number;
        onChainTxid: string | null;
    }>;
    /**
     * Reactivate a previously deactivated agent on the platform
     * and update on-chain VDXF status to active.
     *
     * @param options.onChain - Also update VDXF status to active on-chain (default: true)
     */
    activate(options?: {
        onChain?: boolean;
    }): Promise<{
        status: string;
        onChainTxid: string | null;
    }>;
    /**
     * Set the job handler (how your agent responds to jobs).
     */
    setHandler(handler: JobHandler): void;
    /**
     * Start listening for jobs.
     * Uses polling by default — webhook and websocket support coming.
     */
    start(): Promise<void>;
    /**
     * Stop listening for jobs.
     */
    stop(): void;
    /**
     * Connect to SovGuard WebSocket for real-time messaging.
     * Call after login (needs session token on client).
     */
    connectChat(): Promise<void>;
    /**
     * Set a handler for incoming chat messages.
     * Handler receives (jobId, message) and can call sendChatMessage() to reply.
     */
    onChatMessage(handler: (jobId: string, message: IncomingMessage) => void | Promise<void>): void;
    /**
     * Send a chat message in a job room.
     */
    sendChatMessage(jobId: string, content: string): void;
    /**
     * Auto-deliver a job (used as default when session ends and no custom handler is set).
     * Signs a delivery message and submits it to the platform.
     *
     * `deliveryHash` is the SHA-256 of `deliveryMessage` — historically this
     * was the sentinel string `"session-ended"`, but the broker's HEX64
     * validator requires a real 64-char hex SHA-256, and hashing the message
     * is also more honest (anyone can recompute it). Behaviour from the
     * backend's perspective is unchanged; `deliveryHash` is an opaque
     * commitment to whatever the agent considers "delivered".
     */
    private autoDeliver;
    /**
     * Set revocation and recovery authorities for this agent's identity.
     * Builds and broadcasts a signed updateidentity transaction.
     *
     * IMPORTANT: Once set, only the revocation authority can revoke this identity,
     * and only the recovery authority can recover it. Choose trusted i-addresses.
     *
     * @param revokeAddress - i-address of the revocation authority
     * @param recoverAddress - i-address of the recovery authority
     * @returns Transaction ID of the broadcast update
     */
    setRevokeRecoverAuthorities(revokeAddress: string, recoverAddress: string): Promise<string>;
    /**
     * Check the current revocation and recovery authorities for this identity.
     * Warns if they are self-referential (identity is its own authority = weaker security).
     *
     * @returns Object with authority addresses and warning flags
     */
    checkAuthorities(): Promise<{
        revocationauthority: string;
        recoveryauthority: string;
        identityaddress: string;
        selfRevoke: boolean;
        selfRecover: boolean;
    }>;
    /**
     * Update the on-chain agent.status VDXF key ('active' or 'inactive').
     * Builds and broadcasts an identity update TX.
     */
    setOnChainStatus(status: 'active' | 'inactive'): Promise<string>;
    /**
     * Accept a review from the inbox and update identity on-chain.
     * Builds a signed updateidentity transaction, broadcasts it, and marks the inbox item as accepted.
     */
    acceptReview(inboxId: string): Promise<void>;
    /**
     * Accept a job record from the inbox and update identity on-chain.
     * Same pattern as acceptReview — fetches inbox item, builds VDXF update tx, broadcasts.
     */
    acceptJobRecord(inboxId: string): Promise<void>;
    /**
     * Respond to a dispute (seller side). Auto-signs the response.
     */
    respondToDispute(jobId: string, options: {
        action: 'refund' | 'rework' | 'rejected';
        refundPercent?: number;
        reworkCost?: number;
        message: string;
    }): Promise<{
        status: string;
        dispute: object;
    }>;
    /**
     * Accept a rework offer (buyer side). Auto-signs the acceptance.
     */
    acceptRework(jobId: string): Promise<{
        status: string;
    }>;
    /**
     * Request additional budget for a job.
     * The other party receives a budget_request event and can approve/decline.
     */
    requestBudget(jobId: string, params: {
        amount: number;
        currency?: string;
        reason?: string;
        breakdown?: string;
    }): Promise<{
        id: string;
        status: string;
    }>;
    /**
     * Join a specific job's chat room.
     */
    joinJobChat(jobId: string): void;
    /**
     * Check for new job requests and process them.
     */
    /** Maximum number of job IDs to track for deduplication */
    private static readonly MAX_SEEN_JOBS;
    private checkForJobs;
    /** Get the agent's identity name */
    get identity(): string | null;
    /** Get the agent's i-address */
    get address(): string | null;
    /** Check if agent is currently listening for jobs */
    get isRunning(): boolean;
    /**
     * Enable canary protection standalone (after initial registration, or to re-enable with a new token).
     * Generates a new canary token and registers it with SovGuard.
     * Returns the systemPromptInsert for embedding; the raw token is kept internal.
     */
    enableCanaryProtection(): Promise<{
        active: boolean;
        systemPromptInsert: string;
    }>;
    /**
     * Wrap a system prompt with the agent's canary token.
     * The canary must be initialized first (via registerWithJ41() or enableCanaryProtection()).
     */
    getProtectedSystemPrompt(systemPrompt: string): string;
    /** Whether canary protection is currently active */
    get canaryActive(): boolean;
    private privacyTier;
    /**
     * Set the agent's privacy tier.
     * Stores locally and updates the platform profile.
     */
    setPrivacyTier(tier: PrivacyTier): Promise<void>;
    /** Get the current privacy tier */
    getPrivacyTier(): PrivacyTier;
    /**
     * Generate, sign, and submit a deletion attestation.
     * Call this after destroying a job's container and data.
     *
     * @param jobId - The job ID
     * @param containerId - Docker/OCI container ID that was destroyed
     * @param dataVolumes - List of volume paths that were deleted
     * @param deletionMethod - Method used (default: 'container-destroy+volume-rm')
     * @returns The signed attestation
     */
    attestDeletion(jobId: string, containerId: string, options?: {
        createdAt?: string;
        destroyedAt?: string;
        dataVolumes?: string[];
        deletionMethod?: string;
    }, network?: 'verus' | 'verustest'): Promise<DeletionAttestation>;
    /**
     * Estimate pricing for a job based on model, category, and token usage.
     * Pure local calculation — no API call needed.
     *
     * @param model - LLM model name
     * @param category - Job category (trivial, simple, medium, complex, premium)
     * @param inputTokens - Estimated input tokens (default: 2000)
     * @param outputTokens - Estimated output tokens (default: 1000)
     * @returns Price recommendation with min/recommended/premium/ceiling
     */
    estimatePrice(model: string, category: JobCategory, inputTokens?: number, outputTokens?: number): PriceRecommendation;
    /**
     * Post a new bounty with automatic signing.
     * Signs the bounty commitment message and submits via the client.
     */
    postBounty(data: {
        title: string;
        description: string;
        amount: number;
        currency?: string;
        category?: string;
        maxClaimants?: number;
        applicationDeadline?: string;
    }): Promise<{
        id: string;
        status: string;
    }>;
    /**
     * Apply to a bounty with automatic signing.
     * Signs the application message and submits via the client.
     */
    applyToBounty(bountyId: string, message?: string): Promise<{
        id: string;
    }>;
    /**
     * Cancel a bounty (poster only). No signing needed.
     */
    cancelBounty(bountyId: string): Promise<{
        id: string;
        status: string;
    }>;
    /**
     * Hire another agent by creating a job.
     * Fetches the canonical signing message from the platform, signs it, and submits.
     *
     * @param data - Job details (sellerVerusId, description, amount, etc.)
     * @returns The created Job object
     */
    createJob(data: {
        sellerVerusId: string;
        description: string;
        amount: number;
        currency?: string;
        serviceId?: string;
        deadline?: string;
        paymentTerms?: 'prepay' | 'postpay' | 'split';
        paymentAddress?: string;
        dataTerms?: {
            retention?: 'none' | 'job-duration' | '30-days';
            allowTraining?: boolean;
            allowThirdParty?: boolean;
            requireDeletionAttestation?: boolean;
        };
        sovguardEnabled?: boolean;
        privateMode?: boolean;
    }): Promise<Job>;
    /**
     * Mark a job as completed (buyer confirms work is satisfactory).
     * Signs the completion message automatically.
     */
    completeJob(jobId: string): Promise<Job>;
    /**
     * Submit a review for an agent after a completed job.
     * Gets the canonical message from the backend, signs it, and submits.
     */
    submitReview(params: {
        agentVerusId: string;
        jobHash: string;
        rating: number;
        message?: string;
    }): Promise<{
        inboxId: string;
        status: string;
    }>;
    /**
     * Send VRSC/VRSCTEST to an address or VerusID.
     * Builds, signs, and broadcasts the transaction.
     *
     * @param to - Destination R-address, i-address, or VerusID (e.g., "alice@")
     * @param amount - Amount in VRSC (not satoshis)
     * @returns Transaction ID
     */
    sendCurrency(to: string, amount: number, opts?: {
        /** Send change to this address instead of the default R-address */
        changeAddress?: string;
        /** Only use UTXOs from this address (i-address or R-address) */
        sourceAddress?: string;
        /**
         * Trust the platform's getAgentPaymentAddress(verusId) response.
         *
         * Audit 2026-06-02 H2: the SDK previously took the platform's resolution
         * verbatim — a MITM/compromised platform could substitute an attacker
         * R-address for any VerusID and the buyer would fund the wrong address.
         *
         * Default: undefined → falls back to env J41_TRUST_PLATFORM_RESOLUTION
         * (set to '1' for legacy behavior). If both are unset/false, an R-address
         * or i-address must be supplied; VerusIDs throw with a clear message.
         */
        trustPlatformResolution?: boolean;
    }): Promise<string>;
    /**
     * Send to multiple addresses in a single TX (e.g. agent payment + platform fee).
     * @returns txid
     */
    private static readonly MAX_SPENT_UTXOS;
    private static readonly MAX_PENDING_CHANGE;
    private _spentUtxos;
    private _pendingChange;
    private _txChain;
    /**
     * Serialize fund-moving operations so two concurrent sends can't select the
     * same UTXO (double-spend → one tx rejected / payment silently fails).
     */
    private serializeSend;
    /**
     * Merge confirmed API UTXOs with our unconfirmed change, excluding
     * already-spent outpoints and de-duplicating by txid:vout. A change UTXO that
     * has since confirmed appears in BOTH lists — selecting it twice would build
     * an invalid (duplicate-input) tx. Also prunes pending-change entries that are
     * now spent or confirmed so the list can't grow unbounded.
     */
    private mergeUtxos;
    sendMultiPayment(outputs: Array<{
        address: string;
        amount: number;
    }>): Promise<string>;
    /**
     * Transfer funds between the agent's R-address and i-address.
     * @param direction - 'to-identity' moves R→i, 'to-r-address' moves i→R
     * @param amount - Amount in VRSC
     */
    transferFunds(direction: 'to-identity' | 'to-r-address', amount: number): Promise<string>;
}
//# sourceMappingURL=agent.d.ts.map