adcp 0.1.2__py3-none-any.whl → 1.0.2__py3-none-any.whl
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.
- adcp/__init__.py +80 -2
- adcp/__main__.py +284 -0
- adcp/client.py +290 -105
- adcp/config.py +82 -0
- adcp/exceptions.py +121 -0
- adcp/protocols/__init__.py +2 -0
- adcp/protocols/a2a.py +201 -87
- adcp/protocols/base.py +11 -0
- adcp/protocols/mcp.py +185 -25
- adcp/types/__init__.py +4 -0
- adcp/types/core.py +76 -1
- adcp/types/generated.py +615 -0
- adcp/types/tasks.py +281 -0
- adcp/utils/__init__.py +2 -0
- adcp/utils/operation_id.py +2 -0
- {adcp-0.1.2.dist-info → adcp-1.0.2.dist-info}/METADATA +184 -8
- adcp-1.0.2.dist-info/RECORD +21 -0
- adcp-1.0.2.dist-info/entry_points.txt +2 -0
- adcp-0.1.2.dist-info/RECORD +0 -15
- {adcp-0.1.2.dist-info → adcp-1.0.2.dist-info}/WHEEL +0 -0
- {adcp-0.1.2.dist-info → adcp-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {adcp-0.1.2.dist-info → adcp-1.0.2.dist-info}/top_level.txt +0 -0
adcp/__init__.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
"""
|
|
2
4
|
AdCP Python Client Library
|
|
3
5
|
|
|
@@ -6,13 +8,89 @@ Supports both A2A and MCP protocols with full type safety.
|
|
|
6
8
|
"""
|
|
7
9
|
|
|
8
10
|
from adcp.client import ADCPClient, ADCPMultiAgentClient
|
|
9
|
-
from adcp.
|
|
11
|
+
from adcp.exceptions import (
|
|
12
|
+
ADCPAuthenticationError,
|
|
13
|
+
ADCPConnectionError,
|
|
14
|
+
ADCPError,
|
|
15
|
+
ADCPProtocolError,
|
|
16
|
+
ADCPTimeoutError,
|
|
17
|
+
ADCPToolNotFoundError,
|
|
18
|
+
ADCPWebhookError,
|
|
19
|
+
ADCPWebhookSignatureError,
|
|
20
|
+
)
|
|
21
|
+
from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata
|
|
22
|
+
from adcp.types.generated import (
|
|
23
|
+
ActivateSignalRequest,
|
|
24
|
+
ActivateSignalResponse,
|
|
25
|
+
CreateMediaBuyRequest,
|
|
26
|
+
CreateMediaBuyResponse,
|
|
27
|
+
GetMediaBuyDeliveryRequest,
|
|
28
|
+
GetMediaBuyDeliveryResponse,
|
|
29
|
+
GetProductsRequest,
|
|
30
|
+
GetProductsResponse,
|
|
31
|
+
GetSignalsRequest,
|
|
32
|
+
GetSignalsResponse,
|
|
33
|
+
ListAuthorizedPropertiesRequest,
|
|
34
|
+
ListAuthorizedPropertiesResponse,
|
|
35
|
+
ListCreativeFormatsRequest,
|
|
36
|
+
ListCreativeFormatsResponse,
|
|
37
|
+
ListCreativesRequest,
|
|
38
|
+
ListCreativesResponse,
|
|
39
|
+
MediaBuy,
|
|
40
|
+
Product,
|
|
41
|
+
ProvidePerformanceFeedbackRequest,
|
|
42
|
+
ProvidePerformanceFeedbackResponse,
|
|
43
|
+
SyncCreativesRequest,
|
|
44
|
+
SyncCreativesResponse,
|
|
45
|
+
UpdateMediaBuyRequest,
|
|
46
|
+
UpdateMediaBuyResponse,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
__version__ = "1.0.2"
|
|
10
50
|
|
|
11
|
-
__version__ = "0.1.2"
|
|
12
51
|
__all__ = [
|
|
52
|
+
# Client classes
|
|
13
53
|
"ADCPClient",
|
|
14
54
|
"ADCPMultiAgentClient",
|
|
55
|
+
# Core types
|
|
15
56
|
"AgentConfig",
|
|
57
|
+
"Protocol",
|
|
16
58
|
"TaskResult",
|
|
59
|
+
"TaskStatus",
|
|
17
60
|
"WebhookMetadata",
|
|
61
|
+
# Exceptions
|
|
62
|
+
"ADCPError",
|
|
63
|
+
"ADCPConnectionError",
|
|
64
|
+
"ADCPAuthenticationError",
|
|
65
|
+
"ADCPTimeoutError",
|
|
66
|
+
"ADCPProtocolError",
|
|
67
|
+
"ADCPToolNotFoundError",
|
|
68
|
+
"ADCPWebhookError",
|
|
69
|
+
"ADCPWebhookSignatureError",
|
|
70
|
+
# Generated request/response types
|
|
71
|
+
"GetProductsRequest",
|
|
72
|
+
"GetProductsResponse",
|
|
73
|
+
"CreateMediaBuyRequest",
|
|
74
|
+
"CreateMediaBuyResponse",
|
|
75
|
+
"UpdateMediaBuyRequest",
|
|
76
|
+
"UpdateMediaBuyResponse",
|
|
77
|
+
"SyncCreativesRequest",
|
|
78
|
+
"SyncCreativesResponse",
|
|
79
|
+
"ListCreativesRequest",
|
|
80
|
+
"ListCreativesResponse",
|
|
81
|
+
"ListCreativeFormatsRequest",
|
|
82
|
+
"ListCreativeFormatsResponse",
|
|
83
|
+
"GetMediaBuyDeliveryRequest",
|
|
84
|
+
"GetMediaBuyDeliveryResponse",
|
|
85
|
+
"ListAuthorizedPropertiesRequest",
|
|
86
|
+
"ListAuthorizedPropertiesResponse",
|
|
87
|
+
"GetSignalsRequest",
|
|
88
|
+
"GetSignalsResponse",
|
|
89
|
+
"ActivateSignalRequest",
|
|
90
|
+
"ActivateSignalResponse",
|
|
91
|
+
"ProvidePerformanceFeedbackRequest",
|
|
92
|
+
"ProvidePerformanceFeedbackResponse",
|
|
93
|
+
# Core domain types
|
|
94
|
+
"Product",
|
|
95
|
+
"MediaBuy",
|
|
18
96
|
]
|
adcp/__main__.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
"""Command-line interface for AdCP client - compatible with npx @adcp/client."""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import asyncio
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, cast
|
|
12
|
+
|
|
13
|
+
from adcp.client import ADCPClient
|
|
14
|
+
from adcp.config import (
|
|
15
|
+
CONFIG_FILE,
|
|
16
|
+
get_agent,
|
|
17
|
+
list_agents,
|
|
18
|
+
remove_agent,
|
|
19
|
+
save_agent,
|
|
20
|
+
)
|
|
21
|
+
from adcp.types.core import AgentConfig, Protocol
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def print_json(data: Any) -> None:
|
|
25
|
+
"""Print data as JSON."""
|
|
26
|
+
print(json.dumps(data, indent=2, default=str))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def print_result(result: Any, json_output: bool = False) -> None:
|
|
30
|
+
"""Print result in formatted or JSON mode."""
|
|
31
|
+
if json_output:
|
|
32
|
+
print_json(
|
|
33
|
+
{
|
|
34
|
+
"status": result.status.value,
|
|
35
|
+
"success": result.success,
|
|
36
|
+
"data": result.data,
|
|
37
|
+
"error": result.error,
|
|
38
|
+
"metadata": result.metadata,
|
|
39
|
+
"debug_info": {
|
|
40
|
+
"request": result.debug_info.request,
|
|
41
|
+
"response": result.debug_info.response,
|
|
42
|
+
"duration_ms": result.debug_info.duration_ms,
|
|
43
|
+
}
|
|
44
|
+
if result.debug_info
|
|
45
|
+
else None,
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
print(f"\nStatus: {result.status.value}")
|
|
50
|
+
if result.success:
|
|
51
|
+
if result.data:
|
|
52
|
+
print("\nResult:")
|
|
53
|
+
print_json(result.data)
|
|
54
|
+
else:
|
|
55
|
+
print(f"Error: {result.error}")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def execute_tool(
|
|
59
|
+
agent_config: dict[str, Any], tool_name: str, payload: dict[str, Any], json_output: bool = False
|
|
60
|
+
) -> None:
|
|
61
|
+
"""Execute a tool on an agent."""
|
|
62
|
+
# Ensure required fields
|
|
63
|
+
if "id" not in agent_config:
|
|
64
|
+
agent_config["id"] = agent_config.get("agent_uri", "unknown")
|
|
65
|
+
|
|
66
|
+
if "protocol" not in agent_config:
|
|
67
|
+
agent_config["protocol"] = "mcp"
|
|
68
|
+
|
|
69
|
+
# Convert string protocol to enum
|
|
70
|
+
if isinstance(agent_config["protocol"], str):
|
|
71
|
+
agent_config["protocol"] = Protocol(agent_config["protocol"].lower())
|
|
72
|
+
|
|
73
|
+
config = AgentConfig(**agent_config)
|
|
74
|
+
|
|
75
|
+
async with ADCPClient(config) as client:
|
|
76
|
+
result = await client.call_tool(tool_name, payload)
|
|
77
|
+
print_result(result, json_output)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def load_payload(payload_arg: str | None) -> dict[str, Any]:
|
|
81
|
+
"""Load payload from argument (JSON, @file, or stdin)."""
|
|
82
|
+
if not payload_arg:
|
|
83
|
+
# Try to read from stdin if available and has data
|
|
84
|
+
if not sys.stdin.isatty():
|
|
85
|
+
try:
|
|
86
|
+
return cast(dict[str, Any], json.load(sys.stdin))
|
|
87
|
+
except (json.JSONDecodeError, ValueError):
|
|
88
|
+
pass
|
|
89
|
+
return {}
|
|
90
|
+
|
|
91
|
+
if payload_arg.startswith("@"):
|
|
92
|
+
# Load from file
|
|
93
|
+
file_path = Path(payload_arg[1:])
|
|
94
|
+
if not file_path.exists():
|
|
95
|
+
print(f"Error: File not found: {file_path}", file=sys.stderr)
|
|
96
|
+
sys.exit(1)
|
|
97
|
+
return cast(dict[str, Any], json.loads(file_path.read_text()))
|
|
98
|
+
|
|
99
|
+
# Parse as JSON
|
|
100
|
+
try:
|
|
101
|
+
return cast(dict[str, Any], json.loads(payload_arg))
|
|
102
|
+
except json.JSONDecodeError as e:
|
|
103
|
+
print(f"Error: Invalid JSON payload: {e}", file=sys.stderr)
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def handle_save_auth(alias: str, url: str | None, protocol: str | None) -> None:
|
|
108
|
+
"""Handle --save-auth command."""
|
|
109
|
+
if not url:
|
|
110
|
+
# Interactive mode
|
|
111
|
+
url = input(f"Agent URL for '{alias}': ").strip()
|
|
112
|
+
if not url:
|
|
113
|
+
print("Error: URL is required", file=sys.stderr)
|
|
114
|
+
sys.exit(1)
|
|
115
|
+
|
|
116
|
+
if not protocol:
|
|
117
|
+
protocol = input("Protocol (mcp/a2a) [mcp]: ").strip() or "mcp"
|
|
118
|
+
|
|
119
|
+
auth_token = input("Auth token (optional): ").strip() or None
|
|
120
|
+
|
|
121
|
+
save_agent(alias, url, protocol, auth_token)
|
|
122
|
+
print(f"✓ Saved agent '{alias}'")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def handle_list_agents() -> None:
|
|
126
|
+
"""Handle --list-agents command."""
|
|
127
|
+
agents = list_agents()
|
|
128
|
+
|
|
129
|
+
if not agents:
|
|
130
|
+
print("No saved agents")
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
print("\nSaved agents:")
|
|
134
|
+
for alias, config in agents.items():
|
|
135
|
+
auth = "yes" if config.get("auth_token") else "no"
|
|
136
|
+
print(f" {alias}")
|
|
137
|
+
print(f" URL: {config.get('agent_uri')}")
|
|
138
|
+
print(f" Protocol: {config.get('protocol', 'mcp').upper()}")
|
|
139
|
+
print(f" Auth: {auth}")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def handle_remove_agent(alias: str) -> None:
|
|
143
|
+
"""Handle --remove-agent command."""
|
|
144
|
+
if remove_agent(alias):
|
|
145
|
+
print(f"✓ Removed agent '{alias}'")
|
|
146
|
+
else:
|
|
147
|
+
print(f"Error: Agent '{alias}' not found", file=sys.stderr)
|
|
148
|
+
sys.exit(1)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def handle_show_config() -> None:
|
|
152
|
+
"""Handle --show-config command."""
|
|
153
|
+
print(f"Config file: {CONFIG_FILE}")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def resolve_agent_config(agent_identifier: str) -> dict[str, Any]:
|
|
157
|
+
"""Resolve agent identifier to configuration."""
|
|
158
|
+
# Check if it's a saved alias
|
|
159
|
+
saved = get_agent(agent_identifier)
|
|
160
|
+
if saved:
|
|
161
|
+
return saved
|
|
162
|
+
|
|
163
|
+
# Check if it's a URL
|
|
164
|
+
if agent_identifier.startswith(("http://", "https://")):
|
|
165
|
+
return {
|
|
166
|
+
"id": agent_identifier.split("/")[-1],
|
|
167
|
+
"agent_uri": agent_identifier,
|
|
168
|
+
"protocol": "mcp",
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# Check if it's a JSON config
|
|
172
|
+
if agent_identifier.startswith("{"):
|
|
173
|
+
try:
|
|
174
|
+
return cast(dict[str, Any], json.loads(agent_identifier))
|
|
175
|
+
except json.JSONDecodeError:
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
print(f"Error: Unknown agent '{agent_identifier}'", file=sys.stderr)
|
|
179
|
+
print(" Not found as saved alias", file=sys.stderr)
|
|
180
|
+
print(" Not a valid URL", file=sys.stderr)
|
|
181
|
+
print(" Not valid JSON config", file=sys.stderr)
|
|
182
|
+
sys.exit(1)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def main() -> None:
|
|
186
|
+
"""Main CLI entry point - compatible with JavaScript version."""
|
|
187
|
+
parser = argparse.ArgumentParser(
|
|
188
|
+
description="AdCP Client - Interact with AdCP agents",
|
|
189
|
+
usage="adcp [options] <agent> [tool] [payload]",
|
|
190
|
+
add_help=False,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Configuration management
|
|
194
|
+
parser.add_argument("--save-auth", metavar="ALIAS", help="Save agent configuration")
|
|
195
|
+
parser.add_argument("--list-agents", action="store_true", help="List saved agents")
|
|
196
|
+
parser.add_argument("--remove-agent", metavar="ALIAS", help="Remove saved agent")
|
|
197
|
+
parser.add_argument("--show-config", action="store_true", help="Show config file location")
|
|
198
|
+
|
|
199
|
+
# Execution options
|
|
200
|
+
parser.add_argument("--protocol", choices=["mcp", "a2a"], help="Force protocol type")
|
|
201
|
+
parser.add_argument("--auth", help="Authentication token")
|
|
202
|
+
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
203
|
+
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
|
204
|
+
parser.add_argument("--help", "-h", action="store_true", help="Show help")
|
|
205
|
+
|
|
206
|
+
# Positional arguments
|
|
207
|
+
parser.add_argument("agent", nargs="?", help="Agent alias, URL, or config")
|
|
208
|
+
parser.add_argument("tool", nargs="?", help="Tool name to execute")
|
|
209
|
+
parser.add_argument("payload", nargs="?", help="Payload (JSON, @file, or stdin)")
|
|
210
|
+
|
|
211
|
+
# Parse known args to handle --save-auth with positional args
|
|
212
|
+
args, remaining = parser.parse_known_args()
|
|
213
|
+
|
|
214
|
+
# Handle help
|
|
215
|
+
if args.help or (
|
|
216
|
+
not args.agent
|
|
217
|
+
and not any(
|
|
218
|
+
[
|
|
219
|
+
args.save_auth,
|
|
220
|
+
args.list_agents,
|
|
221
|
+
args.remove_agent,
|
|
222
|
+
args.show_config,
|
|
223
|
+
]
|
|
224
|
+
)
|
|
225
|
+
):
|
|
226
|
+
parser.print_help()
|
|
227
|
+
print("\nExamples:")
|
|
228
|
+
print(" adcp --save-auth myagent https://agent.example.com mcp")
|
|
229
|
+
print(" adcp --list-agents")
|
|
230
|
+
print(" adcp myagent list_tools")
|
|
231
|
+
print(' adcp myagent get_products \'{"brief":"TV ads"}\'')
|
|
232
|
+
print(" adcp https://agent.example.com list_tools")
|
|
233
|
+
sys.exit(0)
|
|
234
|
+
|
|
235
|
+
# Handle configuration commands
|
|
236
|
+
if args.save_auth:
|
|
237
|
+
url = args.agent if args.agent else None
|
|
238
|
+
protocol = args.tool if args.tool else None
|
|
239
|
+
handle_save_auth(args.save_auth, url, protocol)
|
|
240
|
+
sys.exit(0)
|
|
241
|
+
|
|
242
|
+
if args.list_agents:
|
|
243
|
+
handle_list_agents()
|
|
244
|
+
sys.exit(0)
|
|
245
|
+
|
|
246
|
+
if args.remove_agent:
|
|
247
|
+
handle_remove_agent(args.remove_agent)
|
|
248
|
+
sys.exit(0)
|
|
249
|
+
|
|
250
|
+
if args.show_config:
|
|
251
|
+
handle_show_config()
|
|
252
|
+
sys.exit(0)
|
|
253
|
+
|
|
254
|
+
# Execute tool
|
|
255
|
+
if not args.agent:
|
|
256
|
+
print("Error: Agent identifier required", file=sys.stderr)
|
|
257
|
+
sys.exit(1)
|
|
258
|
+
|
|
259
|
+
if not args.tool:
|
|
260
|
+
print("Error: Tool name required", file=sys.stderr)
|
|
261
|
+
sys.exit(1)
|
|
262
|
+
|
|
263
|
+
# Resolve agent config
|
|
264
|
+
agent_config = resolve_agent_config(args.agent)
|
|
265
|
+
|
|
266
|
+
# Override with command-line options
|
|
267
|
+
if args.protocol:
|
|
268
|
+
agent_config["protocol"] = args.protocol
|
|
269
|
+
|
|
270
|
+
if args.auth:
|
|
271
|
+
agent_config["auth_token"] = args.auth
|
|
272
|
+
|
|
273
|
+
if args.debug:
|
|
274
|
+
agent_config["debug"] = True
|
|
275
|
+
|
|
276
|
+
# Load payload
|
|
277
|
+
payload = load_payload(args.payload)
|
|
278
|
+
|
|
279
|
+
# Execute
|
|
280
|
+
asyncio.run(execute_tool(agent_config, args.tool, payload, args.json))
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
if __name__ == "__main__":
|
|
284
|
+
main()
|