Skip to content

fix: improve --save-auth UX with better error messages and auth handling#83

Merged
bokelley merged 1 commit intomainfrom
bokelley/cli-auth-hang
Oct 25, 2025
Merged

fix: improve --save-auth UX with better error messages and auth handling#83
bokelley merged 1 commit intomainfrom
bokelley/cli-auth-hang

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Problem

Issue 1: URL without alias causes hang
When running adcp --save-auth https://url, the CLI treated the URL as the alias and entered interactive mode. The password prompt for auth token was hidden, making it appear to hang with no visible feedback.

Issue 2: Auth token silently skipped
When providing a URL on the command line, the auth token was silently skipped with no way to provide it non-interactively.

Solution

1. Clear Error Messages

  • Detect when URL is provided without alias
  • Show helpful error message with correct usage example

2. New Auth Flags

  • --auth <token> - Provide auth token for non-interactive mode
  • --no-auth - Explicitly skip auth for non-interactive mode
  • Interactive mode now always prompts for auth (can be left blank)

3. Improved Prompts

  • Password prompt now more visible (prints prompt text before hidden input)
  • Updated help text with clearer examples

New Behavior

# Non-interactive with auth
adcp --save-auth myagent https://url --auth token

# Non-interactive without auth
adcp --save-auth myagent https://url --no-auth

# Interactive (asks for protocol & auth)
adcp --save-auth myagent https://url

# Interactive (asks for URL, protocol & auth)
adcp --save-auth myagent

Test Plan

  • Test error message when URL provided without alias
  • Test non-interactive mode with --auth
  • Test non-interactive mode with --no-auth
  • Test interactive mode still prompts for auth
  • Test error when both --auth and --no-auth provided
  • Verify help text is clear

🤖 Generated with Claude Code

**Problem 1: URL without alias causes hang**
When running `adcp --save-auth https://url`, the CLI treated the URL as the
alias and entered interactive mode, asking for inputs with hidden password
prompts that appeared to hang.

**Problem 2: Auth token not requested in non-interactive mode**
When providing URL on command line, auth token was silently skipped with no
way to provide it non-interactively.

**Changes:**
- Detect when URL is provided without alias and show clear error message
- Add `--auth <token>` flag for non-interactive mode with authentication
- Add `--no-auth` flag for non-interactive mode without authentication
- Interactive mode now always prompts for auth token (can be left blank)
- Improve password prompt visibility by printing prompt before hidden input
- Update help text with clearer examples and usage patterns

**New Behavior:**
- `adcp --save-auth alias https://url --auth token` → Non-interactive with auth
- `adcp --save-auth alias https://url --no-auth` → Non-interactive without auth
- `adcp --save-auth alias https://url` → Interactive (asks for protocol & auth)
- `adcp --save-auth alias` → Interactive (asks for URL, protocol & auth)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@bokelley bokelley merged commit ce0477c into main Oct 25, 2025
7 checks passed
bokelley added a commit that referenced this pull request Nov 21, 2025
- Add buyer_ref validation for create_media_buy responses
- Add missing validations for build_creative, preview_creative, list_creatives
- Add null checks in unwrapper to prevent returning null as valid data
- Fix test data to include required buyer_ref field

Addresses code review feedback on PR #83

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Nov 23, 2025
* chore: add changeset for CLI fix

* fix: return raw AdCP responses from Agent class

BREAKING CHANGE: Agent class methods now return raw AdCP
responses matching schemas exactly, instead of wrapping them
in SDK-specific format.

Changes:
- Created unwrapProtocolResponse utility to extract AdCP data
  from MCP/A2A protocol wrappers
- Updated Agent class to return raw AdCP responses
  (discriminated union pattern)
- Responses follow AdCP spec: success has required fields,
  errors have errors array
- Added comprehensive tests for response unwrapping

Migration example in changeset file.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: update changeset to document both breaking changes

- Changed from patch to major version bump
- Added API export cleanup to changeset description
- Documented removal of internal protocol clients and utilities
- Updated migration guide with both response format and removed exports

* refactor: clean up SDK public API exports

Remove internal utilities and wildcard exports from public API:
- Removed ProtocolClient and protocol-level functions from exports
- Removed duplicate NewAgentCollection export
- Made auth and validation exports explicit (no wildcards)
- Added response unwrapping utilities to public API

Library exports now only include user-facing features with clear intent.

* chore: add helper scripts for auditing SDK exports

- audit-exports.js: categorize and detect suspicious exports
- list-types.js: list type exports and Zod schemas

These tools help maintain clean public API.

* fix: resolve TypeScript errors after rebase

- Fix ResponseValidator to only use existing response schemas
- Fix SingleAgentClient to only use existing request schemas
- Update index.ts exports: ADCPClient -> SingleAgentClient
- Fix server.ts imports and type annotations
- Add explicit types for Activity, NotificationMetadata, and response handlers

* chore: update package-lock.json after rebase

* fix: restore backward compatibility and fix schemas after rebase

- Add getAgentConfigs() alias to AdCPClient for test compatibility
- Add AdCPClient.fromEnv() static method
- Restore correct schemas.generated.ts from main (rebase dropped some schemas)

* fix: improve response validation and add null checks

- Add buyer_ref validation for create_media_buy responses
- Add missing validations for build_creative, preview_creative, list_creatives
- Add null checks in unwrapper to prevent returning null as valid data
- Fix test data to include required buyer_ref field

Addresses code review feedback on PR #83

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: update changeset from major to minor

This is a minor version change, not major:
- High-level clients (ADCPMultiAgentClient, AgentClient, SingleAgentClient) unchanged
- Only low-level Agent class response format changed
- Removed internal exports that shouldn't have been public
- Added helpful response utilities

Most users following documented patterns won't need any changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* style: fix prettier formatting

Auto-format code to pass CI prettier checks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: add CreativePolicy, PushNotificationConfig, CreativeFilters to Zod type list

These types were already being generated, but documenting them
explicitly in TOOL_TYPES for clarity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update glob dependency to resolve security vulnerability

npm audit fix updated packages to address CVE in glob package
(versions 10.2.0 - 10.4.5). No vulnerabilities remaining.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add missing ProvidePerformanceFeedback types to Zod generation

Added ProvidePerformanceFeedbackRequest1, ProvidePerformanceFeedbackRequest2,
MetricType, and FeedbackSource types to Zod schema generation. These were
required dependencies for the compound ProvidePerformanceFeedbackRequest type.

Fixes CI schema generation failures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: correct provide_performance_feedback success validation

Changed validation from checking non-existent status fields
to checking success === true, matching the actual schema.

The ProvidePerformanceFeedbackResponse schema is:
{ success: true, context?: {} } | { errors: [...], context?: {} }

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: AdCPClient constructor accepts config parameter

The backward compatibility AdCPClient wrapper now accepts an optional
config parameter (second argument) to match the original constructor
signature. This fixes failing tests for webhook URL templates and
webhook signature verification.

Fixes 22 test failures in CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add missing request validation schemas

Added validation schemas for get_products, create_media_buy, and sync_creatives
to ensure strict validation of request parameters before sending to agents.

This fixes 4 failing tests in test/lib/request-validation.test.js that expected
validation errors to be thrown for:
- sync_creatives with assets as array instead of object
- sync_creatives with mode parameter instead of dry_run
- create_media_buy with invalid top-level fields
- get_products with invalid fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: sync with upstream AdCP schema changes

Synced generated types with upstream AdCP v2.4.0 schema changes:
- Added PropertyID and PropertyTag type aliases
- Updated PublisherPropertySelector to use typed property_ids and property_tags
- Updated Property interface to use PropertyID and PropertyTag types
- Fixed duplicate type definitions in core.generated.ts

Changes from upstream:
- property-id.json and property-tag.json added as separate schema files
- Type-safe property identifiers and tags for better validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: deduplicate PropertyID and PropertyTag types across schemas

The json-schema-to-typescript compiler generates type definitions for each
schema independently, causing PropertyID and PropertyTag to be defined
multiple times (once in media-buy schema, once in property schema).

Added cross-schema type tracking to filter out duplicate definitions:
- Track generated types across all core schema compilations
- Use filterDuplicateTypeDefinitions for each schema
- Ensure first occurrence is kept, subsequent duplicates are filtered

This resolves TS2300 "Duplicate identifier" errors and ensures CI
validation passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update MAX_ALLOWED for AdCP v2.4.0 schema changes

AdCP v2.4.0 introduces provide_performance_feedback tool with a context
field, adding one additional index signature (29 vs 28).

The 29th signature comes from ProvidePerformanceFeedbackRequest2 which
has a context field that must preserve arbitrary properties per AdCP
protocol requirements for distributed tracing.

PropertyID and PropertyTag types are properly deduplicated across schemas
and do not contribute extra index signatures.

Updated MAX_ALLOWED threshold and documentation to reflect this change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: restore accidentally removed response validator schemas

Restored response validation for:
- list_creative_formats
- create_media_buy
- update_media_buy
- get_signals
- activate_signal

These schemas exist in the generated files and should be validated.
The removal was accidental and unrelated to the schema sync work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: handle HITL multi-artifact responses correctly

Problem:
- Real-world HITL responses contain 3 artifacts
- Previous implementation only extracted artifacts[0] (pending_human status)
- Actual AdCP response was in artifacts[1] (end_of_hitl artifact)
- This caused responses to return status info instead of actual data

Solution:
- Enhanced response-unwrapper.ts to intelligently find the correct artifact:
  1. Prioritize artifacts with "end_of_hitl-" or "end_of_" prefix
  2. Look for data parts with AdCP response fields (media_buy_id, packages, etc.)
  3. Skip HITL status artifacts (status: "pending_human", data: null)
  4. Fall back to first artifact if no matches
- Refactored TaskExecutor to use unwrapProtocolResponse() for consistency
- Added test covering real-world HITL 3-artifact structure

This fixes the issue where HITL workflows would return incorrect data.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: include human-readable messages from A2A text parts

Enhancement:
- A2A responses can include both text parts (human-readable messages)
  and data parts (structured AdCP response)
- Similar to MCP's content + structuredContent pattern
- Now extracts text from artifacts and includes as _message field

Implementation:
- Helper function extractFromArtifact() processes both text and data parts
- Concatenates multiple text parts with newlines
- Adds _message field to response when text parts exist
- Maintains backward compatibility (no breaking changes)

Example output:
{
  media_buy_id: "123",
  packages: [...],
  _message: "✅ Media Buy Created Successfully"
}

This matches MCP's pattern of providing both structured data
and human-readable content for display/logging purposes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test: add real-world client HITL response test case

- Uses exact production HITL response with 3 artifacts
- Validates extraction from end_of_hitl artifact (not first or third)
- Verifies all 5 packages extracted correctly
- Confirms message field extracted from text part
- Ensures HITL status and ADK wrapper fields filtered out

* refactor: simplify artifact extraction to focus on completion status

- Remove artifact naming conventions (end_of_hitl-, etc.)
- Extract from first completed artifact with AdCP response fields
- Remove fallback behavior - throw error if no completed artifact found
- Clearer logic: 'first data part of first completed artifact'
- This should be documented in AdCP spec upstream

* refactor: use proper schema validation for A2A artifact responses

Replace hardcoded field checking with tool-specific schema validation
to properly distinguish between intermediate HITL artifacts and completed
AdCP responses. This eliminates the need to maintain a hardcoded field
list and ensures validation works for all current and future AdCP tools.

Changes:
- response-unwrapper: Use isAdcpSuccess() with tool name for validation
- TaskExecutor: Pass taskName through to unwrapper for proper validation
- Tests: Update A2A test calls to pass appropriate tool names

Benefits:
- Validates against full AdCP schemas (13 tools) instead of 6 fields
- Automatically supports new AdCP tools added to isAdcpSuccess()
- Explicit errors instead of fallback behavior
- No more maintenance burden of hardcoded field lists

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: pass toolName for proper AdCP schema validation

Changes:
- Updated unwrapProtocolResponse() to require toolName parameter for A2A validation
- Modified isCompletedResponse() to use isAdcpSuccess() for proper schema checks
- Added test helper exports to main index for convenience
- Updated all test calls to pass appropriate tool names

Why:
- Replaces hardcoded field checking with proper schema validation
- Enables validation of all 13 AdCP tool types (not just 6 fields)
- Explicitly fails when toolName missing (no fallbacks)
- Fixes Response Unwrapper and Test Helpers CI failures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: export detectProtocol functions from main API

The protocol-detection tests were failing because detectProtocol and
detectProtocolWithTimeout were not exported from the library's main
index, even though they existed in src/lib/utils/protocol-detection.ts.

Added exports to:
- src/lib/utils/index.ts (barrel export)
- src/lib/index.ts (main API export)

This fixes the "7 subtests failed" error in Protocol Detection Tests.

* fix: add missing kind field to A2A test data

The response-unwrapper test was failing because the A2A artifact part was
missing the required 'kind' field. A2A protocol requires parts to have:
  { kind: 'data', data: {...} }

Not just:
  { data: {...} }

The unwrapper code checks for p.kind === 'data' so the test data needs
to match the actual A2A protocol structure.

* style: run prettier on modified files

* fix: handle empty A2A artifacts array gracefully

- Modified unwrapProtocolResponse() to return { artifacts: [] } for empty artifacts
- Added logging in TaskExecutor for empty artifacts case
- Fixes test 'should handle empty A2A artifacts gracefully'

* fix: detect and unwrap framework-wrapped A2A responses (e.g., ADK FunctionResponse)

- Add framework wrapper detection in unwrapProtocolResponse() for {id, name, response} pattern
- Extract nested response data while preserving wrapper metadata for logging
- Add framework wrapper logging in TaskExecutor with format detection
- Clean up internal _frameworkWrapper metadata before returning extracted data
- Fixes artifact-extraction test: 'should extract data from framework-wrapped responses'

* fix: improve artifact extraction edge case handling

- Made A2A artifact 'kind' field optional (defaults to 'data')
- Added explicit handling for response.data field
- Updated fallback logging to include responseKeys for debugging

Fixes tests:
- should extract the same data from both protocol formats
- should handle responses with only response.data field
- should fallback to full response when no standard structure found

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: debug logging before unwrapping and AdCPClient alias

Test #6 fix: Restructured extractResponseData() to log artifact details
(artifactCount, partCount, dataKeys) BEFORE calling unwrapProtocolResponse().
This ensures debug logs are created even when validation fails.

Test #7 fix: Changed AdCPClient from wrapper class to simple alias of
ADCPMultiAgentClient, making them identical references for backward
compatibility.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: sync version with AdCP 2.4.0 schemas

Ran schema sync commands to fix CI validation failure:
- npm run sync-schemas
- npm run sync-version --auto-update
- npm run generate-types

Generated types were already up to date. Only version.ts needed update
to reflect AdCP 2.4.0 schema version.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: improve response unwrapper type safety and A2A spec compliance

This commit refactors the response-unwrapper to add proper TypeScript
typing, Zod validation, and correct A2A artifact handling.

**Key Changes:**

1. **Type Safety**
   - Added `AdCPResponse` union type covering all 13 response schemas
   - Added Zod validation with tool-specific schemas
   - Updated function signatures to return typed responses

2. **Protocol Metadata Extraction**
   - Both MCP and A2A now extract text messages to `_message` field
   - MCP: extracts from `content` array with type='text'
   - A2A: extracts from TextParts (kind='text')
   - Protocol metadata preserved after Zod validation

3. **A2A Spec Compliance**
   - Verified artifacts don't have status fields (only Tasks do)
   - Changed to take **last artifact** (conversational protocol pattern)
   - Simplified unwrapper from ~60 to ~35 lines
   - Based on AdCP spec: completed Task → all artifacts completed

4. **Test Updates**
   - Created test-fixtures.js with spec-compliant test data
   - Updated response-unwrapper tests with comprehensive coverage
   - Disabled obsolete artifact-extraction tests (renamed to .old)

**Breaking Changes:**
- unwrapProtocolResponse now accepts optional protocol parameter
- Response validation now strict with Zod schemas

**A2A Findings:**
Per @a2a-js/sdk TypeScript definitions, Artifact interface has no
`status` field. Only Task objects have status. The assumption that
"no status means completed" was incorrect - artifacts simply don't
have that field.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: enhance response-unwrapper with comprehensive validation and error handling

This commit adds extensive test coverage, improved error handling, and better
validation for the response-unwrapper utility.

**Key Enhancements:**

1. **Intermediate Status Rejection**
   - Added validation to reject A2A responses with intermediate statuses
   - Throws clear errors for "working", "submitted", "input-required" states
   - Ensures unwrapper only processes completed Task responses

2. **Improved Error Messages**
   - Include text snippets in MCP parsing errors for better debugging
   - Truncate long text to prevent error message bloat
   - Use error code constants (ERROR_CODES.MCP_ERROR, etc.)

3. **Protocol Detection Edge Cases**
   - Handle empty response objects
   - Detect ambiguous responses with both MCP and A2A fields
   - Prioritize MCP when both protocol indicators present

4. **Zod Validation Improvements**
   - Use z.intersection to preserve _message field after validation
   - Simplifies validation logic (no manual extract/reattach)
   - Better type safety with wrapper schema

5. **Conversational Protocol Consistency**
   - Take last DataPart within artifact (matches last artifact logic)
   - Handles cases where artifacts have multiple data parts
   - Consistent with conversational protocol append pattern

6. **Comprehensive Test Coverage (35 tests total)**
   - Intermediate status rejection tests (3 tests)
   - Protocol auto-detection edge cases (5 tests)
   - A2A spec compliance tests (4 tests)
   - Error handling and validation tests (8 tests)
   - Performance test with 150 artifacts
   - Malformed data part tests

7. **Test Fixtures Enhancement**
   - Added createTestPackage() for media buy testing
   - All fixtures now spec-compliant with required fields

8. **Code Documentation**
   - Added TYPE SAFETY TRADE-OFF ANALYSIS comment
   - Explains why we use current approach vs alternatives
   - Documents rationale for schema casting

**Breaking Changes:**
- unwrapA2AResponse now throws for intermediate statuses
- isAdcpSuccess now uses Zod validation instead of manual checks

**A2A Spec Clarifications:**
- Confirmed: Artifacts have no status field per @a2a-js/sdk
- Task.status.state indicates completion, not artifact status
- Last artifact approach is correct for conversational protocols

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add version functions and fix schema sync for versioned paths

Added getAdcpVersion() and getLibraryVersion() functions to public API
to expose version information programmatically.

Updated sync-schemas to:
- Use ADCP_VERSION from version.ts as source of truth
- Fetch versioned schema index (schemas/2.4.0/index.json)
- Handle versioned schema paths (/schemas/2.4.0/...) correctly
- Cache schemas in flat structure (cache/2.4.0/core/...)

This fixes CI schema synchronization issues where schemas were being
cached in nested directories (cache/2.4.0/schemas/2.4.0/core/...)
due to incorrect path stripping logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: make ADCP_VERSION file the source of truth for schema versioning

Changes:
- Add ADCP_VERSION file as the definitive source of truth for target schema version
- Update sync-schemas.ts to read from ADCP_VERSION file instead of importing from version.ts
- Update sync-version.ts to read from ADCP_VERSION file instead of schema index
- Remove ADCP_VERSION from .gitignore (should be committed)

This enables explicit version control - we decide what version/alias (e.g., "2.4.0" or "v2")
to download rather than following "latest" from adcontextprotocol.org.

Workflow:
1. ADCP_VERSION file contains target version (e.g., "2.4.0" or "v2")
2. sync-schemas reads ADCP_VERSION, downloads schemas from /schemas/{version}/
3. sync-version reads ADCP_VERSION, updates package.json and src/lib/version.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: include version getter functions in generated version.ts

Update sync-version.ts to include getAdcpVersion() and getLibraryVersion()
functions in the generated version.ts file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: handle versioned schema $ref paths in type generation

Update generate-types.ts to properly resolve schema $refs with versioned
paths like /schemas/2.4.0/ in addition to /schemas/v1/.

Changes:
- loadCachedSchema() now strips any version prefix (v1 or X.Y.Z) when looking up cached schemas
- refResolver instances now accept any /schemas/ path instead of only /schemas/v1/
- Generated types updated with proper $ref resolution

This fixes CI failures where type generation couldn't find schemas because:
- sync-schemas caches in flat structure: cache/2.4.0/core/product.json
- Schema $refs use versioned paths: /schemas/2.4.0/core/product.json
- Type generator needs to strip version prefix when loading from cache

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: make Zod schema generation warnings non-fatal

Some AdCP response types use complex discriminated unions that ts-to-zod
cannot convert to Zod schemas. This is acceptable because:

1. TypeScript types provide compile-time validation
2. Runtime validation is optional for these specific tools
3. The generated TypeScript types are correct and compile successfully

Changes:
- Updated generate-zod-from-ts.ts to log warnings instead of exiting with error
- Commented out sync_creatives and preview_creative schema references
- Updated error messaging to explain this is non-fatal and expected

The 6 schemas that cannot be generated (SyncCreativesResponse variants and
PreviewCreative variants) will skip runtime validation but retain TypeScript
type safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add manual Zod schemas for discriminated union types

Added manually-defined Zod schemas for PreviewCreativeRequest,
PreviewCreativeResponse, and SyncCreativesResponse types that ts-to-zod
cannot generate due to complex discriminated unions.

Key changes:
- Added PreviewCreativeRequestSchema with request_type discriminator (single/batch)
- Added PreviewCreativeResponseSchema as union (response_type + errors)
- Added SyncCreativesResponseSchema as union (success fields + errors)
- Updated response-unwrapper.ts and ResponseValidator.ts to use the new schemas

This provides runtime validation for these complex types while maintaining
TypeScript compile-time type safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: sync schemas after upstream format-id.json fix (PR #246)

Upstream PR adcontextprotocol/adcp#246 fixed the format-id schema by:
- Moving width/height dimensions directly into schema properties
- Using JSON Schema `dependencies` keyword instead of complex allOf/oneOf
- Eliminating intersection types that caused code generation issues

Changes:
- Regenerated TypeScript types - now clean FormatID interface (no numbered variants)
- Regenerated Zod schemas - all 92 schemas generated successfully
- Fixed CreativeAgentClient.findByDimensions() to handle union type properly
- Added UPSTREAM-SCHEMA-RECOMMENDATIONS.md documenting schema patterns

Result:
- ✅ FormatID is now a single clean type with optional width/height
- ✅ All Zod schemas generate automatically (no ts-to-zod errors)
- ✅ Build passes with no TypeScript errors
- ✅ Ready for CI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add dimensions.json schema to cache (force-add)

The sync-schemas script isn't automatically downloading dimensions.json
even though it's referenced by format-id.json. Force-adding it to bypass
.gitignore so CI can generate types properly.

This schema defines width/height pixel dimensions used by format-id.json
and other visual asset schemas.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update test data to match schema requirements

- Add complete Product objects with all required fields
  - name, description, publisher_properties, format_ids
  - delivery_type, pricing_options (with is_fixed flag)
  - delivery_measurement
- Add complete Creative objects for list_creatives tests
  - creative_id, name, format_id, status
  - created_date, updated_date
- Add query_summary and pagination to list_creatives response
- Create helper functions for test fixtures (createValidProduct, createValidCreative)

Zod validation now properly validates test data against schemas.

* fix: unwrap nested response field in A2A data parts

Some agents wrap AdCP responses in an extra { response: { ... } } layer.
This fix detects and unwraps that nested structure before validation.

- Add unwrapping logic in unwrapA2AResponse for nested response objects
- Add test case for nested response unwrapping
- Remove UPSTREAM-SCHEMA-RECOMMENDATIONS.md (upstream fixes merged)

Fixes issue where Yahoo agent returns:
  { data: { response: { products: [...] } } }
instead of:
  { data: { products: [...] } }

* fix: make sync-schemas recursively download nested $ref dependencies

Previously, the script only downloaded one level of nested refs, which meant
that schemas referenced by other schemas (like dimensions.json) were missed.

Changes:
- Convert single-pass nested ref download to recursive loop (max depth 10)
- Track all downloaded refs to avoid re-downloading
- Continue until no new refs are found at current depth
- Log depth level for visibility

Testing:
- Removed dimensions.json from cache
- Ran sync-schemas
- Verified dimensions.json downloaded at depth 2
- Build passes with dynamically downloaded schemas

Result:
- dimensions.json automatically downloaded (found at depth 2)
- Removed force-committed dimensions.json from git tracking
- Schema cache directory remains gitignored as intended

* style: fix Prettier formatting in sync-schemas.ts

* feat: use AdCP v2 branch for schemas and fix schema path handling

Changes:
- Update ADCP_VERSION from 2.4.0 to v2 (tracks latest 2.x.x)
- Fix sync-schemas to properly handle version-agnostic  paths
  - Schemas contain `/schemas/2.4.0/` refs regardless of branch version
  - Strip version segment to get proper relative path
  - Maintain directory structure (core/, media-buy/, etc.)
- Fix generate-types to read  from index.json instead of hardcoding
  - loadToolSchema now reads task. from index
  - loadCoreSchema now reads schema. from index
  - No more hardcoded `/schemas/v1/` paths
- Update package.json adcp_version to v2
- Regenerate types with v2 schemas (same as 2.4.0 but tracks branch)

Benefits:
- Using v2 means we automatically get latest 2.x.x patches
- Schema sync works with any version format (v1, v2, X.Y.Z)
- Type generation no longer depends on hardcoded version paths

Testing:
- Synced schemas with v2 branch
- Generated types successfully (92 Zod schemas)
- Build passes
- Schemas properly organized in core/, media-buy/, creative/, etc.

* feat: upgrade to AdCP 2.5.0 schema

- Updated ADCP_VERSION from v2 to 2.5.0
- Synced schemas from adcontextprotocol.org
- Regenerated TypeScript types from 2.5.0 schemas
- Updated package.json adcp_version field
- Library version remains 3.1.0

This allows the client to automatically pick up patch updates
in the 2.5.x series without requiring code changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* style: fix prettier formatting in version.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: use v2.5 alias for automatic patch version tracking

Updated ADCP_VERSION from 2.5.0 to v2.5 to use the upstream
symlink alias. This allows the client to automatically pick up
patch releases (2.5.1, 2.5.2, etc.) without code changes.

The v2.5 alias points to the latest 2.5.x release on
adcontextprotocol.org.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* style: fix prettier formatting in version.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
youbek pushed a commit to youbek/adcp-client that referenced this pull request Dec 10, 2025
…rotocol#145)

* chore: add changeset for CLI fix

* fix: return raw AdCP responses from Agent class

BREAKING CHANGE: Agent class methods now return raw AdCP
responses matching schemas exactly, instead of wrapping them
in SDK-specific format.

Changes:
- Created unwrapProtocolResponse utility to extract AdCP data
  from MCP/A2A protocol wrappers
- Updated Agent class to return raw AdCP responses
  (discriminated union pattern)
- Responses follow AdCP spec: success has required fields,
  errors have errors array
- Added comprehensive tests for response unwrapping

Migration example in changeset file.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: update changeset to document both breaking changes

- Changed from patch to major version bump
- Added API export cleanup to changeset description
- Documented removal of internal protocol clients and utilities
- Updated migration guide with both response format and removed exports

* refactor: clean up SDK public API exports

Remove internal utilities and wildcard exports from public API:
- Removed ProtocolClient and protocol-level functions from exports
- Removed duplicate NewAgentCollection export
- Made auth and validation exports explicit (no wildcards)
- Added response unwrapping utilities to public API

Library exports now only include user-facing features with clear intent.

* chore: add helper scripts for auditing SDK exports

- audit-exports.js: categorize and detect suspicious exports
- list-types.js: list type exports and Zod schemas

These tools help maintain clean public API.

* fix: resolve TypeScript errors after rebase

- Fix ResponseValidator to only use existing response schemas
- Fix SingleAgentClient to only use existing request schemas
- Update index.ts exports: ADCPClient -> SingleAgentClient
- Fix server.ts imports and type annotations
- Add explicit types for Activity, NotificationMetadata, and response handlers

* chore: update package-lock.json after rebase

* fix: restore backward compatibility and fix schemas after rebase

- Add getAgentConfigs() alias to AdCPClient for test compatibility
- Add AdCPClient.fromEnv() static method
- Restore correct schemas.generated.ts from main (rebase dropped some schemas)

* fix: improve response validation and add null checks

- Add buyer_ref validation for create_media_buy responses
- Add missing validations for build_creative, preview_creative, list_creatives
- Add null checks in unwrapper to prevent returning null as valid data
- Fix test data to include required buyer_ref field

Addresses code review feedback on PR adcontextprotocol#83

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: update changeset from major to minor

This is a minor version change, not major:
- High-level clients (ADCPMultiAgentClient, AgentClient, SingleAgentClient) unchanged
- Only low-level Agent class response format changed
- Removed internal exports that shouldn't have been public
- Added helpful response utilities

Most users following documented patterns won't need any changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* style: fix prettier formatting

Auto-format code to pass CI prettier checks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: add CreativePolicy, PushNotificationConfig, CreativeFilters to Zod type list

These types were already being generated, but documenting them
explicitly in TOOL_TYPES for clarity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update glob dependency to resolve security vulnerability

npm audit fix updated packages to address CVE in glob package
(versions 10.2.0 - 10.4.5). No vulnerabilities remaining.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add missing ProvidePerformanceFeedback types to Zod generation

Added ProvidePerformanceFeedbackRequest1, ProvidePerformanceFeedbackRequest2,
MetricType, and FeedbackSource types to Zod schema generation. These were
required dependencies for the compound ProvidePerformanceFeedbackRequest type.

Fixes CI schema generation failures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: correct provide_performance_feedback success validation

Changed validation from checking non-existent status fields
to checking success === true, matching the actual schema.

The ProvidePerformanceFeedbackResponse schema is:
{ success: true, context?: {} } | { errors: [...], context?: {} }

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: AdCPClient constructor accepts config parameter

The backward compatibility AdCPClient wrapper now accepts an optional
config parameter (second argument) to match the original constructor
signature. This fixes failing tests for webhook URL templates and
webhook signature verification.

Fixes 22 test failures in CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add missing request validation schemas

Added validation schemas for get_products, create_media_buy, and sync_creatives
to ensure strict validation of request parameters before sending to agents.

This fixes 4 failing tests in test/lib/request-validation.test.js that expected
validation errors to be thrown for:
- sync_creatives with assets as array instead of object
- sync_creatives with mode parameter instead of dry_run
- create_media_buy with invalid top-level fields
- get_products with invalid fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: sync with upstream AdCP schema changes

Synced generated types with upstream AdCP v2.4.0 schema changes:
- Added PropertyID and PropertyTag type aliases
- Updated PublisherPropertySelector to use typed property_ids and property_tags
- Updated Property interface to use PropertyID and PropertyTag types
- Fixed duplicate type definitions in core.generated.ts

Changes from upstream:
- property-id.json and property-tag.json added as separate schema files
- Type-safe property identifiers and tags for better validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: deduplicate PropertyID and PropertyTag types across schemas

The json-schema-to-typescript compiler generates type definitions for each
schema independently, causing PropertyID and PropertyTag to be defined
multiple times (once in media-buy schema, once in property schema).

Added cross-schema type tracking to filter out duplicate definitions:
- Track generated types across all core schema compilations
- Use filterDuplicateTypeDefinitions for each schema
- Ensure first occurrence is kept, subsequent duplicates are filtered

This resolves TS2300 "Duplicate identifier" errors and ensures CI
validation passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update MAX_ALLOWED for AdCP v2.4.0 schema changes

AdCP v2.4.0 introduces provide_performance_feedback tool with a context
field, adding one additional index signature (29 vs 28).

The 29th signature comes from ProvidePerformanceFeedbackRequest2 which
has a context field that must preserve arbitrary properties per AdCP
protocol requirements for distributed tracing.

PropertyID and PropertyTag types are properly deduplicated across schemas
and do not contribute extra index signatures.

Updated MAX_ALLOWED threshold and documentation to reflect this change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: restore accidentally removed response validator schemas

Restored response validation for:
- list_creative_formats
- create_media_buy
- update_media_buy
- get_signals
- activate_signal

These schemas exist in the generated files and should be validated.
The removal was accidental and unrelated to the schema sync work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: handle HITL multi-artifact responses correctly

Problem:
- Real-world HITL responses contain 3 artifacts
- Previous implementation only extracted artifacts[0] (pending_human status)
- Actual AdCP response was in artifacts[1] (end_of_hitl artifact)
- This caused responses to return status info instead of actual data

Solution:
- Enhanced response-unwrapper.ts to intelligently find the correct artifact:
  1. Prioritize artifacts with "end_of_hitl-" or "end_of_" prefix
  2. Look for data parts with AdCP response fields (media_buy_id, packages, etc.)
  3. Skip HITL status artifacts (status: "pending_human", data: null)
  4. Fall back to first artifact if no matches
- Refactored TaskExecutor to use unwrapProtocolResponse() for consistency
- Added test covering real-world HITL 3-artifact structure

This fixes the issue where HITL workflows would return incorrect data.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: include human-readable messages from A2A text parts

Enhancement:
- A2A responses can include both text parts (human-readable messages)
  and data parts (structured AdCP response)
- Similar to MCP's content + structuredContent pattern
- Now extracts text from artifacts and includes as _message field

Implementation:
- Helper function extractFromArtifact() processes both text and data parts
- Concatenates multiple text parts with newlines
- Adds _message field to response when text parts exist
- Maintains backward compatibility (no breaking changes)

Example output:
{
  media_buy_id: "123",
  packages: [...],
  _message: "✅ Media Buy Created Successfully"
}

This matches MCP's pattern of providing both structured data
and human-readable content for display/logging purposes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test: add real-world client HITL response test case

- Uses exact production HITL response with 3 artifacts
- Validates extraction from end_of_hitl artifact (not first or third)
- Verifies all 5 packages extracted correctly
- Confirms message field extracted from text part
- Ensures HITL status and ADK wrapper fields filtered out

* refactor: simplify artifact extraction to focus on completion status

- Remove artifact naming conventions (end_of_hitl-, etc.)
- Extract from first completed artifact with AdCP response fields
- Remove fallback behavior - throw error if no completed artifact found
- Clearer logic: 'first data part of first completed artifact'
- This should be documented in AdCP spec upstream

* refactor: use proper schema validation for A2A artifact responses

Replace hardcoded field checking with tool-specific schema validation
to properly distinguish between intermediate HITL artifacts and completed
AdCP responses. This eliminates the need to maintain a hardcoded field
list and ensures validation works for all current and future AdCP tools.

Changes:
- response-unwrapper: Use isAdcpSuccess() with tool name for validation
- TaskExecutor: Pass taskName through to unwrapper for proper validation
- Tests: Update A2A test calls to pass appropriate tool names

Benefits:
- Validates against full AdCP schemas (13 tools) instead of 6 fields
- Automatically supports new AdCP tools added to isAdcpSuccess()
- Explicit errors instead of fallback behavior
- No more maintenance burden of hardcoded field lists

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: pass toolName for proper AdCP schema validation

Changes:
- Updated unwrapProtocolResponse() to require toolName parameter for A2A validation
- Modified isCompletedResponse() to use isAdcpSuccess() for proper schema checks
- Added test helper exports to main index for convenience
- Updated all test calls to pass appropriate tool names

Why:
- Replaces hardcoded field checking with proper schema validation
- Enables validation of all 13 AdCP tool types (not just 6 fields)
- Explicitly fails when toolName missing (no fallbacks)
- Fixes Response Unwrapper and Test Helpers CI failures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: export detectProtocol functions from main API

The protocol-detection tests were failing because detectProtocol and
detectProtocolWithTimeout were not exported from the library's main
index, even though they existed in src/lib/utils/protocol-detection.ts.

Added exports to:
- src/lib/utils/index.ts (barrel export)
- src/lib/index.ts (main API export)

This fixes the "7 subtests failed" error in Protocol Detection Tests.

* fix: add missing kind field to A2A test data

The response-unwrapper test was failing because the A2A artifact part was
missing the required 'kind' field. A2A protocol requires parts to have:
  { kind: 'data', data: {...} }

Not just:
  { data: {...} }

The unwrapper code checks for p.kind === 'data' so the test data needs
to match the actual A2A protocol structure.

* style: run prettier on modified files

* fix: handle empty A2A artifacts array gracefully

- Modified unwrapProtocolResponse() to return { artifacts: [] } for empty artifacts
- Added logging in TaskExecutor for empty artifacts case
- Fixes test 'should handle empty A2A artifacts gracefully'

* fix: detect and unwrap framework-wrapped A2A responses (e.g., ADK FunctionResponse)

- Add framework wrapper detection in unwrapProtocolResponse() for {id, name, response} pattern
- Extract nested response data while preserving wrapper metadata for logging
- Add framework wrapper logging in TaskExecutor with format detection
- Clean up internal _frameworkWrapper metadata before returning extracted data
- Fixes artifact-extraction test: 'should extract data from framework-wrapped responses'

* fix: improve artifact extraction edge case handling

- Made A2A artifact 'kind' field optional (defaults to 'data')
- Added explicit handling for response.data field
- Updated fallback logging to include responseKeys for debugging

Fixes tests:
- should extract the same data from both protocol formats
- should handle responses with only response.data field
- should fallback to full response when no standard structure found

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: debug logging before unwrapping and AdCPClient alias

Test adcontextprotocol#6 fix: Restructured extractResponseData() to log artifact details
(artifactCount, partCount, dataKeys) BEFORE calling unwrapProtocolResponse().
This ensures debug logs are created even when validation fails.

Test adcontextprotocol#7 fix: Changed AdCPClient from wrapper class to simple alias of
ADCPMultiAgentClient, making them identical references for backward
compatibility.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: sync version with AdCP 2.4.0 schemas

Ran schema sync commands to fix CI validation failure:
- npm run sync-schemas
- npm run sync-version --auto-update
- npm run generate-types

Generated types were already up to date. Only version.ts needed update
to reflect AdCP 2.4.0 schema version.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: improve response unwrapper type safety and A2A spec compliance

This commit refactors the response-unwrapper to add proper TypeScript
typing, Zod validation, and correct A2A artifact handling.

**Key Changes:**

1. **Type Safety**
   - Added `AdCPResponse` union type covering all 13 response schemas
   - Added Zod validation with tool-specific schemas
   - Updated function signatures to return typed responses

2. **Protocol Metadata Extraction**
   - Both MCP and A2A now extract text messages to `_message` field
   - MCP: extracts from `content` array with type='text'
   - A2A: extracts from TextParts (kind='text')
   - Protocol metadata preserved after Zod validation

3. **A2A Spec Compliance**
   - Verified artifacts don't have status fields (only Tasks do)
   - Changed to take **last artifact** (conversational protocol pattern)
   - Simplified unwrapper from ~60 to ~35 lines
   - Based on AdCP spec: completed Task → all artifacts completed

4. **Test Updates**
   - Created test-fixtures.js with spec-compliant test data
   - Updated response-unwrapper tests with comprehensive coverage
   - Disabled obsolete artifact-extraction tests (renamed to .old)

**Breaking Changes:**
- unwrapProtocolResponse now accepts optional protocol parameter
- Response validation now strict with Zod schemas

**A2A Findings:**
Per @a2a-js/sdk TypeScript definitions, Artifact interface has no
`status` field. Only Task objects have status. The assumption that
"no status means completed" was incorrect - artifacts simply don't
have that field.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: enhance response-unwrapper with comprehensive validation and error handling

This commit adds extensive test coverage, improved error handling, and better
validation for the response-unwrapper utility.

**Key Enhancements:**

1. **Intermediate Status Rejection**
   - Added validation to reject A2A responses with intermediate statuses
   - Throws clear errors for "working", "submitted", "input-required" states
   - Ensures unwrapper only processes completed Task responses

2. **Improved Error Messages**
   - Include text snippets in MCP parsing errors for better debugging
   - Truncate long text to prevent error message bloat
   - Use error code constants (ERROR_CODES.MCP_ERROR, etc.)

3. **Protocol Detection Edge Cases**
   - Handle empty response objects
   - Detect ambiguous responses with both MCP and A2A fields
   - Prioritize MCP when both protocol indicators present

4. **Zod Validation Improvements**
   - Use z.intersection to preserve _message field after validation
   - Simplifies validation logic (no manual extract/reattach)
   - Better type safety with wrapper schema

5. **Conversational Protocol Consistency**
   - Take last DataPart within artifact (matches last artifact logic)
   - Handles cases where artifacts have multiple data parts
   - Consistent with conversational protocol append pattern

6. **Comprehensive Test Coverage (35 tests total)**
   - Intermediate status rejection tests (3 tests)
   - Protocol auto-detection edge cases (5 tests)
   - A2A spec compliance tests (4 tests)
   - Error handling and validation tests (8 tests)
   - Performance test with 150 artifacts
   - Malformed data part tests

7. **Test Fixtures Enhancement**
   - Added createTestPackage() for media buy testing
   - All fixtures now spec-compliant with required fields

8. **Code Documentation**
   - Added TYPE SAFETY TRADE-OFF ANALYSIS comment
   - Explains why we use current approach vs alternatives
   - Documents rationale for schema casting

**Breaking Changes:**
- unwrapA2AResponse now throws for intermediate statuses
- isAdcpSuccess now uses Zod validation instead of manual checks

**A2A Spec Clarifications:**
- Confirmed: Artifacts have no status field per @a2a-js/sdk
- Task.status.state indicates completion, not artifact status
- Last artifact approach is correct for conversational protocols

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: add version functions and fix schema sync for versioned paths

Added getAdcpVersion() and getLibraryVersion() functions to public API
to expose version information programmatically.

Updated sync-schemas to:
- Use ADCP_VERSION from version.ts as source of truth
- Fetch versioned schema index (schemas/2.4.0/index.json)
- Handle versioned schema paths (/schemas/2.4.0/...) correctly
- Cache schemas in flat structure (cache/2.4.0/core/...)

This fixes CI schema synchronization issues where schemas were being
cached in nested directories (cache/2.4.0/schemas/2.4.0/core/...)
due to incorrect path stripping logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: make ADCP_VERSION file the source of truth for schema versioning

Changes:
- Add ADCP_VERSION file as the definitive source of truth for target schema version
- Update sync-schemas.ts to read from ADCP_VERSION file instead of importing from version.ts
- Update sync-version.ts to read from ADCP_VERSION file instead of schema index
- Remove ADCP_VERSION from .gitignore (should be committed)

This enables explicit version control - we decide what version/alias (e.g., "2.4.0" or "v2")
to download rather than following "latest" from adcontextprotocol.org.

Workflow:
1. ADCP_VERSION file contains target version (e.g., "2.4.0" or "v2")
2. sync-schemas reads ADCP_VERSION, downloads schemas from /schemas/{version}/
3. sync-version reads ADCP_VERSION, updates package.json and src/lib/version.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: include version getter functions in generated version.ts

Update sync-version.ts to include getAdcpVersion() and getLibraryVersion()
functions in the generated version.ts file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: handle versioned schema $ref paths in type generation

Update generate-types.ts to properly resolve schema $refs with versioned
paths like /schemas/2.4.0/ in addition to /schemas/v1/.

Changes:
- loadCachedSchema() now strips any version prefix (v1 or X.Y.Z) when looking up cached schemas
- refResolver instances now accept any /schemas/ path instead of only /schemas/v1/
- Generated types updated with proper $ref resolution

This fixes CI failures where type generation couldn't find schemas because:
- sync-schemas caches in flat structure: cache/2.4.0/core/product.json
- Schema $refs use versioned paths: /schemas/2.4.0/core/product.json
- Type generator needs to strip version prefix when loading from cache

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: make Zod schema generation warnings non-fatal

Some AdCP response types use complex discriminated unions that ts-to-zod
cannot convert to Zod schemas. This is acceptable because:

1. TypeScript types provide compile-time validation
2. Runtime validation is optional for these specific tools
3. The generated TypeScript types are correct and compile successfully

Changes:
- Updated generate-zod-from-ts.ts to log warnings instead of exiting with error
- Commented out sync_creatives and preview_creative schema references
- Updated error messaging to explain this is non-fatal and expected

The 6 schemas that cannot be generated (SyncCreativesResponse variants and
PreviewCreative variants) will skip runtime validation but retain TypeScript
type safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add manual Zod schemas for discriminated union types

Added manually-defined Zod schemas for PreviewCreativeRequest,
PreviewCreativeResponse, and SyncCreativesResponse types that ts-to-zod
cannot generate due to complex discriminated unions.

Key changes:
- Added PreviewCreativeRequestSchema with request_type discriminator (single/batch)
- Added PreviewCreativeResponseSchema as union (response_type + errors)
- Added SyncCreativesResponseSchema as union (success fields + errors)
- Updated response-unwrapper.ts and ResponseValidator.ts to use the new schemas

This provides runtime validation for these complex types while maintaining
TypeScript compile-time type safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: sync schemas after upstream format-id.json fix (PR adcontextprotocol#246)

Upstream PR adcontextprotocol/adcp#246 fixed the format-id schema by:
- Moving width/height dimensions directly into schema properties
- Using JSON Schema `dependencies` keyword instead of complex allOf/oneOf
- Eliminating intersection types that caused code generation issues

Changes:
- Regenerated TypeScript types - now clean FormatID interface (no numbered variants)
- Regenerated Zod schemas - all 92 schemas generated successfully
- Fixed CreativeAgentClient.findByDimensions() to handle union type properly
- Added UPSTREAM-SCHEMA-RECOMMENDATIONS.md documenting schema patterns

Result:
- ✅ FormatID is now a single clean type with optional width/height
- ✅ All Zod schemas generate automatically (no ts-to-zod errors)
- ✅ Build passes with no TypeScript errors
- ✅ Ready for CI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: add dimensions.json schema to cache (force-add)

The sync-schemas script isn't automatically downloading dimensions.json
even though it's referenced by format-id.json. Force-adding it to bypass
.gitignore so CI can generate types properly.

This schema defines width/height pixel dimensions used by format-id.json
and other visual asset schemas.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update test data to match schema requirements

- Add complete Product objects with all required fields
  - name, description, publisher_properties, format_ids
  - delivery_type, pricing_options (with is_fixed flag)
  - delivery_measurement
- Add complete Creative objects for list_creatives tests
  - creative_id, name, format_id, status
  - created_date, updated_date
- Add query_summary and pagination to list_creatives response
- Create helper functions for test fixtures (createValidProduct, createValidCreative)

Zod validation now properly validates test data against schemas.

* fix: unwrap nested response field in A2A data parts

Some agents wrap AdCP responses in an extra { response: { ... } } layer.
This fix detects and unwraps that nested structure before validation.

- Add unwrapping logic in unwrapA2AResponse for nested response objects
- Add test case for nested response unwrapping
- Remove UPSTREAM-SCHEMA-RECOMMENDATIONS.md (upstream fixes merged)

Fixes issue where Yahoo agent returns:
  { data: { response: { products: [...] } } }
instead of:
  { data: { products: [...] } }

* fix: make sync-schemas recursively download nested $ref dependencies

Previously, the script only downloaded one level of nested refs, which meant
that schemas referenced by other schemas (like dimensions.json) were missed.

Changes:
- Convert single-pass nested ref download to recursive loop (max depth 10)
- Track all downloaded refs to avoid re-downloading
- Continue until no new refs are found at current depth
- Log depth level for visibility

Testing:
- Removed dimensions.json from cache
- Ran sync-schemas
- Verified dimensions.json downloaded at depth 2
- Build passes with dynamically downloaded schemas

Result:
- dimensions.json automatically downloaded (found at depth 2)
- Removed force-committed dimensions.json from git tracking
- Schema cache directory remains gitignored as intended

* style: fix Prettier formatting in sync-schemas.ts

* feat: use AdCP v2 branch for schemas and fix schema path handling

Changes:
- Update ADCP_VERSION from 2.4.0 to v2 (tracks latest 2.x.x)
- Fix sync-schemas to properly handle version-agnostic  paths
  - Schemas contain `/schemas/2.4.0/` refs regardless of branch version
  - Strip version segment to get proper relative path
  - Maintain directory structure (core/, media-buy/, etc.)
- Fix generate-types to read  from index.json instead of hardcoding
  - loadToolSchema now reads task. from index
  - loadCoreSchema now reads schema. from index
  - No more hardcoded `/schemas/v1/` paths
- Update package.json adcp_version to v2
- Regenerate types with v2 schemas (same as 2.4.0 but tracks branch)

Benefits:
- Using v2 means we automatically get latest 2.x.x patches
- Schema sync works with any version format (v1, v2, X.Y.Z)
- Type generation no longer depends on hardcoded version paths

Testing:
- Synced schemas with v2 branch
- Generated types successfully (92 Zod schemas)
- Build passes
- Schemas properly organized in core/, media-buy/, creative/, etc.

* feat: upgrade to AdCP 2.5.0 schema

- Updated ADCP_VERSION from v2 to 2.5.0
- Synced schemas from adcontextprotocol.org
- Regenerated TypeScript types from 2.5.0 schemas
- Updated package.json adcp_version field
- Library version remains 3.1.0

This allows the client to automatically pick up patch updates
in the 2.5.x series without requiring code changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* style: fix prettier formatting in version.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: use v2.5 alias for automatic patch version tracking

Updated ADCP_VERSION from 2.5.0 to v2.5 to use the upstream
symlink alias. This allows the client to automatically pick up
patch releases (2.5.1, 2.5.2, etc.) without code changes.

The v2.5 alias points to the latest 2.5.x release on
adcontextprotocol.org.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* style: fix prettier formatting in version.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
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