v5.19.0
Minor Changes
-
af944a1: feat(AgentClient): add
AgentClient.fromMCPClient()factory for in-process MCP transportAdds a new static factory method that accepts a pre-connected
@modelcontextprotocol/sdkClientinstance instead of a URL-based agent config. This enables compliance test fleets to wire up a fullAgentClientagainst anInMemoryTransportpair without an HTTP loopback server.MCP only. This factory wraps an MCP
Clientfrom@modelcontextprotocol/sdk. There is no equivalent in-process bridge for A2A today — for A2A agents, run them on a loopback HTTP server and use the standardAgentClientconstructor with the agent'sagent_uri.Key behaviors preserved over the in-process path:
adcp_major_versionis injected on every tool callidempotency_keyis auto-generated for mutating tasksisErrorenvelopes surface asTaskResult<{ success: false }>- HTTP-only methods (
resolveCanonicalUrl,getWebhookUrl,registerWebhook,unregisterWebhook) throw descriptivein-processguard errors - Endpoint discovery and SSRF validation are bypassed for the sentinel URI
Exports the new
InProcessAgentClientConfigtype for typed factory usage. -
efbe785: Add
pgBackend.probe()andserve({ readinessCheck })for fail-fast pool validationSellers wiring
createIdempotencyStore({ backend: pgBackend(pool) })from aDATABASE_URLenv var previously got a silent failure mode: a bad URL (typo, deprovisioned DB, missing creds) lets the server boot successfully, advertiseIdempotencySupported, then fail every mutating call indefinitely.This release adds:
pgBackend.probe()— runsSELECT 1 FROM "<table>" LIMIT 0at startup, validating both connectivity and that the idempotency table has been migrated. Throws a descriptive error naming the table, root cause, and remediation steps.IdempotencyStore.probe()— delegates tobackend.probe()when the backend implements it; no-ops formemoryBackend.probeIdempotencyStore(store)— convenience export for callers that manage their own lifecycle (Lambda, custom HTTP frameworks).ServeOptions.readinessCheck?: () => Promise<void>— called beforehttpServer.listen(). The server never accepts connections if the check throws, so a misconfigured pool crashes the process at deploy time rather than silently failing live traffic.
Wire the probe in
serve():const store = createIdempotencyStore({ backend: pgBackend(pool), ttlSeconds: 86400 }); pool.on('error', err => console.error('pg pool error', err)); // prevent crash on idle-client errors serve(createAgent, { readinessCheck: () => store.probe(), });
readinessCheckis general-purpose — use it for any startup dependency check, not just idempotency.Non-breaking.
createIdempotencyStoreremains synchronous. Existing callers require no changes. Option A (async constructor) is tracked separately as a future major-version enhancement. -
a26db16: Storyboard runner: add
$generate:opaque_idsubstitution andcontext_outputs[generate]for threading runner-minted task IDs through multi-step lifecycle storyboards.$generate:opaque_idand$generate:opaque_id#<alias>work identically to$generate:uuid_v4/$generate:uuid_v4#<alias>but carry explicit task-ID semantics. Both share the same alias cache namespace.context_outputsentries now acceptgenerate: "opaque_id" | "uuid_v4"as an alternative topath:. Whengenerateis set the runner mints (or reuses, via alias-cache coherence) a UUID at post-step time and writes it into$context.<key>for subsequent steps. If an inline$generate:opaque_id#<key>substitution already ran in the same step'ssample_request, the generator reuses that value — the two forms are alias-coherent.ContextProvenanceEntry.source_kindandContextValueRejectedHint.source_kindgain a'generator'variant for accurate diagnostic attribution.ContextOutput.pathis now optional (mutually exclusive with the newgeneratefield).
Patch Changes
-
c58ff99: Fix
get_media_buysconvention extractor poisoning context during multi-page pagination walks (#998). The extractor unconditionally capturedmedia_buys[0].media_buy_idfrom every successfulget_media_buysresponse. When a storyboard walks multi-page results, the page-1 response carriespagination.has_more: true— buys[0] is not the canonical buy, it is just the first item in a list slice. The captured ID was then picked up by the request-builder enricher on step 2 and injected asmedia_buy_ids: [that_id], turning the pagination continuation into a single-ID lookup. The agent returned one buy withhas_more: false, total_count: 1, failingtotal_count: 3storyboard assertions.The extractor now skips extraction when
pagination.has_more === true, matching the conservative=== trueconvention used elsewhere in the codebase (hasMorePages()invalidations.ts). Whenhas_moreis absent orfalse— i.e., a terminal or single-page response — extraction proceeds as before. This unblocksget-media-buys-pagination-integrityinadcontextprotocol/adcp#3122from upgrading to the seeded multi-page walk model used bylist_creativesand other paginated storyboards.