Commit 4aa7a6d
authored
feat(sdk): per-instance adcp_version pin + wire emission (Stage 2 + 3a) (#294)
* feat(sdk): per-instance adcp_version constructor option (Stage 2)
Adds Stripe-style per-instance protocol-version pinning. Each
ADCPClient / ADCPMultiAgentClient / ADCPServerBuilder accepts an
adcp_version constructor option (release-precision string, e.g.
"3.0", "3.1", "3.1-beta"). Default = the SDK's compile-time pin
(ADCP_VERSION packaged with the wheel). Each surface exposes
get_adcp_version().
Stage 2 is plumbing only — the value is stored per-instance and
exposed via the getter; no wire emission yet. Stage 3 lifts the
cross-major fence and threads the pin through schema/validator
selection and outbound wire emission. The protocol RFC for the
matching wire field is filed at adcontextprotocol/adcp#3493.
Cross-major pins raise ConfigurationError at construction —
within major 3 every accepted pin agrees with the wire's
ADCP_MAJOR_VERSION constant; no silent drift. Patch-precision
strings ("3.0.1") are accepted for backwards compatibility but
the spec defines negotiation at release precision only.
44 new tests in tests/test_adcp_version_option.py cover defaults,
valid pins, cross-major rejection, unparseable strings, and all
four constructor surfaces.
* feat(sdk): wire emission for adcp_version pin (Stage 3a)
Lifts the per-instance adcp_version pin from plumbing-only (Stage 2)
to actual wire emission. Builds against the upstream RFC at
adcontextprotocol/adcp#3493 — assumes that lands.
Client side:
- ProtocolAdapter gains envelope_enricher hook + _enrich_outgoing_params
helper. Hook runs after idempotency injection, before validation.
- MCPAdapter._call_mcp_tool and A2AAdapter._call_a2a_tool both apply
the enricher to the outbound params dict.
- ADCPClient.__init__ installs an enricher that prepends
adcp_version=self._adcp_version to every outbound request. Caller-
supplied values on the params dict win over the pin (per-call
override remains available once generated request types declare
the field).
Server side:
- capabilities_response() accepts adcp_version, supported_versions,
build_version. Emits supported_versions (release-precision list)
and build_version (advisory full semver) on the adcp block, plus
top-level adcp_version on the response envelope. Legacy
major_versions still emitted for back-compat through 3.x.
- ADCPServerBuilder's auto-generated get_adcp_capabilities handler
threads the builder's pinned adcp_version into capabilities_response().
10 new tests in tests/test_adcp_version_wire.py cover envelope
injection, default-value behavior, caller override, capability
response shape, and the auto-capabilities handler.
* fix(sdk): normalize adcp_version to release-precision before wire emission
Per the merged AdCP version-negotiation spec
(adcontextprotocol/adcp#3493, core/version-envelope.json):
"SDKs that read full-semver values from bundle metadata
(e.g. ComplianceIndex.published_version = '3.1.0-beta.1') MUST
normalize to release-precision ('3.1-beta.1') before emitting on
the wire — meta-field values are NOT valid wire values."
The packaged ADCP_VERSION file ships full-semver ('3.0.0' today). We
were passing it through unchanged to the wire, which is non-compliant.
Adds normalize_to_release_precision() to _version.py and applies it
in resolve_adcp_version() so:
- Patch-precision input ('3.0.0', '3.0.1') → stored/emitted as '3.0'
- Release-precision input ('3.0', '3.1-beta') → unchanged
- Pre-release tags preserved ('3.1.0-rc.1' → '3.1-rc.1')
get_adcp_version() returns the normalized form regardless of what
the caller passed — wire values are the canonical form.
13 new normalization tests; existing tests updated to assert
normalized output where the input was patch-precision.
* fix(sdk): code review polish on adcp_version pin
Addresses code-reviewer findings on PR #294:
- Re-export ConfigurationError from adcp.__init__ so callers can
import it from the public package surface (matches every other
ADCPError subclass).
- Accept SemVer build metadata (3.0.1+canary, 3.1.0-beta+sha.5) on
the regex; strip it on wire emission alongside patch. Build
metadata is purely a build identifier and never part of a contract.
- Document the caller-wins precedence on per-call params dict in
ADCPClient.__init__'s adcp_version section.
- Drop dead `if TYPE_CHECKING: pass` block in _version.py.
Tests: 3 new build-metadata normalization cases. 70/70 passing.
* docs(sdk): dx-expert polish on adcp_version pin
Addresses dx-expert findings on PR #294:
- ConfigurationError docstring trimmed from past-tense narrative to
the actionable rule: install the SDK major that targets the wire
version you want. Staging history lives in _version.py module
docstring (where it belongs).
- force_a2a_version docstring gains explicit cross-reference: "Not
for AdCP protocol pinning — see adcp_version for that." The two
string-shaped version kwargs sit side-by-side; agents skimming
the signature will guess wrong without the disambiguation.
- adcp_version docstring documents the migration from the legacy
adcp_major_version (integer) wire field — both coexist on the
wire through 3.x, servers prefer the new field, generated request
types still expose the legacy field until tracked schema sync
(issue #306) lands.
* feat(sdk): per-agent adcp_version map on ADCPMultiAgentClient
Addresses adtech-product-expert finding: a holdco trade desk almost
always has one seller on a newer release than the others during
rollout. Forcing all sub-clients to share a uniform pin makes the
multi-client useless the moment one seller ships a new release.
ADCPMultiAgentClient now accepts adcp_version: str | dict[str, str] | None:
- None → every agent uses the SDK default (unchanged).
- str → every agent uses this pin (unchanged).
- dict[str, str] → per-agent override map. Agents missing from the
map fall back to the SDK default. Each entry is independently
validated; cross-major in any entry raises ConfigurationError.
multi.get_adcp_version() returns the uniform pin when all agents
agree (including the all-same dict case); raises ValueError with the
per-agent map in the message when pins are heterogeneous, pointing
callers at multi.agent(id).get_adcp_version() for per-agent reads.
Also addresses python-expert findings:
- responses.py: build_version emit guard tightened from `if x:` to
`is not None` for consistency with the rest of the function.
- protocols/base.py: envelope_enricher docstring documents the
contract that top-level Request models must declare extra="allow"
(so the injected adcp_version key passes the post-enrichment
schema validator).
6 new tests covering per-agent map, fall-back, heterogeneous
get_adcp_version() behavior, and cross-major rejection within a map.
75/75 passing.
* chore(types): regen public API snapshot for ConfigurationError
Snapshot test caught the new public symbol added in commit ebed151
(re-export ConfigurationError from adcp.__init__). Regenerated via
scripts/regenerate_public_api_snapshot.py — addition is intentional.1 parent 2b36d67 commit 4aa7a6d
12 files changed
Lines changed: 833 additions & 19 deletions
File tree
- src/adcp
- protocols
- server
- tests
- fixtures
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
46 | 47 | | |
47 | 48 | | |
48 | 49 | | |
| |||
838 | 839 | | |
839 | 840 | | |
840 | 841 | | |
| 842 | + | |
841 | 843 | | |
842 | 844 | | |
843 | 845 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
336 | 337 | | |
337 | 338 | | |
338 | 339 | | |
| 340 | + | |
339 | 341 | | |
340 | 342 | | |
341 | 343 | | |
| |||
403 | 405 | | |
404 | 406 | | |
405 | 407 | | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
410 | | - | |
411 | | - | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
412 | 415 | | |
413 | 416 | | |
414 | 417 | | |
| |||
417 | 420 | | |
418 | 421 | | |
419 | 422 | | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
420 | 456 | | |
| 457 | + | |
421 | 458 | | |
422 | 459 | | |
423 | 460 | | |
| |||
462 | 499 | | |
463 | 500 | | |
464 | 501 | | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
465 | 513 | | |
466 | 514 | | |
467 | 515 | | |
| |||
479 | 527 | | |
480 | 528 | | |
481 | 529 | | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
482 | 546 | | |
483 | 547 | | |
484 | 548 | | |
| |||
4216 | 4280 | | |
4217 | 4281 | | |
4218 | 4282 | | |
| 4283 | + | |
4219 | 4284 | | |
4220 | 4285 | | |
4221 | 4286 | | |
| |||
4229 | 4294 | | |
4230 | 4295 | | |
4231 | 4296 | | |
| 4297 | + | |
| 4298 | + | |
| 4299 | + | |
| 4300 | + | |
| 4301 | + | |
| 4302 | + | |
| 4303 | + | |
| 4304 | + | |
| 4305 | + | |
| 4306 | + | |
| 4307 | + | |
| 4308 | + | |
| 4309 | + | |
| 4310 | + | |
4232 | 4311 | | |
4233 | | - | |
4234 | | - | |
4235 | | - | |
4236 | | - | |
4237 | | - | |
4238 | | - | |
4239 | | - | |
4240 | | - | |
4241 | | - | |
4242 | | - | |
| 4312 | + | |
| 4313 | + | |
| 4314 | + | |
| 4315 | + | |
| 4316 | + | |
| 4317 | + | |
| 4318 | + | |
| 4319 | + | |
| 4320 | + | |
| 4321 | + | |
| 4322 | + | |
| 4323 | + | |
| 4324 | + | |
| 4325 | + | |
| 4326 | + | |
| 4327 | + | |
| 4328 | + | |
| 4329 | + | |
| 4330 | + | |
| 4331 | + | |
| 4332 | + | |
| 4333 | + | |
| 4334 | + | |
| 4335 | + | |
| 4336 | + | |
| 4337 | + | |
| 4338 | + | |
| 4339 | + | |
| 4340 | + | |
| 4341 | + | |
| 4342 | + | |
| 4343 | + | |
| 4344 | + | |
4243 | 4345 | | |
4244 | 4346 | | |
| 4347 | + | |
| 4348 | + | |
| 4349 | + | |
| 4350 | + | |
| 4351 | + | |
| 4352 | + | |
| 4353 | + | |
| 4354 | + | |
| 4355 | + | |
| 4356 | + | |
| 4357 | + | |
| 4358 | + | |
| 4359 | + | |
| 4360 | + | |
| 4361 | + | |
| 4362 | + | |
| 4363 | + | |
| 4364 | + | |
| 4365 | + | |
| 4366 | + | |
4245 | 4367 | | |
4246 | 4368 | | |
4247 | 4369 | | |
| |||
0 commit comments