polyc-a2a 2026.9.0

polychrome A2A edge: serves a domain-signed Agent Card and drives message/send tasks onto a turn.
//! polychrome-a2a — an **A2A v1.0** edge that puts an agent-to-agent peer in
//! front of a polychrome conversation.
//!
//! A2A (`Agent2Agent`) is the open protocol agents use to discover and call one
//! another. The wire is the **v1.0** (`lf.a2a.v1`) `ProtoJSON` dialect
//! ([`types`]) — `PascalCase` methods, `SCREAMING_SNAKE` enums, field-presence
//! unions — mirroring the canonical Rust SDK (`a2aproject/a2a-rs`) so the edge
//! interops with any v1.0 peer.
//!
//! Both halves live here:
//!
//! - **Server** — serves a domain-signed **Agent Card** at
//!   `/.well-known/agent-card.json` ([`card`]) and implements the
//!   capability-ungated method set over JSON-RPC ([`rpc`]): `SendMessage` maps a
//!   message onto a single polychrome turn ([`task`]) and records the resulting
//!   task durably ([`store`]); `GetTask`/`CancelTask`/`ListTasks` read it back.
//!   The record lives in the state plane and this edge reaches it the same way
//!   it reaches a turn: an RPC into the control plane.
//! - **Client** ([`client`]) — fetches + verifies a peer's card and drives
//!   `SendMessage`/`GetTask` against it.
//!
//! ## The load-bearing mapping
//!
//! A2A's `input-required` task state and polychrome's human-in-the-loop
//! approval gate are the same idea: a task cannot proceed until a human
//! decides. A turn that pauses on an approval
//! ([`polyc_rpc_client::TurnEvent::ApprovalPending`]) becomes a
//! `TASK_STATE_INPUT_REQUIRED` task ([`task::outcome_from_events`] →
//! [`rpc`]), so an A2A peer is told, in its own protocol, that the work is
//! blocked on a decision.
//!
//! ## Identity provisioning (follow-up)
//!
//! For this foundation slice the signing key is derived from a configured seed
//! (the convention `polyc_crypto`'s signers use for dev/test). Wiring the
//! deployment principal to a secret store — so the card is signed by the same
//! durable key that backs the rest of the deployment's provenance — is a
//! follow-up.

#![forbid(unsafe_code)]
#![warn(missing_docs)]

pub mod card;
pub mod client;
pub mod config;
pub mod peer_directory;
pub mod rpc;
pub mod server;
pub mod store;
pub mod task;
pub mod types;

pub use card::{CardConfig, build_card, sign_card, signed_card, verify_card, verify_self_signed};
pub use client::{A2aClient, ClientError, PeerCard, PeerOutcome, ResponseBounds};
pub use config::{Cli, Config};
pub use peer_directory::{PEERS_ENV, PeerConfig};
pub use server::{AppState, PeerAuthenticator, PeerCredentialError, router};
#[cfg(any(test, feature = "test-util"))]
pub use store::test_double::InMemoryTaskStore;
pub use store::{TaskDialerStore, TaskStore, TaskStoreError, TaskUpdate, UnconfiguredTaskStore};
pub use task::{
    AgentDialerRunner, ApprovalDialerResponder, ApprovalResponder, TurnOutcome, TurnRequest,
    TurnRunner, TurnStreamEvent, UnconfiguredApprovalResponder, UnconfiguredRunner,
    outcome_from_events,
};
pub use types::{
    Artifact, Message, Part, PartContent, Role, SendMessageResponse, StreamResponse, Task,
    TaskArtifactUpdateEvent, TaskState, TaskStatus, TaskStatusUpdateEvent,
};