agentdom 3.6.0__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.
agentdom/__init__.py ADDED
@@ -0,0 +1,45 @@
1
+ """
2
+ AgentDOM Python SDK
3
+ ===================
4
+
5
+ The universal runtime that makes every website, desktop app,
6
+ and API accessible to AI agents — zero human in the loop.
7
+
8
+ pip install agentdom
9
+
10
+ Usage (Flask):
11
+ from agentdom import AgentDOM
12
+
13
+ agent = AgentDOM(host="api.myapp.com")
14
+
15
+ @agent.capability("todos.create", description="Create a todo")
16
+ def create_todo(args):
17
+ return {"id": 1, "title": args["title"]}
18
+
19
+ agent.register(app)
20
+
21
+ Usage (FastAPI):
22
+ from agentdom import AgentDOM
23
+
24
+ agent = AgentDOM(host="api.myapp.com")
25
+
26
+ @agent.capability("items.list", description="List items")
27
+ async def list_items(args):
28
+ return [{"id": 1, "name": "Widget"}]
29
+
30
+ agent.register(fastapi_app)
31
+
32
+ Usage (standalone dispatch):
33
+ from agentdom import dispatch_intent
34
+
35
+ result = await dispatch_intent("issues.create", {
36
+ "title": "Bug report",
37
+ "body": "Reproducible on iOS 17"
38
+ }, host="github.com")
39
+ """
40
+
41
+ from agentdom.core import AgentDOM, AgentCapability
42
+ from agentdom.dispatch import dispatch_intent
43
+
44
+ __version__ = "1.0.0"
45
+ __all__ = ["AgentDOM", "AgentCapability", "dispatch_intent", "__version__"]
agentdom/core.py ADDED
@@ -0,0 +1,206 @@
1
+ """
2
+ agentdom.core — AgentDOM class and capability registration.
3
+ """
4
+
5
+ import datetime
6
+ from typing import Callable, List, Optional
7
+
8
+
9
+ class AgentCapability:
10
+ """A single declared capability (intent + handler)."""
11
+
12
+ def __init__(
13
+ self,
14
+ intent: str,
15
+ description: str,
16
+ handler: Callable,
17
+ args: dict = None,
18
+ side_effects: list = None,
19
+ method: str = "POST",
20
+ ):
21
+ self.intent = intent
22
+ self.description = description
23
+ self.handler = handler
24
+ self.args = args or {}
25
+ self.side_effects = side_effects or ["write_local"]
26
+ self.method = method
27
+
28
+
29
+ class AgentDOM:
30
+ """
31
+ Embed AgentDOM into any Python web app.
32
+
33
+ Serves /.well-known/agentdom.json automatically and routes
34
+ incoming agent intents to your handler functions.
35
+
36
+ Args:
37
+ host: Your public domain (e.g. "api.myapp.com")
38
+ name: Human-readable name (defaults to host)
39
+ description: Short description of your service
40
+ auth: Auth config dict, e.g. {"method": "api_key", ...}
41
+ api_base_path: Route prefix for intent endpoints (default: /api/agentdom)
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ host: str,
47
+ name: Optional[str] = None,
48
+ description: Optional[str] = None,
49
+ auth: Optional[dict] = None,
50
+ api_base_path: str = "/api/agentdom",
51
+ ):
52
+ if not host:
53
+ raise ValueError("AgentDOM: host is required")
54
+ self.host = host
55
+ self.name = name or host
56
+ self.description = description or f"AgentDOM manifest for {host}"
57
+ self.auth = auth or {"method": "none"}
58
+ self.api_base_path = api_base_path
59
+ self._capabilities: List[AgentCapability] = []
60
+
61
+ def capability(
62
+ self,
63
+ intent: str,
64
+ description: str = "",
65
+ args: dict = None,
66
+ side_effects: list = None,
67
+ method: str = "POST",
68
+ ):
69
+ """
70
+ Decorator to register a capability handler.
71
+
72
+ Example:
73
+ @agent.capability("todos.create", description="Create a todo")
74
+ def create_todo(args):
75
+ return db.todos.insert(args["title"])
76
+ """
77
+ def decorator(fn: Callable):
78
+ cap = AgentCapability(
79
+ intent=intent,
80
+ description=description,
81
+ handler=fn,
82
+ args=args or {},
83
+ side_effects=side_effects or ["write_local"],
84
+ method=method,
85
+ )
86
+ self._capabilities.append(cap)
87
+ return fn
88
+ return decorator
89
+
90
+ def manifest(self) -> dict:
91
+ """
92
+ Build and return the agentdom.json manifest as a Python dict.
93
+ Serve this at GET /.well-known/agentdom.json.
94
+ """
95
+ return {
96
+ "version": "1.0",
97
+ "host": self.host,
98
+ "name": self.name,
99
+ "description": self.description,
100
+ "generated_at": datetime.datetime.utcnow().isoformat() + "Z",
101
+ "generated_by": "agentdom-python/1.0.0",
102
+ "auth": self.auth,
103
+ "capabilities": [
104
+ {
105
+ "intent": cap.intent,
106
+ "description": cap.description,
107
+ "transport": "api",
108
+ "method": cap.method,
109
+ "endpoint": f"https://{self.host}{self.api_base_path}/{cap.intent}",
110
+ "args": {
111
+ k: {
112
+ "type": v if isinstance(v, str) else v.get("type", "string"),
113
+ "required": v.get("required", False) if isinstance(v, dict) else True,
114
+ "description": v.get("description", "") if isinstance(v, dict) else "",
115
+ }
116
+ for k, v in cap.args.items()
117
+ },
118
+ "side_effects": cap.side_effects,
119
+ }
120
+ for cap in self._capabilities
121
+ ],
122
+ }
123
+
124
+ def register(self, app):
125
+ """
126
+ Auto-detect Flask or FastAPI and register all routes.
127
+
128
+ Registers:
129
+ GET /.well-known/agentdom.json → serves the manifest
130
+ POST /api/agentdom/<intent> → dispatches to your handler
131
+ """
132
+ app_module = type(app).__module__
133
+
134
+ if "flask" in app_module:
135
+ self._register_flask(app)
136
+ elif "fastapi" in app_module:
137
+ self._register_fastapi(app)
138
+ else:
139
+ raise ValueError(
140
+ "AgentDOM.register() expects a Flask or FastAPI app instance. "
141
+ "For other frameworks, use .manifest() and route manually."
142
+ )
143
+
144
+ def _register_flask(self, app):
145
+ """Attach routes to a Flask app."""
146
+ from flask import request, jsonify
147
+
148
+ manifest = self.manifest()
149
+ cap_map = {cap.intent: cap for cap in self._capabilities}
150
+
151
+ @app.route("/.well-known/agentdom.json", methods=["GET"])
152
+ def agentdom_manifest():
153
+ return jsonify(manifest)
154
+
155
+ @app.route(f"{self.api_base_path}/<path:intent>", methods=["POST"])
156
+ def agentdom_intent(intent):
157
+ cap = cap_map.get(intent)
158
+ if not cap:
159
+ return jsonify({
160
+ "error": f"Intent '{intent}' not found",
161
+ "available": list(cap_map.keys()),
162
+ }), 404
163
+
164
+ try:
165
+ body = request.get_json(silent=True) or {}
166
+ result = cap.handler(body)
167
+ return jsonify({"success": True, "result": result})
168
+ except Exception as exc:
169
+ return jsonify({"success": False, "error": str(exc)}), 500
170
+
171
+ def _register_fastapi(self, app):
172
+ """Attach routes to a FastAPI app."""
173
+ from fastapi import Request
174
+ from fastapi.responses import JSONResponse
175
+
176
+ manifest = self.manifest()
177
+ cap_map = {cap.intent: cap for cap in self._capabilities}
178
+
179
+ @app.get("/.well-known/agentdom.json")
180
+ async def agentdom_manifest():
181
+ return JSONResponse(
182
+ manifest,
183
+ headers={"Cache-Control": "public, max-age=3600", "Access-Control-Allow-Origin": "*"},
184
+ )
185
+
186
+ @app.post(f"{self.api_base_path}/{{intent:path}}")
187
+ async def agentdom_intent(intent: str, request: Request):
188
+ import asyncio
189
+ cap = cap_map.get(intent)
190
+ if not cap:
191
+ return JSONResponse(
192
+ {"error": f"Intent '{intent}' not found", "available": list(cap_map.keys())},
193
+ status_code=404,
194
+ )
195
+ try:
196
+ body = await request.json()
197
+ except Exception:
198
+ body = {}
199
+ try:
200
+ if asyncio.iscoroutinefunction(cap.handler):
201
+ result = await cap.handler(body)
202
+ else:
203
+ result = cap.handler(body)
204
+ return JSONResponse({"success": True, "result": result})
205
+ except Exception as exc:
206
+ return JSONResponse({"success": False, "error": str(exc)}, status_code=500)
agentdom/dispatch.py ADDED
@@ -0,0 +1,103 @@
1
+ """
2
+ agentdom.dispatch — dispatch_intent() for calling any AgentDOM-compatible service.
3
+
4
+ This is the consumer-side function. It fetches the manifest from a host,
5
+ finds the capability matching the intent, and executes it via the declared transport.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ from typing import Any, Optional
11
+
12
+
13
+ async def dispatch_intent(
14
+ intent: str,
15
+ args: dict,
16
+ host: str,
17
+ token: Optional[str] = None,
18
+ agentdom_api: Optional[str] = None,
19
+ ) -> Any:
20
+ """
21
+ Dispatch an intent to an AgentDOM-compatible host.
22
+
23
+ This is the main consumer-side function. It:
24
+ 1. Fetches the /.well-known/agentdom.json manifest from the host
25
+ 2. Finds the capability matching `intent`
26
+ 3. Executes the call via the declared transport (api, browser, desktop)
27
+
28
+ Args:
29
+ intent: Intent name, e.g. "issues.create"
30
+ args: Intent arguments dict
31
+ host: Target host, e.g. "github.com"
32
+ token: Auth token (overrides env var lookup)
33
+ agentdom_api: AgentDOM API server URL (default: https://api.getagentdom.com)
34
+
35
+ Returns:
36
+ The result from the remote capability.
37
+
38
+ Raises:
39
+ ValueError: If the intent is not found in the manifest.
40
+ httpx.HTTPStatusError: If the HTTP request fails.
41
+
42
+ Example:
43
+ from agentdom import dispatch_intent
44
+
45
+ result = await dispatch_intent(
46
+ "issues.create",
47
+ {"title": "Bug in login", "body": "Steps to reproduce..."},
48
+ host="github.com",
49
+ )
50
+ print(result) # → {"id": 42, "url": "https://github.com/..."}
51
+ """
52
+ try:
53
+ import httpx
54
+ except ImportError:
55
+ raise ImportError(
56
+ "agentdom dispatch requires httpx: pip install agentdom[dispatch]"
57
+ )
58
+
59
+ api_base = agentdom_api or os.environ.get("AGENTDOM_API_URL", "https://api.getagentdom.com")
60
+
61
+ # Resolve auth token from env if not provided
62
+ if not token:
63
+ env_key = host.upper().replace(".", "_") + "_TOKEN"
64
+ token = os.environ.get(env_key) or os.environ.get("AGENTDOM_TOKEN")
65
+
66
+ headers = {"Content-Type": "application/json"}
67
+ if token:
68
+ headers["Authorization"] = f"Bearer {token}"
69
+
70
+ payload = {"intent": intent, "host": host, "args": args}
71
+
72
+ async with httpx.AsyncClient(timeout=30) as client:
73
+ res = await client.post(
74
+ f"{api_base}/api/agentdom/dispatch",
75
+ headers=headers,
76
+ json=payload,
77
+ )
78
+ res.raise_for_status()
79
+ data = res.json()
80
+ return data.get("result", data)
81
+
82
+
83
+ def dispatch_intent_sync(
84
+ intent: str,
85
+ args: dict,
86
+ host: str,
87
+ token: Optional[str] = None,
88
+ agentdom_api: Optional[str] = None,
89
+ ) -> Any:
90
+ """
91
+ Synchronous version of dispatch_intent for non-async code.
92
+
93
+ Example:
94
+ from agentdom import dispatch_intent_sync
95
+
96
+ result = dispatch_intent_sync(
97
+ "repos.list",
98
+ {"username": "octocat"},
99
+ host="github.com",
100
+ )
101
+ """
102
+ import asyncio
103
+ return asyncio.run(dispatch_intent(intent, args, host, token, agentdom_api))
@@ -0,0 +1,241 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentdom
3
+ Version: 3.6.0
4
+ Summary: The universal runtime that makes every website, desktop app, and API accessible to AI agents — zero human in the loop.
5
+ Project-URL: Homepage, https://getagentdom.com
6
+ Project-URL: Documentation, https://getagentdom.com/docs/python
7
+ Project-URL: Repository, https://github.com/RagavRida/agentdom
8
+ Project-URL: Changelog, https://github.com/RagavRida/agentdom/blob/main/CHANGELOG.md
9
+ Project-URL: Bug Tracker, https://github.com/RagavRida/agentdom/issues
10
+ Author-email: Ragavendhra Machikatla <hi@getagentdom.com>
11
+ License: MIT
12
+ Keywords: agentdom,agents,ai,automation,browser,dispatch,llm,mcp,protocol,rpa
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
25
+ Requires-Python: >=3.9
26
+ Provides-Extra: all
27
+ Requires-Dist: fastapi>=0.100; extra == 'all'
28
+ Requires-Dist: flask>=2.0; extra == 'all'
29
+ Requires-Dist: httpx>=0.25; extra == 'all'
30
+ Requires-Dist: uvicorn>=0.20; extra == 'all'
31
+ Provides-Extra: dev
32
+ Requires-Dist: build; extra == 'dev'
33
+ Requires-Dist: flake8>=7; extra == 'dev'
34
+ Requires-Dist: httpx>=0.25; extra == 'dev'
35
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
36
+ Requires-Dist: pytest>=8; extra == 'dev'
37
+ Requires-Dist: twine; extra == 'dev'
38
+ Provides-Extra: dispatch
39
+ Requires-Dist: httpx>=0.25; extra == 'dispatch'
40
+ Provides-Extra: fastapi
41
+ Requires-Dist: fastapi>=0.100; extra == 'fastapi'
42
+ Requires-Dist: uvicorn>=0.20; extra == 'fastapi'
43
+ Provides-Extra: flask
44
+ Requires-Dist: flask>=2.0; extra == 'flask'
45
+ Description-Content-Type: text/markdown
46
+
47
+ # agentdom
48
+
49
+ **The universal runtime that makes every website, desktop app, and API accessible to AI agents — zero human in the loop.**
50
+
51
+ [![PyPI version](https://img.shields.io/pypi/v/agentdom?color=f97316&style=flat-square)](https://pypi.org/project/agentdom/)
52
+ [![Python versions](https://img.shields.io/pypi/pyversions/agentdom?style=flat-square)](https://pypi.org/project/agentdom/)
53
+ [![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/RagavRida/agentdom/blob/main/LICENSE)
54
+ [![npm](https://img.shields.io/npm/v/agentdom?label=npm&color=f97316&style=flat-square)](https://www.npmjs.com/package/agentdom)
55
+
56
+ [Website](https://getagentdom.com) · [Docs](https://getagentdom.com/docs/python) · [GitHub](https://github.com/RagavRida/agentdom) · [npm package](https://www.npmjs.com/package/agentdom)
57
+
58
+ ---
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ pip install agentdom
64
+ ```
65
+
66
+ With framework support:
67
+
68
+ ```bash
69
+ pip install "agentdom[flask]" # Flask integration
70
+ pip install "agentdom[fastapi]" # FastAPI integration
71
+ pip install "agentdom[dispatch]" # dispatch_intent() support (requires httpx)
72
+ pip install "agentdom[all]" # everything
73
+ ```
74
+
75
+ ## Quick start — dispatch an intent
76
+
77
+ ```python
78
+ import asyncio
79
+ from agentdom import dispatch_intent
80
+
81
+ async def main():
82
+ # Create a GitHub issue — routes via REST API, no browser needed
83
+ result = await dispatch_intent(
84
+ "issues.create",
85
+ {
86
+ "title": "Login crash on iOS 17",
87
+ "body": "Reproducible on iPhone 15 Pro",
88
+ "labels": ["bug", "mobile"],
89
+ },
90
+ host="github.com",
91
+ )
92
+ print(result) # → {"id": 42, "url": "https://github.com/..."}
93
+
94
+ asyncio.run(main())
95
+ ```
96
+
97
+ Or synchronously:
98
+
99
+ ```python
100
+ from agentdom import dispatch_intent_sync
101
+
102
+ result = dispatch_intent_sync("repos.list", {"username": "octocat"}, host="github.com")
103
+ ```
104
+
105
+ ## Embed AgentDOM in your app
106
+
107
+ ### Flask
108
+
109
+ ```python
110
+ from flask import Flask
111
+ from agentdom import AgentDOM
112
+
113
+ app = Flask(__name__)
114
+ agent = AgentDOM(
115
+ host="api.myapp.com",
116
+ auth={"method": "api_key", "key_header": "Authorization"},
117
+ )
118
+
119
+ @agent.capability("todos.create", description="Create a new todo item",
120
+ args={"title": {"type": "string", "required": True}})
121
+ def create_todo(args):
122
+ return {"id": 1, "title": args["title"]}
123
+
124
+ @agent.capability("todos.list", description="List all todo items")
125
+ def list_todos(args):
126
+ return [{"id": 1, "title": "Buy milk"}]
127
+
128
+ agent.register(app)
129
+
130
+ # Now your app automatically serves:
131
+ # GET /.well-known/agentdom.json → manifest
132
+ # POST /api/agentdom/todos.create → your handler
133
+ # POST /api/agentdom/todos.list → your handler
134
+ ```
135
+
136
+ ### FastAPI
137
+
138
+ ```python
139
+ from fastapi import FastAPI
140
+ from agentdom import AgentDOM
141
+
142
+ app = FastAPI()
143
+ agent = AgentDOM(host="api.myapp.com")
144
+
145
+ @agent.capability("orders.ship", description="Ship a pending order",
146
+ args={"order_id": {"type": "string", "required": True}})
147
+ async def ship_order(args):
148
+ # async handlers are fully supported
149
+ return await shipping_service.ship(args["order_id"])
150
+
151
+ agent.register(app)
152
+ ```
153
+
154
+ ### Standalone manifest
155
+
156
+ ```python
157
+ from agentdom import AgentDOM
158
+
159
+ agent = AgentDOM(host="api.myapp.com")
160
+
161
+ @agent.capability("items.create", description="Create an item")
162
+ def create_item(args):
163
+ return {"created": True}
164
+
165
+ # Get the manifest dict to serve however you like
166
+ manifest = agent.manifest()
167
+ print(manifest)
168
+ # → {"version": "1.0", "host": "api.myapp.com", "capabilities": [...], ...}
169
+ ```
170
+
171
+ ## Auth configuration
172
+
173
+ ```python
174
+ # API key
175
+ agent = AgentDOM(
176
+ host="api.myapp.com",
177
+ auth={
178
+ "method": "api_key",
179
+ "key_header": "Authorization",
180
+ "key_format": "Bearer {token}",
181
+ },
182
+ )
183
+
184
+ # OAuth 2.0
185
+ agent = AgentDOM(
186
+ host="api.myapp.com",
187
+ auth={
188
+ "method": "oauth2",
189
+ "auth_url": "https://api.myapp.com/oauth/authorize",
190
+ "token_url": "https://api.myapp.com/oauth/token",
191
+ "scopes": ["read", "write"],
192
+ },
193
+ )
194
+
195
+ # No auth (public API)
196
+ agent = AgentDOM(host="api.myapp.com", auth={"method": "none"})
197
+ ```
198
+
199
+ ## Environment variables
200
+
201
+ | Variable | Description |
202
+ |---|---|
203
+ | `AGENTDOM_API_URL` | Override the AgentDOM API server URL |
204
+ | `AGENTDOM_TOKEN` | Default auth token for dispatch_intent |
205
+ | `<HOST>_TOKEN` | Per-host token (e.g. `GITHUB_COM_TOKEN`) |
206
+
207
+ ## Agent Token Protocol
208
+
209
+ Publishers can declare an `agent_tokens` endpoint so agents provision their own scoped tokens automatically:
210
+
211
+ ```python
212
+ agent = AgentDOM(
213
+ host="api.myapp.com",
214
+ auth={
215
+ "method": "api_key",
216
+ "agent_tokens": {
217
+ "issue": "POST https://api.myapp.com/agent-tokens",
218
+ "revoke": "DELETE https://api.myapp.com/agent-tokens/{id}",
219
+ "scopes": ["read", "write"],
220
+ "max_ttl_seconds": 86400,
221
+ },
222
+ },
223
+ )
224
+ ```
225
+
226
+ ## Supported providers
227
+
228
+ | Provider | Auth | Capabilities |
229
+ |---|---|---|
230
+ | `github.com` | Device Flow | repos, issues, PRs, actions (811) |
231
+ | `linear.app` | OAuth 2.0 | issues, teams, cycles (8) |
232
+ | `slack.com` | OAuth 2.0 | messages, channels (6) |
233
+ | `notion.so` | OAuth 2.0 | pages, databases (6) |
234
+ | `stripe.com` | API Key | payments, customers (442) |
235
+ | `resend.com` | API Key | emails, domains (5) |
236
+
237
+ More providers at [getagentdom.com/providers](https://getagentdom.com/providers).
238
+
239
+ ## License
240
+
241
+ MIT © [Ragavendhra Machikatla](https://github.com/RagavRida)
@@ -0,0 +1,6 @@
1
+ agentdom/__init__.py,sha256=5C2ICG7LQxobd23_FUUPe8G52bpb5ra712RVym_ZA9w,1150
2
+ agentdom/core.py,sha256=t5agQmECgzVFb0Pi4ttzabEowLM3EYu9LTx6_QTYavU,7169
3
+ agentdom/dispatch.py,sha256=ioERHOrE6nDRoyrbRC1xnXx7gZ4tpK4nHpH2q-RjL3c,3108
4
+ agentdom-3.6.0.dist-info/METADATA,sha256=259ATgq64pPo1DttzQqM9KSPyKw_T_SZtNPe26owIIs,7482
5
+ agentdom-3.6.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
6
+ agentdom-3.6.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any