funduq-provider-sdk¶
Part of the SDKs.
What an agent provider and funduq agree on, stated from the provider's
side. Dependencies are cryptography, pyjwt, ag-ui-protocol — no
transport library, and no funduq: not depending on funduq is what makes this
package a second opinion on the bytes rather than an echo, and a fitness
test keeps it that way.
Identity and signing¶
ProviderIdentity wraps the Ed25519 keypair (generate, or load-or-create
from a key file so a restarted process keeps its identity; public_key
is the 64-char hex). Around it, builders for every payload the provider
signs: registration and deletion (timestamped), the link-open connect
proof (challenge-answered — sign_connect over the pinned funduq key,
funduq's nonce, the provider's own nonce, and the names to serve, so the
proof names its recipient and cannot be relayed to another funduq), the
per-call KYOK signature, and the two singular acts on a bound thread's
run — sign_resolution to answer its ask, sign_cancel to ask that it
stop, each under its own tag so neither is ever the other. Each builder is the independent twin of funduq's, and
reproduces the published vectors byte-for-byte, deterministic signatures
included.
The port and the worker¶
FunduqLink is the abstract port a transport implements: deliver a
run (handing it over — the verdict, accepted / declined / Refusal,
answers through funduq's answer_offer door on the same road reports
take, so a provider that accepts and streams in the same breath loses
nothing), cancel (acknowledged),
report_event, finish_run. Reading the record — a thread's history, a run — is not a link verb: every party reads through funduq's one read surface (Funduq.as_reader(key)), the provider as the key it proved at the handshake. InProcessLink is the
in-process transport (in-process is a transport, not a special case);
ProviderRuntime is the worker loop — one handler per thread, one active
run per thread by construction — that executes each agent's run_stream,
takes interjections through the opt-in interject_stream hook, and
reports events back through whatever link it is on. The shapes every
crossing uses are funduq-contract's; see the provider
link.
The envelopes¶
DeliveredRun is both what the runtime consumes and the declared wire
frame (model_dump(by_alias=True) / model_validate); CallerProps,
VerifiedActor and KyokForwardedProps declare funduq's two
forwarded-props additions so no provider restates them — a restated copy
once drifted on one field's nullability and silently dropped verified
caller identities.
Chain machinery¶
Both halves: sign_hop / new_chain / extend_chain to participate in
an actor chain, and verify_chain to police one — the twin of funduq's
verifier, same rules, no roster resolution, so an LLM provider or any
consumer can verify a delegation path without importing funduq.
A chain reached you through funduq only if its last hop says so. funduq
signs one hop of its own onto every chain it relays, naming the agent it
dispatched to under dispatchedTo. Nobody else can sign that hop. So an
agent reading forwardedProps.funduq.actorChain checks two things before treating
it as relayed: the tail hop's key is the funduq key its link proved at the
handshake, and dispatchedTo is itself. A chain that fails either is
something the caller typed into its own forwardedProps, or a real chain
carried to the wrong agent — a caller's words, not funduq's. The SDK does not
make this check for you; whether to accept a chain at all is your policy, and
the check is the first line of it.