Skip to content

fix(management): decode the real snake_case wire keys for agents endpoints - #143

Open
pcarranzav wants to merge 1 commit into
mainfrom
pcv/fix-agents-wire-schema
Open

fix(management): decode the real snake_case wire keys for agents endpoints#143
pcarranzav wants to merge 1 commit into
mainfrom
pcv/fix-agents-wire-schema

Conversation

@pcarranzav

Copy link
Copy Markdown
Member

What

AmpersendManagementClient.createAgent() / .listAgents() decode the /v1/sdk/agents responses against camelCase keys (userId, initData, createdAt, updatedAt) while the API has emitted snake_case since the endpoints landed — every TS release 0.0.11–0.0.28 fails with Missing key ["userId"] against every API version. The Python SDK has the same aliases, masked only on pydantic ≥ 2.11 (validate_by_name is silently unsupported below that). The bug survived because test fixtures matched the SDK schema instead of the real wire format.

Paired with an API-side dual-emit shim (edgeandnode/ampersend#708) that retroactively heals already-installed releases; plan lives there (docs/plans/sdk-agents-schema-compat.md).

Changes

  • TS: AgentResponse pipes through Schema.encodeKeys({ userId: "user_id", initData: "init_data", createdAt: "created_at", updatedAt: "updated_at" }) — decoding reads the real wire keys; the public property surface is unchanged (non-breaking). CamelCase duplicates from the dual-emit API are ignored as excess keys.
  • Python: validation_aliasAliasChoices(snake, camel) on AgentResponse and AgentInitData; dropped validate_by_name; pydantic floor stays >=2.0 (decided: maximal compatibility, no silent degradation on any 2.x).
  • Fixtures rewritten to the real wire shape (snake outer keys, camelCase init_data inner keys, extra ignored fields like status/team_id), with dual-emit and legacy-camel decode cases. Comment added: a fixture matching the SDK schema instead of the wire is exactly how this bug survived.
  • Audit: no other management-client endpoint decodes mismatched keys (AgentResponse is the only decoded schema; envelope keys already match; balance/nonce are wire-strings on both sides).
  • Version bump 0.0.29 (TS + Python; uv.lock minimal bump). No tag/publish in this PR.

Verification

  • TS: build/lint clean; management tests 5/5. Python: ruff/mypy clean; management tests 7/7; uv lock --check passes.
  • E2E against a locally run dual-emit API: 0.0.29 createAgent (real Base Sepolia deploy) + listAgents pass in TS; list_agents passes in Python (incl. inner init_data alias decode); published 0.0.28 from npm confirmed healed by the API-side dual-emit.
  • Known pre-existing: tests/cli/{card,setup}.test.ts fail in shells exporting AMPERSEND_API_URL (test-isolation gap, unrelated; 64/64 pass with it unset).

🤖 Generated with Claude Code

https://claude.ai/code/session_01R4eTPfdoMYxuCWyUyx2H8V

…oints

AgentResponse decoded userId/initData/createdAt/updatedAt in camelCase
while the API has emitted snake_case (user_id/init_data/created_at/
updated_at) since the endpoints existed — createAgent()/listAgents()
fail with `Missing key ["userId"]` on every release 0.0.11-0.0.28. The
bug survived because the test fixtures matched the SDK schema instead
of the real wire format. Paired API-side dual-emit shim:
edgeandnode/ampersend PR #708 (plan: docs/plans/sdk-agents-schema-compat.md
there).

- TS: Schema.encodeKeys maps the four decoded camelCase properties to
  their snake_case wire keys — public type surface unchanged
  (non-breaking); dual-emitted camelCase duplicates are ignored as
  excess keys.
- Python: validation_alias -> AliasChoices(snake, camel) on
  AgentResponse and AgentInitData; dropped validate_by_name (silently
  unsupported on pydantic 2.0-2.10, which is how the same bug hid
  there); pydantic floor stays >=2.0.
- Test fixtures rewritten to the real wire shape (snake outer keys,
  camelCase init_data inner keys, extra ignored fields) with dual-emit
  and legacy-camel cases.
- Version bump to 0.0.29 (TS + Python); no other management-client
  endpoint had further key mismatches (audited).

Verified E2E against a locally run API: 0.0.29 create+list pass in both
languages; published 0.0.28 confirmed healed by the API-side dual-emit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4eTPfdoMYxuCWyUyx2H8V
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant