@adcp/client 4.21.0 → 4.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +278 -0
- package/README.md +96 -61
- package/bin/adcp.js +342 -4
- package/dist/lib/agents/index.generated.d.ts +9 -1
- package/dist/lib/agents/index.generated.d.ts.map +1 -1
- package/dist/lib/agents/index.generated.js +12 -0
- package/dist/lib/agents/index.generated.js.map +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts +2 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +10 -1
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/discovery/property-crawler.d.ts +4 -0
- package/dist/lib/discovery/property-crawler.d.ts.map +1 -1
- package/dist/lib/discovery/property-crawler.js +10 -2
- package/dist/lib/discovery/property-crawler.js.map +1 -1
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +6 -4
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +8 -6
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/protocols/mcp.d.ts.map +1 -1
- package/dist/lib/protocols/mcp.js +24 -11
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +3 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/serve.d.ts +45 -0
- package/dist/lib/server/serve.d.ts.map +1 -0
- package/dist/lib/server/serve.js +86 -0
- package/dist/lib/server/serve.js.map +1 -0
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +1 -0
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +48 -63
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts +24 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js +157 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
- package/dist/lib/testing/compliance/types.d.ts +1 -1
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/index.d.ts +1 -0
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +23 -1
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/orchestrator.d.ts +8 -0
- package/dist/lib/testing/orchestrator.d.ts.map +1 -1
- package/dist/lib/testing/orchestrator.js +8 -0
- package/dist/lib/testing/orchestrator.js.map +1 -1
- package/dist/lib/testing/storyboard/context.d.ts +34 -0
- package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/context.js +257 -0
- package/dist/lib/testing/storyboard/context.js.map +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +15 -0
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/index.js +48 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -0
- package/dist/lib/testing/storyboard/loader.d.ts +53 -0
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/loader.js +114 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -0
- package/dist/lib/testing/storyboard/path.d.ts +29 -0
- package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/path.js +121 -0
- package/dist/lib/testing/storyboard/path.js.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts +28 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.js +410 -0
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
- package/dist/lib/testing/storyboard/runner.d.ts +24 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/runner.js +280 -0
- package/dist/lib/testing/storyboard/runner.js.map +1 -0
- package/dist/lib/testing/storyboard/task-map.d.ts +21 -0
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/task-map.js +84 -0
- package/dist/lib/testing/storyboard/task-map.js.map +1 -0
- package/dist/lib/testing/storyboard/types.d.ts +156 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/types.js +10 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -0
- package/dist/lib/testing/storyboard/validations.d.ts +17 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/validations.js +166 -0
- package/dist/lib/testing/storyboard/validations.js.map +1 -0
- package/dist/lib/testing/types.d.ts +2 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/core.generated.d.ts +2 -2
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js +1 -1
- package/dist/lib/types/schemas.generated.d.ts +193 -34
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +87 -5
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/tools.generated.d.ts +280 -3
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.d.ts.map +1 -1
- package/dist/lib/utils/response-schemas.js +34 -3
- package/dist/lib/utils/response-schemas.js.map +1 -1
- package/dist/lib/utils/validate-user-agent.d.ts +8 -0
- package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
- package/dist/lib/utils/validate-user-agent.js +15 -0
- package/dist/lib/utils/validate-user-agent.js.map +1 -0
- package/dist/lib/version.d.ts +6 -0
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +7 -1
- package/dist/lib/version.js.map +1 -1
- package/docs/README.md +42 -0
- package/docs/guides/BUILD-AN-AGENT.md +292 -0
- package/docs/llms.txt +634 -0
- package/examples/README.md +106 -0
- package/examples/adcp.config.json +30 -0
- package/examples/basic-a2a.ts +76 -0
- package/examples/basic-mcp.ts +50 -0
- package/examples/batch-preview-test.ts +266 -0
- package/examples/conversation-client.ts +291 -0
- package/examples/debug-preview-response.ts +73 -0
- package/examples/debug-preview-with-logging.ts +50 -0
- package/examples/easy-config-demo.ts +242 -0
- package/examples/env-config.ts +51 -0
- package/examples/error-compliant-server.ts +237 -0
- package/examples/generative-creative-demo.ts +205 -0
- package/examples/inspect-card-formats.ts +161 -0
- package/examples/logger-usage.ts +165 -0
- package/examples/oauth-cli-example.ts +154 -0
- package/examples/pr78-async-patterns-demo.ts +247 -0
- package/examples/signals-agent.ts +162 -0
- package/examples/simple-getting-started.ts +225 -0
- package/examples/simple-protocol-demo.ts +75 -0
- package/examples/test-helpers-demo.ts +239 -0
- package/examples/zod-validation-example.ts +126 -0
- package/package.json +12 -2
- package/skills/adcp/SKILL.md +13 -2
- package/storyboards/audience_sync.yaml +199 -0
- package/storyboards/behavioral_analysis.yaml +244 -0
- package/storyboards/brand_rights.yaml +131 -0
- package/storyboards/creative_ad_server.yaml +171 -0
- package/storyboards/creative_sales_agent.yaml +169 -0
- package/storyboards/creative_template.yaml +306 -0
- package/storyboards/deterministic_testing.yaml +925 -0
- package/storyboards/error_compliance.yaml +231 -0
- package/storyboards/governance_content_standards.yaml +213 -0
- package/storyboards/governance_property_lists.yaml +372 -0
- package/storyboards/media_buy_catalog_creative.yaml +457 -0
- package/storyboards/media_buy_governance_escalation.yaml +467 -0
- package/storyboards/media_buy_guaranteed_approval.yaml +396 -0
- package/storyboards/media_buy_non_guaranteed.yaml +288 -0
- package/storyboards/media_buy_proposal_mode.yaml +369 -0
- package/storyboards/media_buy_seller.yaml +560 -0
- package/storyboards/media_buy_state_machine.yaml +254 -0
- package/storyboards/schema.yaml +65 -0
- package/storyboards/schema_validation.yaml +166 -0
- package/storyboards/si_session.yaml +384 -0
- package/storyboards/signal_marketplace.yaml +283 -0
- package/storyboards/signal_owned.yaml +211 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# AI Coding Assistant Instructions for AdCP Client
|
|
2
|
+
|
|
3
|
+
This document contains essential guidelines for AI coding assistants (Claude, Copilot, etc.) working on the AdCP Client project.
|
|
4
|
+
|
|
5
|
+
## Start Here
|
|
6
|
+
|
|
7
|
+
**Protocol overview** — Read `docs/llms.txt` for a single-file summary of AdCP: all 46 tools, key types, error codes, common flows, and test scenarios. Also available at https://adcontextprotocol.github.io/adcp-client/llms.txt
|
|
8
|
+
|
|
9
|
+
**Type reference** — Read `docs/TYPE-SUMMARY.md` for curated type signatures (AgentConfig, TaskResult, ConversationContext, and all tool request/response shapes).
|
|
10
|
+
|
|
11
|
+
**Do NOT read these files** — they are large generated files that waste context:
|
|
12
|
+
- `src/lib/types/tools.generated.ts` (~13,000 lines) — use TYPE-SUMMARY.md instead
|
|
13
|
+
- `src/lib/types/core.generated.ts` (~2,000 lines) — use TYPE-SUMMARY.md instead
|
|
14
|
+
- `src/lib/types/schemas.generated.ts` (~8,000 lines) — Zod runtime schemas, rarely needed directly
|
|
15
|
+
- `src/lib/agents/index.generated.ts` — generated Agent classes, use the client API instead
|
|
16
|
+
|
|
17
|
+
**Building a server-side agent?** — Read `docs/guides/BUILD-AN-AGENT.md` and the `storyboards/` directory for expected tool call sequences.
|
|
18
|
+
|
|
19
|
+
## Project Overview
|
|
20
|
+
|
|
21
|
+
**@adcp/client** is the official TypeScript client library for the Ad Context Protocol (AdCP), documented at [docs.adcontextprotocol.org](https://docs.adcontextprotocol.org/docs/).
|
|
22
|
+
|
|
23
|
+
**Components:**
|
|
24
|
+
|
|
25
|
+
1. **Library** (`src/lib/`) - NPM package for AdCP agent communication
|
|
26
|
+
2. **CLI** (`bin/`) - Command-line tooling for testing agents
|
|
27
|
+
|
|
28
|
+
## 🚨 CRITICAL REQUIREMENTS - MUST FOLLOW 🚨
|
|
29
|
+
|
|
30
|
+
### 1. ALWAYS USE OFFICIAL PROTOCOL CLIENTS
|
|
31
|
+
|
|
32
|
+
- **A2A Protocol**: ALWAYS use the official `@a2a-js/sdk` client
|
|
33
|
+
- **MCP Protocol**: ALWAYS use the official `@modelcontextprotocol/sdk` client
|
|
34
|
+
- **NEVER** implement custom HTTP fallbacks or protocol implementations
|
|
35
|
+
- **NEVER** parse SSE responses manually
|
|
36
|
+
- **NEVER** make direct fetch() calls to agent endpoints
|
|
37
|
+
- If an official client fails to import, FIX THE IMPORT - don't create workarounds
|
|
38
|
+
|
|
39
|
+
### 2. NEVER USE MOCK DATA
|
|
40
|
+
|
|
41
|
+
- **NEVER** inject mock products, formats, or any other fake data
|
|
42
|
+
- **NEVER** provide fallback data when agents return empty responses
|
|
43
|
+
- **ALWAYS** return exactly what the agents provide
|
|
44
|
+
- If an agent returns empty arrays or errors, show that to the user
|
|
45
|
+
- Real data only - no exceptions
|
|
46
|
+
|
|
47
|
+
### 3. MCP CLIENT AUTHENTICATION - CRITICAL
|
|
48
|
+
|
|
49
|
+
The MCP SDK automatically handles initialization. Authentication must be provided via headers:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const transport = new StreamableHTTPClientTransport(url, {
|
|
53
|
+
requestInit: {
|
|
54
|
+
headers: {
|
|
55
|
+
'x-adcp-auth': authToken,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
await client.connect(transport); // This automatically calls initialize internally
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Critical Architecture Patterns
|
|
63
|
+
|
|
64
|
+
### Protocol Abstraction Layer
|
|
65
|
+
|
|
66
|
+
The library supports both **A2A** and **MCP** protocols via unified interface:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { ProtocolClient } from './src/lib/protocols';
|
|
70
|
+
// Routes to: callA2ATool() or callMCPTool() based on agent.protocol
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**🚨 CRITICAL: A2A Protocol Implementation Requirements**
|
|
74
|
+
|
|
75
|
+
The A2A protocol has specific implementation requirements that differ from MCP:
|
|
76
|
+
|
|
77
|
+
**1. Artifact Field Names**
|
|
78
|
+
|
|
79
|
+
A2A artifacts use `artifactId` per @a2a-js/sdk Artifact interface, NOT `name`:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Correct (per @a2a-js/sdk)
|
|
83
|
+
if (!artifact.artifactId) {
|
|
84
|
+
warnings.push('A2A artifact missing artifactId field');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Incorrect - 'name' doesn't exist in A2A SDK
|
|
88
|
+
if (!artifact.name) { ... }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**2. Two Types of Webhooks - Do Not Confuse!**
|
|
92
|
+
|
|
93
|
+
**1. `push_notification_config` - For Async Task Status Updates**
|
|
94
|
+
|
|
95
|
+
Used for receiving task completion/progress notifications. Placement differs by protocol:
|
|
96
|
+
|
|
97
|
+
- **A2A Protocol**: Goes in `params.configuration.pushNotificationConfig` (camelCase)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
await a2aClient.sendMessage({
|
|
101
|
+
message: { /* task content */ },
|
|
102
|
+
configuration: {
|
|
103
|
+
pushNotificationConfig: { // ← For async task status
|
|
104
|
+
url: webhookUrl,
|
|
105
|
+
token?: clientToken,
|
|
106
|
+
authentication: { schemes: ['HMAC-SHA256'], credentials: secret }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- **MCP Protocol**: Goes in tool arguments as `push_notification_config` (snake_case)
|
|
113
|
+
```typescript
|
|
114
|
+
await mcpClient.callTool('create_media_buy', {
|
|
115
|
+
buyer_ref: '...',
|
|
116
|
+
packages: [...],
|
|
117
|
+
push_notification_config: { // ← For async task status
|
|
118
|
+
url: webhookUrl,
|
|
119
|
+
token?: clientToken,
|
|
120
|
+
authentication: { schemes: ['HMAC-SHA256'], credentials: secret }
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**2. `reporting_webhook` - For Reporting Data Delivery**
|
|
126
|
+
|
|
127
|
+
Used for receiving periodic performance metrics. **Always stays in skill parameters** (both A2A and MCP):
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Both protocols - reporting_webhook in skill parameters
|
|
131
|
+
{
|
|
132
|
+
buyer_ref: '...',
|
|
133
|
+
packages: [...],
|
|
134
|
+
reporting_webhook: { // ← Stays in parameters for BOTH protocols
|
|
135
|
+
url: reportingUrl,
|
|
136
|
+
token?: clientToken,
|
|
137
|
+
authentication: { schemes: ['HMAC-SHA256'], credentials: secret },
|
|
138
|
+
reporting_frequency: 'daily', // Additional fields specific to reporting
|
|
139
|
+
requested_metrics: ['impressions', 'spend', 'clicks']
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Schema: https://adcontextprotocol.org/schemas/v1/core/push-notification-config.json
|
|
145
|
+
|
|
146
|
+
The `ProtocolClient.callTool()` method in `src/lib/protocols/index.ts` handles this routing automatically.
|
|
147
|
+
|
|
148
|
+
### Async Operation Patterns (AdCP PR 78)
|
|
149
|
+
|
|
150
|
+
All operations follow 5 status patterns based on agent response:
|
|
151
|
+
|
|
152
|
+
- `completed` - Sync completion with result
|
|
153
|
+
- `working` - Long-running, poll with `tasks/get`
|
|
154
|
+
- `submitted` - Webhook delivery required
|
|
155
|
+
- `input_required` - Agent needs clarification via input handlers
|
|
156
|
+
- `deferred` - Client defers decision to human/external system
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Core flow in src/lib/core/TaskExecutor.ts
|
|
160
|
+
const result = await executor.executeTask(agent, 'get_products', params, inputHandler);
|
|
161
|
+
// Status determines next steps: polling, webhook wait, or input handling
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Conversation-Aware Input Handling
|
|
165
|
+
|
|
166
|
+
Agents may need clarifications during execution. Use input handlers:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const client = new AdCPClient(agent, {
|
|
170
|
+
handlers: {
|
|
171
|
+
onGetProductsStatusChange: (response, metadata) => {
|
|
172
|
+
// Fires for ALL status changes: sync completion, webhook delivery, etc.
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Input handler pattern for clarifications
|
|
178
|
+
const handler = async context => {
|
|
179
|
+
return context.inputRequest.field === 'budget' ? 50000 : context.deferToHuman();
|
|
180
|
+
};
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Build & Release Process
|
|
184
|
+
|
|
185
|
+
### Changesets-Based Releases
|
|
186
|
+
|
|
187
|
+
**🚨 NEVER manually edit `package.json` version** - Use changesets:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm run changeset # Create changeset for changes
|
|
191
|
+
# Merge PR to main → Auto Release PR created
|
|
192
|
+
# Merge Release PR → Auto publish to npm
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**The correct separation:**
|
|
196
|
+
|
|
197
|
+
- `package.json` version = **Library version** (managed by changesets)
|
|
198
|
+
- `src/lib/version.ts` ADCP_VERSION = **AdCP schema version** (can differ from library version)
|
|
199
|
+
|
|
200
|
+
### Schema Generation Workflow
|
|
201
|
+
|
|
202
|
+
Library types auto-generated from AdCP schemas:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
npm run sync-schemas # Download from protocol repo
|
|
206
|
+
npm run generate-types # Generate TypeScript types
|
|
207
|
+
npm run generate-zod-schemas # Generate runtime validation
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Testing Strategies
|
|
211
|
+
|
|
212
|
+
### Protocol-Level Mocking
|
|
213
|
+
|
|
214
|
+
Test TaskExecutor patterns by mocking `ProtocolClient.callTool()`:
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
ProtocolClient.callTool = mock.fn(async (agent, taskName, params) => {
|
|
218
|
+
if (taskName === 'tasks/get') return { task: { status: 'working' } };
|
|
219
|
+
return { status: 'submitted' };
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Test Commands
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
npm test # Unit tests
|
|
227
|
+
npm run test:protocols # Protocol compliance tests
|
|
228
|
+
npm run test:e2e # End-to-end against live server
|
|
229
|
+
npm run test:all # Full test suite
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## File Organization
|
|
233
|
+
|
|
234
|
+
- `docs/llms.txt` - **Start here**: protocol overview, all tools, types, flows (generated)
|
|
235
|
+
- `docs/TYPE-SUMMARY.md` - Curated type reference (generated)
|
|
236
|
+
- `src/lib/core/` - Main client classes (AdCPClient, TaskExecutor)
|
|
237
|
+
- `src/lib/protocols/` - A2A/MCP protocol implementations
|
|
238
|
+
- `src/lib/types/` - Generated TypeScript types from schemas (prefer TYPE-SUMMARY.md)
|
|
239
|
+
- `storyboards/` - YAML definitions of tool call sequences for each agent type
|
|
240
|
+
- `test/lib/` - Library unit tests
|
|
241
|
+
- `test/e2e/` - Integration tests
|
|
242
|
+
- `examples/` - Usage examples and demos
|
|
243
|
+
|
|
244
|
+
## Backwards Compatibility
|
|
245
|
+
|
|
246
|
+
**This is a published npm library. Callers on older versions must not break when we add new required fields.**
|
|
247
|
+
|
|
248
|
+
When adding a new required field to a request schema:
|
|
249
|
+
|
|
250
|
+
1. **Infer it from existing fields** in `SingleAgentClient.normalizeRequestParams()` so callers that don't send it still work
|
|
251
|
+
2. **Update all internal callers** (testing scenarios) to send the field explicitly
|
|
252
|
+
3. **Add tests** verifying the inference works and that explicit values are preserved
|
|
253
|
+
|
|
254
|
+
Example: `buying_mode` was added as required on `get_products`. The client infers it from `brief` presence — callers that only sent `{ brief: '...' }` keep working.
|
|
255
|
+
|
|
256
|
+
The pattern:
|
|
257
|
+
|
|
258
|
+
- `normalizeRequestParams()` runs before validation, filling in derivable fields
|
|
259
|
+
- `validateRequest()` runs Zod schemas after normalization
|
|
260
|
+
- `adaptRequestForServerVersion()` handles v3→v2 downgrades for older servers
|
|
261
|
+
|
|
262
|
+
**Never add a required field without a backwards-compatible default or inference path.**
|
|
263
|
+
|
|
264
|
+
## Common Gotchas
|
|
265
|
+
|
|
266
|
+
1. **Protocol clients**: Always use official `@a2a-js/sdk` and `@modelcontextprotocol/sdk`
|
|
267
|
+
2. **Mock data**: Never inject fallback data when agents return empty responses
|
|
268
|
+
3. **Version management**: Let changesets handle package.json, edit ADCP_VERSION separately
|
|
269
|
+
4. **Backwards compatibility**: New required schema fields need inference in `normalizeRequestParams()`
|
|
270
|
+
|
|
271
|
+
## References
|
|
272
|
+
|
|
273
|
+
- [Protocol overview (llms.txt)](https://adcontextprotocol.github.io/adcp-client/llms.txt)
|
|
274
|
+
- [API Documentation](https://adcontextprotocol.github.io/adcp-client/api/index.html)
|
|
275
|
+
- [AdCP Specification](https://adcontextprotocol.org)
|
|
276
|
+
- [A2A SDK](https://github.com/a2a/a2a-js-sdk)
|
|
277
|
+
- [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
278
|
+
- [Changesets Documentation](https://github.com/changesets/changesets)
|
package/README.md
CHANGED
|
@@ -9,9 +9,16 @@
|
|
|
9
9
|
|
|
10
10
|
Official TypeScript/JavaScript client for the **Ad Context Protocol (AdCP)**. Build distributed advertising operations that work synchronously OR asynchronously with the same code.
|
|
11
11
|
|
|
12
|
+
## For AI Agents
|
|
13
|
+
|
|
14
|
+
Start with [`docs/llms.txt`](./docs/llms.txt) — the full protocol spec in one file (tools, types, error codes, examples). Building a server? See [`docs/guides/BUILD-AN-AGENT.md`](./docs/guides/BUILD-AN-AGENT.md). For type signatures, use [`docs/TYPE-SUMMARY.md`](./docs/TYPE-SUMMARY.md). Skip `src/lib/types/*.generated.ts` — they're machine-generated and will burn context.
|
|
15
|
+
|
|
16
|
+
These docs are also available in `node_modules/@adcp/client/docs/` after install.
|
|
17
|
+
|
|
12
18
|
## The Core Concept
|
|
13
19
|
|
|
14
20
|
AdCP operations are **distributed and asynchronous by default**. An agent might:
|
|
21
|
+
|
|
15
22
|
- Complete your request **immediately** (synchronous)
|
|
16
23
|
- Need time to process and **send results via webhook** (asynchronous)
|
|
17
24
|
- Ask for **clarifications** before proceeding
|
|
@@ -31,44 +38,47 @@ npm install @adcp/client
|
|
|
31
38
|
import { ADCPMultiAgentClient } from '@adcp/client';
|
|
32
39
|
|
|
33
40
|
// Configure agents and handlers
|
|
34
|
-
const client = new ADCPMultiAgentClient(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
const client = new ADCPMultiAgentClient(
|
|
42
|
+
[
|
|
43
|
+
{
|
|
44
|
+
id: 'agent_x',
|
|
45
|
+
agent_uri: 'https://agent-x.com',
|
|
46
|
+
protocol: 'a2a',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'agent_y',
|
|
50
|
+
agent_uri: 'https://agent-y.com/mcp/',
|
|
51
|
+
protocol: 'mcp',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
40
54
|
{
|
|
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
|
-
// Handle clarification needed
|
|
67
|
-
console.log('Needs input:', metadata.message);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
55
|
+
// Webhook URL template (macros: {agent_id}, {task_type}, {operation_id})
|
|
56
|
+
webhookUrlTemplate: 'https://myapp.com/webhook/{task_type}/{agent_id}/{operation_id}',
|
|
57
|
+
|
|
58
|
+
// Activity callback - fires for ALL events (requests, responses, status changes, webhooks)
|
|
59
|
+
onActivity: activity => {
|
|
60
|
+
console.log(`[${activity.type}] ${activity.task_type} - ${activity.operation_id}`);
|
|
61
|
+
// Log to monitoring, update UI, etc.
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// Status change handlers - called for ALL status changes (completed, failed, input-required, working, etc)
|
|
65
|
+
handlers: {
|
|
66
|
+
onGetProductsStatusChange: (response, metadata) => {
|
|
67
|
+
// Called for sync completion, async webhook, AND status changes
|
|
68
|
+
console.log(`[${metadata.status}] Got products for ${metadata.operation_id}`);
|
|
69
|
+
|
|
70
|
+
if (metadata.status === 'completed') {
|
|
71
|
+
db.saveProducts(metadata.operation_id, response.products);
|
|
72
|
+
} else if (metadata.status === 'failed') {
|
|
73
|
+
db.markFailed(metadata.operation_id, metadata.message);
|
|
74
|
+
} else if (metadata.status === 'input-required') {
|
|
75
|
+
// Handle clarification needed
|
|
76
|
+
console.log('Needs input:', metadata.message);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
},
|
|
70
80
|
}
|
|
71
|
-
|
|
81
|
+
);
|
|
72
82
|
|
|
73
83
|
// Execute operation - library handles operation IDs, webhook URLs, context management
|
|
74
84
|
const agent = client.agent('agent_x');
|
|
@@ -132,7 +142,7 @@ const client = new ADCPMultiAgentClient(agents, {
|
|
|
132
142
|
webhookUrlTemplate: 'https://myapp.com/api/v1/adcp/{agent_id}?operation={operation_id}',
|
|
133
143
|
|
|
134
144
|
// OR namespace to avoid conflicts
|
|
135
|
-
webhookUrlTemplate: 'https://myapp.com/adcp-webhooks/{agent_id}/{task_type}/{operation_id}'
|
|
145
|
+
webhookUrlTemplate: 'https://myapp.com/adcp-webhooks/{agent_id}/{task_type}/{operation_id}',
|
|
136
146
|
});
|
|
137
147
|
```
|
|
138
148
|
|
|
@@ -172,21 +182,22 @@ Get observability into everything happening:
|
|
|
172
182
|
|
|
173
183
|
```typescript
|
|
174
184
|
const client = new ADCPMultiAgentClient(agents, {
|
|
175
|
-
onActivity:
|
|
185
|
+
onActivity: activity => {
|
|
176
186
|
console.log({
|
|
177
|
-
type: activity.type,
|
|
187
|
+
type: activity.type, // 'protocol_request', 'webhook_received', etc.
|
|
178
188
|
operation_id: activity.operation_id,
|
|
179
189
|
agent_id: activity.agent_id,
|
|
180
|
-
status: activity.status
|
|
190
|
+
status: activity.status,
|
|
181
191
|
});
|
|
182
192
|
|
|
183
193
|
// Stream to UI, save to database, send to monitoring
|
|
184
194
|
eventStream.send(activity);
|
|
185
|
-
}
|
|
195
|
+
},
|
|
186
196
|
});
|
|
187
197
|
```
|
|
188
198
|
|
|
189
199
|
Activity types:
|
|
200
|
+
|
|
190
201
|
- `protocol_request` - Request sent to agent
|
|
191
202
|
- `protocol_response` - Response received from agent
|
|
192
203
|
- `status_change` - Task status changed
|
|
@@ -200,7 +211,7 @@ Activity types:
|
|
|
200
211
|
// When creating a media buy, agent registers for delivery notifications
|
|
201
212
|
const result = await agent.createMediaBuy({
|
|
202
213
|
campaign_id: 'camp_123',
|
|
203
|
-
budget: { amount: 10000, currency: 'USD' }
|
|
214
|
+
budget: { amount: 10000, currency: 'USD' },
|
|
204
215
|
// Agent internally sets up recurring delivery_report notifications
|
|
205
216
|
});
|
|
206
217
|
|
|
@@ -220,12 +231,13 @@ const client = new ADCPMultiAgentClient(agents, {
|
|
|
220
231
|
if (metadata.notification_type === 'final') {
|
|
221
232
|
db.markOperationComplete(metadata.operation_id);
|
|
222
233
|
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
234
|
+
},
|
|
235
|
+
},
|
|
225
236
|
});
|
|
226
237
|
```
|
|
227
238
|
|
|
228
239
|
Notifications use the **same webhook URL pattern** as regular operations:
|
|
240
|
+
|
|
229
241
|
```
|
|
230
242
|
POST https://myapp.com/webhook/media_buy_delivery/agent_x/delivery_report_agent_x_2025-10
|
|
231
243
|
```
|
|
@@ -257,7 +269,7 @@ handlers: {
|
|
|
257
269
|
if (metadata.status === 'completed') {
|
|
258
270
|
const buyId = (response as CreateMediaBuyResponse).media_buy_id; // Typed!
|
|
259
271
|
}
|
|
260
|
-
}
|
|
272
|
+
};
|
|
261
273
|
}
|
|
262
274
|
```
|
|
263
275
|
|
|
@@ -266,11 +278,7 @@ handlers: {
|
|
|
266
278
|
Building a server that receives AdCP tool calls? Import request types for handler signatures and Zod schemas for validation:
|
|
267
279
|
|
|
268
280
|
```typescript
|
|
269
|
-
import {
|
|
270
|
-
CreateMediaBuyRequest,
|
|
271
|
-
CreateMediaBuyResponse,
|
|
272
|
-
CreateMediaBuyRequestSchema,
|
|
273
|
-
} from '@adcp/client';
|
|
281
|
+
import { CreateMediaBuyRequest, CreateMediaBuyResponse, CreateMediaBuyRequestSchema } from '@adcp/client';
|
|
274
282
|
|
|
275
283
|
function handleCreateMediaBuy(rawParams: unknown): CreateMediaBuyResponse {
|
|
276
284
|
const request: CreateMediaBuyRequest = CreateMediaBuyRequestSchema.parse(rawParams);
|
|
@@ -309,7 +317,7 @@ results.forEach((result, i) => {
|
|
|
309
317
|
|
|
310
318
|
```typescript
|
|
311
319
|
const client = new ADCPMultiAgentClient(agents, {
|
|
312
|
-
webhookSecret: process.env.WEBHOOK_SECRET
|
|
320
|
+
webhookSecret: process.env.WEBHOOK_SECRET,
|
|
313
321
|
});
|
|
314
322
|
|
|
315
323
|
// Signatures verified automatically on handleWebhook()
|
|
@@ -319,13 +327,15 @@ const client = new ADCPMultiAgentClient(agents, {
|
|
|
319
327
|
### Authentication
|
|
320
328
|
|
|
321
329
|
```typescript
|
|
322
|
-
const agents = [
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
330
|
+
const agents = [
|
|
331
|
+
{
|
|
332
|
+
id: 'agent_x',
|
|
333
|
+
name: 'Agent X',
|
|
334
|
+
agent_uri: 'https://agent-x.com',
|
|
335
|
+
protocol: 'a2a',
|
|
336
|
+
auth_token: process.env.AGENT_X_TOKEN, // ✅ Secure - load from env
|
|
337
|
+
},
|
|
338
|
+
];
|
|
329
339
|
```
|
|
330
340
|
|
|
331
341
|
## Environment Configuration
|
|
@@ -356,6 +366,7 @@ const client = ADCPMultiAgentClient.fromEnv();
|
|
|
356
366
|
All AdCP tools with full type safety:
|
|
357
367
|
|
|
358
368
|
**Media Buy Lifecycle:**
|
|
369
|
+
|
|
359
370
|
- `getProducts()` - Discover advertising products
|
|
360
371
|
- `listCreativeFormats()` - Get supported creative formats
|
|
361
372
|
- `createMediaBuy()` - Create new media buy
|
|
@@ -365,11 +376,13 @@ All AdCP tools with full type safety:
|
|
|
365
376
|
- `getMediaBuyDelivery()` - Get delivery performance
|
|
366
377
|
|
|
367
378
|
**Audience & Targeting:**
|
|
379
|
+
|
|
368
380
|
- `getSignals()` - Get audience signals
|
|
369
381
|
- `activateSignal()` - Activate audience signals
|
|
370
382
|
- `providePerformanceFeedback()` - Send performance feedback
|
|
371
383
|
|
|
372
384
|
**Protocol:**
|
|
385
|
+
|
|
373
386
|
- `getAdcpCapabilities()` - Get agent capabilities (v3)
|
|
374
387
|
|
|
375
388
|
## Property Discovery (AdCP v2.2.0)
|
|
@@ -391,7 +404,7 @@ import { PropertyCrawler, getPropertyIndex } from '@adcp/client';
|
|
|
391
404
|
const crawler = new PropertyCrawler();
|
|
392
405
|
await crawler.crawlAgents([
|
|
393
406
|
{ agent_url: 'https://agent-x.com', protocol: 'a2a' },
|
|
394
|
-
{ agent_url: 'https://agent-y.com/mcp/', protocol: 'mcp' }
|
|
407
|
+
{ agent_url: 'https://agent-y.com/mcp/', protocol: 'mcp' },
|
|
395
408
|
]);
|
|
396
409
|
|
|
397
410
|
const index = getPropertyIndex();
|
|
@@ -418,7 +431,7 @@ const crawler = new PropertyCrawler();
|
|
|
418
431
|
// Crawl agents - gets publisher_domains from each, then fetches adagents.json
|
|
419
432
|
const result = await crawler.crawlAgents([
|
|
420
433
|
{ agent_url: 'https://sales.cnn.com' },
|
|
421
|
-
{ agent_url: 'https://sales.espn.com' }
|
|
434
|
+
{ agent_url: 'https://sales.espn.com' },
|
|
422
435
|
]);
|
|
423
436
|
|
|
424
437
|
console.log(`✅ ${result.successfulAgents} agents`);
|
|
@@ -441,6 +454,7 @@ Supports 18 identifier types: `domain`, `subdomain`, `ios_bundle`, `android_pack
|
|
|
441
454
|
### Use Case
|
|
442
455
|
|
|
443
456
|
Build a registry service that:
|
|
457
|
+
|
|
444
458
|
- Periodically crawls agents with `PropertyCrawler`
|
|
445
459
|
- Persists discovered properties to a database
|
|
446
460
|
- Exposes fast query APIs using the in-memory index patterns
|
|
@@ -600,6 +614,7 @@ npm start
|
|
|
600
614
|
```
|
|
601
615
|
|
|
602
616
|
Features:
|
|
617
|
+
|
|
603
618
|
- Configure multiple agents (test agents + your own)
|
|
604
619
|
- Execute ONE operation across all agents
|
|
605
620
|
- See live activity stream (protocol requests, webhooks, handlers)
|
|
@@ -609,11 +624,13 @@ Features:
|
|
|
609
624
|
## Examples
|
|
610
625
|
|
|
611
626
|
### Basic Operation
|
|
627
|
+
|
|
612
628
|
```typescript
|
|
613
629
|
const result = await agent.getProducts({ brief: 'Coffee brands' });
|
|
614
630
|
```
|
|
615
631
|
|
|
616
632
|
### With Clarification Handler
|
|
633
|
+
|
|
617
634
|
```typescript
|
|
618
635
|
const result = await agent.createMediaBuy(
|
|
619
636
|
{ buyer_ref: 'campaign-123', account_id: 'acct-456', packages: [...] },
|
|
@@ -628,6 +645,7 @@ const result = await agent.createMediaBuy(
|
|
|
628
645
|
```
|
|
629
646
|
|
|
630
647
|
### With Webhook for Long-Running Operations
|
|
648
|
+
|
|
631
649
|
```typescript
|
|
632
650
|
const operationId = createOperationId();
|
|
633
651
|
|
|
@@ -636,7 +654,7 @@ const result = await agent.syncCreatives(
|
|
|
636
654
|
null, // No clarification handler = webhook mode
|
|
637
655
|
{
|
|
638
656
|
contextId: operationId,
|
|
639
|
-
webhookUrl: agent.getWebhookUrl('sync_creatives', operationId)
|
|
657
|
+
webhookUrl: agent.getWebhookUrl('sync_creatives', operationId),
|
|
640
658
|
}
|
|
641
659
|
);
|
|
642
660
|
|
|
@@ -644,6 +662,23 @@ const result = await agent.syncCreatives(
|
|
|
644
662
|
// Handler fires when webhook received
|
|
645
663
|
```
|
|
646
664
|
|
|
665
|
+
## Building an Agent (Server)
|
|
666
|
+
|
|
667
|
+
The examples above show client-side usage — calling existing agents. To build your own agent that serves AdCP tools:
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
import { createTaskCapableServer, taskToolResponse, GetSignalsRequestSchema } from '@adcp/client';
|
|
671
|
+
|
|
672
|
+
const server = createTaskCapableServer('My Signals Agent', '1.0.0');
|
|
673
|
+
|
|
674
|
+
server.tool('get_signals', 'Discover audience segments.', GetSignalsRequestSchema.shape, async args => {
|
|
675
|
+
const signals = queryYourDatabase(args.signal_spec);
|
|
676
|
+
return taskToolResponse({ signals, sandbox: true }, `Found ${signals.length} segment(s)`);
|
|
677
|
+
});
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
See the [Build an Agent guide](docs/guides/BUILD-AN-AGENT.md) for the full walkthrough, and [`examples/signals-agent.ts`](examples/signals-agent.ts) for a complete runnable example.
|
|
681
|
+
|
|
647
682
|
## Contributing
|
|
648
683
|
|
|
649
684
|
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|