import type { AgentTool } from "../internal/harness-types.js";
import type { A2aServerSpec, ToolEffect } from "./types.js";
/** The hard per-skill description bound (ruled 2026-08-03: ~2KiB). */
export declare const A2A_SKILL_DESCRIPTION_MAX_CHARS = 2048;
/**
 * The safety axes carried alongside one materialized A2A tool, for `prepare-task` to fold into the SAME
 * irreversible/egress collections first-party and MCP tools feed.
 *
 * Unlike MCP there is no server-hint leg to merge: the protocol has no per-skill annotation vocabulary,
 * and a remote agent's self-declaration would not be trustworthy if it had one. Every A2A tool therefore
 * starts at the ruled default (`egress:true`, the effect undeclared — read as `write` everywhere) and the CALLER's
 * {@link A2aServerSpec.toolAxes} is the only thing that can lower it (design F: caller = trust root).
 */
export interface A2aToolAxis {
    /** Namespaced tool name (`a2a__<peer>__<skill>`). */
    name: string;
    /** `"never"` appears ONLY via an explicit caller override — enforcement ignores it (tighten-only),
     *  the ask's risk-axes report face consumes it. */
    irreversibility?: "always" | "never";
    /** `false` appears ONLY via an explicit caller override — same posture: enforcement ignores it,
     *  the report face consumes it (an explicit negative is a judgment, not silence). */
    egress?: boolean;
    /** Present ONLY when the caller's override declares it; absent is the repeat-unsafe `write` every reader applies (and
     *  the roster names `default` provenance — a default is not a declaration). */
    effect?: ToolEffect;
}
/** design/99 §E9 equivalent for A2A — a per-peer projection of THIS materialization. A2A holds no
 *  connection (every call is its own HTTPS request), so `ready` means "the card was fetched and its
 *  skills were mounted at prepare time", never "the peer is alive right now". */
export interface A2aPeerStatus {
    name: string;
    status: "ready" | "failed";
    /** The card's self-declared name, neutralized + bounded (it rides consumer-rendered lines). */
    agentName?: string;
    agentDescription?: string;
    /** The negotiated JSON-RPC endpoint this task will call. */
    endpoint?: string;
    toolNames?: string[];
    error?: string;
}
/** One per-peer entry of {@link MaterializedA2a.refresh}. */
export interface A2aRefreshResult {
    peer: string;
    /** The peer's namespaced-name prefix — the consumer's SPLICE DOMAIN for a wholesale swap (the same
     *  self-healing prefix domain the MCP refresh receipt hands out). Present on every entry. */
    prefix: string;
    status: "refreshed" | "failed" | "disposed";
    toolCount: number;
    added: string[];
    removed: string[];
    tools?: AgentTool[];
    axes?: A2aToolAxis[];
    error?: string;
}
/**
 * Tools materialized from one or more A2A peers.
 *
 * Deliberately NARROWER than {@link import("./mcp.js").MaterializedMcp}: A2A has no server-instructions
 * channel and no intake schema gate, so there is no `serverInstructions`, no `instructionsDelta` and no
 * `droppedTools` face — an absent face is honest, an empty one that can never fill is a face a consumer
 * writes code against for nothing.
 */
export interface MaterializedA2a {
    tools: AgentTool[];
    toolAxes: A2aToolAxis[];
    /** One entry per peer that could not be materialized and was SKIPPED (fail-open, design/29): the task
     *  runs with the healthy peers' tools. The Runner forwards these to `onError(phase:"a2a")`. */
    warnings: Error[];
    /** One entry per DECLARED peer, in declaration order, ready or failed — the declaration as this materialization read it once. */
    statuses: A2aPeerStatus[];
    /** Re-read one peer's card (or every declared peer) and re-derive its tools. Unlike the MCP refresh
     *  this dials nothing new — every A2A call is a fresh request anyway — so a peer whose card or network
     *  failed at prepare time can genuinely recover here. The DECLARATION is not re-read: a refresh works
     *  from the copy this materialization took and judged — the members too (`headers`, `allowSkills`,
     *  `toolAxes` are copied, not shared) — so a declaration refused then is refused again and a caller
     *  rewriting its object afterwards, by replacing a member or by editing one in place, changes nothing. */
    refresh: (peer?: string) => Promise<A2aRefreshResult[]>;
    /**
     * Task teardown. There is no socket to close (every call is its own request), so what this owns is the
     * LIFETIME statement: after it resolves, a tool that somehow still holds a reference fails loudly
     * instead of talking to a remote agent on behalf of a task that has ended.
     */
    dispose: () => Promise<void>;
}
/** A JSON-RPC error answered BY the peer (the exchange happened; the peer refused or failed). Carries the
 *  numeric code for `instanceof`-plus-code discrimination — never message-text matching. */
export declare class A2aRpcError extends Error {
    readonly code: number;
    constructor(peer: string, method: string, code: number, message: string);
}
/**
 * Materialize every declared A2A peer into tools for one task.
 *
 * Peers are set up IN PARALLEL and merged in SPEC ORDER, so the tool roster (and therefore the system
 * prompt's tool list and the prefix cache) is byte-identical regardless of which card answered first.
 * `allSettled` keeps it fail-open: one unreachable peer is a skipped peer with a warning, never a task
 * that cannot start.
 */
export declare function materializeA2aTools(specs: readonly A2aServerSpec[], principal?: string, signal?: AbortSignal): Promise<MaterializedA2a>;
