aimarket-agent 2.0.0__tar.gz
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.
- aimarket_agent-2.0.0/LICENSE +21 -0
- aimarket_agent-2.0.0/PKG-INFO +125 -0
- aimarket_agent-2.0.0/README.md +104 -0
- aimarket_agent-2.0.0/aimarket_agent/__init__.py +15 -0
- aimarket_agent-2.0.0/aimarket_agent/agent.py +268 -0
- aimarket_agent-2.0.0/aimarket_agent/cli.py +167 -0
- aimarket_agent-2.0.0/aimarket_agent.egg-info/PKG-INFO +125 -0
- aimarket_agent-2.0.0/aimarket_agent.egg-info/SOURCES.txt +12 -0
- aimarket_agent-2.0.0/aimarket_agent.egg-info/dependency_links.txt +1 -0
- aimarket_agent-2.0.0/aimarket_agent.egg-info/entry_points.txt +2 -0
- aimarket_agent-2.0.0/aimarket_agent.egg-info/requires.txt +6 -0
- aimarket_agent-2.0.0/aimarket_agent.egg-info/top_level.txt +1 -0
- aimarket_agent-2.0.0/pyproject.toml +29 -0
- aimarket_agent-2.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AI-Factory Project Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aimarket-agent
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Reference consumer agent for AIMarket Protocol v2 — AI-to-AI discovery, payment, invoke
|
|
5
|
+
Author-email: AI-Factory <dev@modelmarket.dev>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/alexar76/aimarket-agent
|
|
8
|
+
Project-URL: Documentation, https://github.com/alexar76/aimarket-agent#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/alexar76/aimarket-agent
|
|
10
|
+
Project-URL: Issues, https://github.com/alexar76/aimarket-agent/issues
|
|
11
|
+
Keywords: aimarket,ai-agents,marketplace,mcp,agent,httpx,sdk
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: httpx>=0.28
|
|
16
|
+
Requires-Dist: cryptography>=44
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-httpx>=0.35; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
<!-- aicom-mirror-notice -->
|
|
23
|
+
> **Mirror — read-only.**
|
|
24
|
+
> The canonical source for `aimarket-agent` lives in the AI-Factory monorepo.
|
|
25
|
+
> Open issues and PRs at `Superowner/aicom`; commits pushed here are
|
|
26
|
+
> overwritten by `scripts/mirror_satellites.sh` on the next sync run.
|
|
27
|
+
> See `docs/repository-canonical-policy.md` for the policy.
|
|
28
|
+
|
|
29
|
+
# AIMarket Agent v2.0.0
|
|
30
|
+
|
|
31
|
+
**Reference consumer agent for the AIMarket Protocol.**
|
|
32
|
+
`pip install aimarket-agent` — any AI (Claude, GPT, Cursor, LangChain) can discover, pay, and invoke capabilities across the AIMarket federation. MIT Licensed.
|
|
33
|
+
|
|
34
|
+
## Live Hub
|
|
35
|
+
|
|
36
|
+
This agent connects to **[modelmarket.dev](https://modelmarket.dev)** — the reference hub with 12 capabilities and 14 plugins.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install aimarket-agent
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Full autonomous cycle
|
|
48
|
+
aimarket-agent run "translate spec to 5 languages + legal review" \
|
|
49
|
+
--base-url https://modelmarket.dev \
|
|
50
|
+
--budget 3.00
|
|
51
|
+
|
|
52
|
+
# Search capabilities
|
|
53
|
+
aimarket-agent search "code review" --base-url https://modelmarket.dev
|
|
54
|
+
|
|
55
|
+
# Invoke a single capability
|
|
56
|
+
aimarket-agent invoke prod-translate/translate.multi@v2 \
|
|
57
|
+
--base-url https://modelmarket.dev \
|
|
58
|
+
--input '{"text":"Hello world"}'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Python SDK
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from aimarket_agent import AIMarketAgent
|
|
65
|
+
|
|
66
|
+
agent = AIMarketAgent(
|
|
67
|
+
base_url="https://modelmarket.dev",
|
|
68
|
+
budget=3.00,
|
|
69
|
+
affiliate_id="my_app"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Full cycle: discover → channel → invoke → settle → BOM
|
|
73
|
+
result = agent.run("translate spec to 5 languages + legal review")
|
|
74
|
+
print(f"Spent: ${result['total_spent_usd']:.2f}")
|
|
75
|
+
|
|
76
|
+
# Discovery only
|
|
77
|
+
capabilities = agent.discover("summarize long documents")
|
|
78
|
+
for c in capabilities:
|
|
79
|
+
print(f" {c['capability_id']} — ${c.get('price_per_call_usd', 0):.2f}")
|
|
80
|
+
|
|
81
|
+
# Single invoke
|
|
82
|
+
result = agent.invoke_single(
|
|
83
|
+
"prod-translate", "translate.multi@v2",
|
|
84
|
+
{"text": "Hello world", "locales": ["ru", "fr", "de"]}
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Full Autonomous Cycle
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
① GET /.well-known/ai-market.json → discover hub
|
|
92
|
+
② POST /ai-market/discover → search capabilities
|
|
93
|
+
③ POST /ai-market/channel/open → pre-fund channel
|
|
94
|
+
④ POST /capabilities/{pid}/{cid}/invoke → invoke (safety-gated)
|
|
95
|
+
⑤ POST /ai-market/channel/close → settle + refund
|
|
96
|
+
⑥ Save bill_of_materials.json → signed audit trail
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Safety Gate
|
|
100
|
+
|
|
101
|
+
If an invocation is blocked by the safety gate (injection, PII, etc.), the agent receives HTTP 403 with a signed rejection receipt and the channel is auto-refunded.
|
|
102
|
+
|
|
103
|
+
## Output
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
[discover] 12 capabilities across 12 products
|
|
107
|
+
[plan] translate.multi@v2 (est $0.40)
|
|
108
|
+
[channel] opened ch_a8f3 with $3.00 deposit
|
|
109
|
+
[call] translate.multi@v2 ....... $0.40 ✓ 8.1s
|
|
110
|
+
[settle] used $0.40, refund $2.60
|
|
111
|
+
[saved] bill_of_materials.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Configuration
|
|
115
|
+
|
|
116
|
+
| CLI flag | Default | Description |
|
|
117
|
+
|----------|---------|-------------|
|
|
118
|
+
| `--base-url` | `http://127.0.0.1:9083` | Hub URL |
|
|
119
|
+
| `--budget` | `3.0` | Max budget in USD |
|
|
120
|
+
| `--affiliate` | — | Affiliate ID for revenue share |
|
|
121
|
+
| `--json` | false | Output as JSON |
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT · Maintained by AI-Factory · [modelmarket.dev](https://modelmarket.dev) · [Hub API](https://modelmarket.dev/.well-known/ai-market.json)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<!-- aicom-mirror-notice -->
|
|
2
|
+
> **Mirror — read-only.**
|
|
3
|
+
> The canonical source for `aimarket-agent` lives in the AI-Factory monorepo.
|
|
4
|
+
> Open issues and PRs at `Superowner/aicom`; commits pushed here are
|
|
5
|
+
> overwritten by `scripts/mirror_satellites.sh` on the next sync run.
|
|
6
|
+
> See `docs/repository-canonical-policy.md` for the policy.
|
|
7
|
+
|
|
8
|
+
# AIMarket Agent v2.0.0
|
|
9
|
+
|
|
10
|
+
**Reference consumer agent for the AIMarket Protocol.**
|
|
11
|
+
`pip install aimarket-agent` — any AI (Claude, GPT, Cursor, LangChain) can discover, pay, and invoke capabilities across the AIMarket federation. MIT Licensed.
|
|
12
|
+
|
|
13
|
+
## Live Hub
|
|
14
|
+
|
|
15
|
+
This agent connects to **[modelmarket.dev](https://modelmarket.dev)** — the reference hub with 12 capabilities and 14 plugins.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install aimarket-agent
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Full autonomous cycle
|
|
27
|
+
aimarket-agent run "translate spec to 5 languages + legal review" \
|
|
28
|
+
--base-url https://modelmarket.dev \
|
|
29
|
+
--budget 3.00
|
|
30
|
+
|
|
31
|
+
# Search capabilities
|
|
32
|
+
aimarket-agent search "code review" --base-url https://modelmarket.dev
|
|
33
|
+
|
|
34
|
+
# Invoke a single capability
|
|
35
|
+
aimarket-agent invoke prod-translate/translate.multi@v2 \
|
|
36
|
+
--base-url https://modelmarket.dev \
|
|
37
|
+
--input '{"text":"Hello world"}'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Python SDK
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from aimarket_agent import AIMarketAgent
|
|
44
|
+
|
|
45
|
+
agent = AIMarketAgent(
|
|
46
|
+
base_url="https://modelmarket.dev",
|
|
47
|
+
budget=3.00,
|
|
48
|
+
affiliate_id="my_app"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Full cycle: discover → channel → invoke → settle → BOM
|
|
52
|
+
result = agent.run("translate spec to 5 languages + legal review")
|
|
53
|
+
print(f"Spent: ${result['total_spent_usd']:.2f}")
|
|
54
|
+
|
|
55
|
+
# Discovery only
|
|
56
|
+
capabilities = agent.discover("summarize long documents")
|
|
57
|
+
for c in capabilities:
|
|
58
|
+
print(f" {c['capability_id']} — ${c.get('price_per_call_usd', 0):.2f}")
|
|
59
|
+
|
|
60
|
+
# Single invoke
|
|
61
|
+
result = agent.invoke_single(
|
|
62
|
+
"prod-translate", "translate.multi@v2",
|
|
63
|
+
{"text": "Hello world", "locales": ["ru", "fr", "de"]}
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Full Autonomous Cycle
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
① GET /.well-known/ai-market.json → discover hub
|
|
71
|
+
② POST /ai-market/discover → search capabilities
|
|
72
|
+
③ POST /ai-market/channel/open → pre-fund channel
|
|
73
|
+
④ POST /capabilities/{pid}/{cid}/invoke → invoke (safety-gated)
|
|
74
|
+
⑤ POST /ai-market/channel/close → settle + refund
|
|
75
|
+
⑥ Save bill_of_materials.json → signed audit trail
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Safety Gate
|
|
79
|
+
|
|
80
|
+
If an invocation is blocked by the safety gate (injection, PII, etc.), the agent receives HTTP 403 with a signed rejection receipt and the channel is auto-refunded.
|
|
81
|
+
|
|
82
|
+
## Output
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
[discover] 12 capabilities across 12 products
|
|
86
|
+
[plan] translate.multi@v2 (est $0.40)
|
|
87
|
+
[channel] opened ch_a8f3 with $3.00 deposit
|
|
88
|
+
[call] translate.multi@v2 ....... $0.40 ✓ 8.1s
|
|
89
|
+
[settle] used $0.40, refund $2.60
|
|
90
|
+
[saved] bill_of_materials.json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
| CLI flag | Default | Description |
|
|
96
|
+
|----------|---------|-------------|
|
|
97
|
+
| `--base-url` | `http://127.0.0.1:9083` | Hub URL |
|
|
98
|
+
| `--budget` | `3.0` | Max budget in USD |
|
|
99
|
+
| `--affiliate` | — | Affiliate ID for revenue share |
|
|
100
|
+
| `--json` | false | Output as JSON |
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT · Maintained by AI-Factory · [modelmarket.dev](https://modelmarket.dev) · [Hub API](https://modelmarket.dev/.well-known/ai-market.json)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""AIMarket Agent v2.0.0 — Reference consumer for AIMarket Protocol.
|
|
2
|
+
|
|
3
|
+
MIT Licensed. Lightweight pip-installable agent that any AI (Claude, GPT,
|
|
4
|
+
Cursor, LangChain) can use to discover, pay, and invoke capabilities
|
|
5
|
+
across the AIMarket federation.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
pip install aimarket-agent
|
|
9
|
+
aimarket-agent run "translate spec to 5 languages" --budget 3.00
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from aimarket_agent.agent import AIMarketAgent
|
|
13
|
+
|
|
14
|
+
__all__ = ["AIMarketAgent", "__version__"]
|
|
15
|
+
__version__ = "2.0.0"
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""AIMarketAgent — The reference consumer for Protocol v2.
|
|
2
|
+
|
|
3
|
+
Encapsulates the full autonomous cycle:
|
|
4
|
+
discovery → channel open → invoke (safety-gated) → settle → bill of materials.
|
|
5
|
+
|
|
6
|
+
Lightweight: only httpx + cryptography dependencies. No FastAPI, no database.
|
|
7
|
+
Designed to be pip-installed by any AI agent runtime.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
import time
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import httpx
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AIMarketAgent:
|
|
21
|
+
"""Reference consumer for AIMarket Protocol v2.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
agent = AIMarketAgent(base_url="https://hub.example.com", budget=3.00)
|
|
25
|
+
result = agent.run("translate spec to 5 langs + legal review")
|
|
26
|
+
print(result["bill_of_materials"])
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
base_url: str,
|
|
32
|
+
budget: float = 3.0,
|
|
33
|
+
timeout: float = 120.0,
|
|
34
|
+
affiliate_id: str = "",
|
|
35
|
+
):
|
|
36
|
+
self.base_url = base_url.rstrip("/")
|
|
37
|
+
self.budget = budget
|
|
38
|
+
self.timeout = timeout
|
|
39
|
+
self.affiliate_id = affiliate_id
|
|
40
|
+
self.session = httpx.Client(timeout=timeout)
|
|
41
|
+
|
|
42
|
+
def _url(self, path: str) -> str:
|
|
43
|
+
return f"{self.base_url}{path}"
|
|
44
|
+
|
|
45
|
+
def _open_channel(self) -> str:
|
|
46
|
+
"""Try to open a payment channel; return channel_id or "" if hub has no channels plugin."""
|
|
47
|
+
try:
|
|
48
|
+
ch = self.session.post(
|
|
49
|
+
self._url("/ai-market/v2/channel/open"),
|
|
50
|
+
json={"deposit_usd": self.budget, "tx_hash": f"agent-{int(time.time())}"},
|
|
51
|
+
)
|
|
52
|
+
if ch.status_code == 404:
|
|
53
|
+
return "" # channels plugin not installed on this hub
|
|
54
|
+
ch.raise_for_status()
|
|
55
|
+
return (ch.json().get("channel") or {}).get("channel_id", "")
|
|
56
|
+
except Exception:
|
|
57
|
+
return ""
|
|
58
|
+
|
|
59
|
+
def _close_channel(self, channel_id: str) -> dict[str, Any]:
|
|
60
|
+
if not channel_id:
|
|
61
|
+
return {"skipped": "no channel was opened"}
|
|
62
|
+
try:
|
|
63
|
+
r = self.session.post(
|
|
64
|
+
self._url("/ai-market/v2/channel/close"),
|
|
65
|
+
json={"channel_id": channel_id, "settle_tx_hash": f"agent-settle-{channel_id}"},
|
|
66
|
+
)
|
|
67
|
+
r.raise_for_status()
|
|
68
|
+
return r.json().get("settlement") or {}
|
|
69
|
+
except Exception:
|
|
70
|
+
return {"error": "settle failed"}
|
|
71
|
+
|
|
72
|
+
def run(self, task: str) -> dict[str, Any]:
|
|
73
|
+
"""Execute the full autonomous cycle for *task*.
|
|
74
|
+
|
|
75
|
+
Returns bill-of-materials dict with all receipts.
|
|
76
|
+
"""
|
|
77
|
+
result: dict[str, Any] = {"task": task, "ok": False}
|
|
78
|
+
|
|
79
|
+
# ── Phase 1: Discovery ──────────────────────────────────
|
|
80
|
+
try:
|
|
81
|
+
wk = self.session.get(self._url("/.well-known/ai-market.json"))
|
|
82
|
+
wk.raise_for_status()
|
|
83
|
+
except Exception as exc:
|
|
84
|
+
return {**result, "error": f"discovery failed: {exc}"}
|
|
85
|
+
|
|
86
|
+
# Hub v3 exposes capability discovery via GET /ai-market/v2/search.
|
|
87
|
+
# Older drafts proposed POST /ai-market/discover with a "plan" response —
|
|
88
|
+
# we fall back to v2 search and synthesise a one-step plan per match.
|
|
89
|
+
plan: list[dict[str, Any]] = []
|
|
90
|
+
try:
|
|
91
|
+
search = self.session.get(
|
|
92
|
+
self._url("/ai-market/v2/search"),
|
|
93
|
+
params={
|
|
94
|
+
"intent": task,
|
|
95
|
+
"budget": str(self.budget),
|
|
96
|
+
"limit": "6",
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
search.raise_for_status()
|
|
100
|
+
matches = search.json().get("matches") or []
|
|
101
|
+
for m in matches:
|
|
102
|
+
plan.append({
|
|
103
|
+
"product_id": m.get("product_id", ""),
|
|
104
|
+
"capability_id": m.get("capability_id", ""),
|
|
105
|
+
"source_hub": m.get("source_hub", "local"),
|
|
106
|
+
"draft_input": {"text": task},
|
|
107
|
+
"est_price_usd": m.get("routed_price_usd") or m.get("price_per_call_usd", 0),
|
|
108
|
+
})
|
|
109
|
+
except Exception as exc:
|
|
110
|
+
return {**result, "error": f"search failed: {exc}"}
|
|
111
|
+
|
|
112
|
+
if not plan:
|
|
113
|
+
return {**result, "plan": [], "note": "no matching capabilities"}
|
|
114
|
+
|
|
115
|
+
# Cap plan at first match for predictable spend; multi-step DAGs are a
|
|
116
|
+
# future protocol-level feature (pipelines endpoint).
|
|
117
|
+
plan = plan[:1]
|
|
118
|
+
result["plan"] = plan
|
|
119
|
+
result["estimated_total_usd"] = sum(s["est_price_usd"] for s in plan)
|
|
120
|
+
|
|
121
|
+
# ── Phase 2: Channel open (optional) ──────────────────
|
|
122
|
+
channel_id = self._open_channel()
|
|
123
|
+
result["channel_id"] = channel_id
|
|
124
|
+
|
|
125
|
+
# ── Phase 3: Invoke each step ──────────────────────────
|
|
126
|
+
results: list[dict[str, Any]] = []
|
|
127
|
+
context: dict[str, Any] = {}
|
|
128
|
+
total_spent = 0.0
|
|
129
|
+
all_ok = True
|
|
130
|
+
|
|
131
|
+
for step in plan:
|
|
132
|
+
pid = step["product_id"]
|
|
133
|
+
cid = step["capability_id"]
|
|
134
|
+
source_hub = step.get("source_hub", "local")
|
|
135
|
+
inp = dict(step.get("draft_input") or {})
|
|
136
|
+
if context:
|
|
137
|
+
inp.setdefault("context", context)
|
|
138
|
+
|
|
139
|
+
headers: dict[str, str] = {}
|
|
140
|
+
if channel_id:
|
|
141
|
+
headers["X-Payment-Channel"] = channel_id
|
|
142
|
+
if self.affiliate_id:
|
|
143
|
+
headers["X-AIMarket-Affiliate"] = self.affiliate_id
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
r = self.session.post(
|
|
147
|
+
self._url("/ai-market/v2/invoke"),
|
|
148
|
+
json={
|
|
149
|
+
"product_id": pid,
|
|
150
|
+
"capability_id": cid,
|
|
151
|
+
"source_hub": source_hub,
|
|
152
|
+
"input": inp,
|
|
153
|
+
},
|
|
154
|
+
headers=headers,
|
|
155
|
+
)
|
|
156
|
+
except Exception as exc:
|
|
157
|
+
results.append({"error": str(exc), "capability_id": cid})
|
|
158
|
+
all_ok = False
|
|
159
|
+
break
|
|
160
|
+
|
|
161
|
+
if r.status_code == 403:
|
|
162
|
+
rejection = r.json()
|
|
163
|
+
results.append({
|
|
164
|
+
"capability_id": cid,
|
|
165
|
+
"safety_blocked": True,
|
|
166
|
+
"category": rejection.get("category"),
|
|
167
|
+
"reason": rejection.get("reason"),
|
|
168
|
+
})
|
|
169
|
+
all_ok = False
|
|
170
|
+
break
|
|
171
|
+
|
|
172
|
+
if r.status_code == 402:
|
|
173
|
+
results.append({
|
|
174
|
+
"capability_id": cid,
|
|
175
|
+
"payment_required": True,
|
|
176
|
+
"detail": r.json(),
|
|
177
|
+
})
|
|
178
|
+
all_ok = False
|
|
179
|
+
break
|
|
180
|
+
|
|
181
|
+
if not r.is_success:
|
|
182
|
+
results.append({"error": f"HTTP {r.status_code}", "capability_id": cid})
|
|
183
|
+
all_ok = False
|
|
184
|
+
break
|
|
185
|
+
|
|
186
|
+
body = r.json()
|
|
187
|
+
price_val = body.get("price_usd", 0) or 0
|
|
188
|
+
total_spent += price_val
|
|
189
|
+
results.append(body)
|
|
190
|
+
|
|
191
|
+
if body.get("success"):
|
|
192
|
+
context = body.get("result") or {}
|
|
193
|
+
else:
|
|
194
|
+
all_ok = False
|
|
195
|
+
break
|
|
196
|
+
|
|
197
|
+
# ── Phase 4: Settle ─────────────────────────────────────
|
|
198
|
+
settlement = self._close_channel(channel_id)
|
|
199
|
+
|
|
200
|
+
# ── Phase 5: Bill of materials ──────────────────────────
|
|
201
|
+
bom: dict[str, Any] = {
|
|
202
|
+
"task": task,
|
|
203
|
+
"plan": plan,
|
|
204
|
+
"results": results,
|
|
205
|
+
"settlement": settlement,
|
|
206
|
+
"channel_id": channel_id,
|
|
207
|
+
"total_spent_usd": round(total_spent, 4),
|
|
208
|
+
"all_ok": all_ok,
|
|
209
|
+
"protocol_version": "v2",
|
|
210
|
+
"agent_version": "2.0.0",
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
result["ok"] = all_ok
|
|
214
|
+
result["bill_of_materials"] = bom
|
|
215
|
+
result["total_spent_usd"] = round(total_spent, 4)
|
|
216
|
+
return result
|
|
217
|
+
|
|
218
|
+
def discover(self, query: str, limit: int = 8) -> list[dict[str, Any]]:
|
|
219
|
+
"""Search for capabilities without invoking."""
|
|
220
|
+
try:
|
|
221
|
+
r = self.session.get(
|
|
222
|
+
self._url("/ai-market/v2/search"),
|
|
223
|
+
params={"intent": query, "budget": str(self.budget), "limit": str(limit)},
|
|
224
|
+
)
|
|
225
|
+
r.raise_for_status()
|
|
226
|
+
return r.json().get("matches") or []
|
|
227
|
+
except Exception:
|
|
228
|
+
return []
|
|
229
|
+
|
|
230
|
+
def invoke_single(
|
|
231
|
+
self,
|
|
232
|
+
product_id: str,
|
|
233
|
+
capability_id: str,
|
|
234
|
+
input_payload: dict[str, Any],
|
|
235
|
+
source_hub: str = "local",
|
|
236
|
+
) -> dict[str, Any]:
|
|
237
|
+
"""Invoke a single capability directly."""
|
|
238
|
+
channel_id = self._open_channel()
|
|
239
|
+
headers: dict[str, str] = {}
|
|
240
|
+
if channel_id:
|
|
241
|
+
headers["X-Payment-Channel"] = channel_id
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
r = self.session.post(
|
|
245
|
+
self._url("/ai-market/v2/invoke"),
|
|
246
|
+
json={
|
|
247
|
+
"product_id": product_id,
|
|
248
|
+
"capability_id": capability_id,
|
|
249
|
+
"source_hub": source_hub,
|
|
250
|
+
"input": input_payload,
|
|
251
|
+
},
|
|
252
|
+
headers=headers,
|
|
253
|
+
)
|
|
254
|
+
finally:
|
|
255
|
+
self._close_channel(channel_id)
|
|
256
|
+
|
|
257
|
+
if r.status_code == 403:
|
|
258
|
+
return {"safety_blocked": True, **r.json()}
|
|
259
|
+
return r.json()
|
|
260
|
+
|
|
261
|
+
def close(self) -> None:
|
|
262
|
+
self.session.close()
|
|
263
|
+
|
|
264
|
+
def __enter__(self) -> "AIMarketAgent":
|
|
265
|
+
return self
|
|
266
|
+
|
|
267
|
+
def __exit__(self, *exc_info: Any) -> None:
|
|
268
|
+
self.close()
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""AIMarket Agent CLI — pip-installable reference consumer.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
aimarket-agent run "translate spec to 5 langs" --budget 3.00
|
|
6
|
+
aimarket-agent search "legal review"
|
|
7
|
+
aimarket-agent invoke prod-xxx/translate.multi@v2 --input '{"text":"hello"}'
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
from aimarket_agent.agent import AIMarketAgent
|
|
17
|
+
|
|
18
|
+
_BOLD = "\033[1m"
|
|
19
|
+
_DIM = "\033[2m"
|
|
20
|
+
_GREEN = "\033[32m"
|
|
21
|
+
_YELLOW = "\033[33m"
|
|
22
|
+
_RED = "\033[31m"
|
|
23
|
+
_RESET = "\033[0m"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main() -> int:
|
|
27
|
+
parser = argparse.ArgumentParser(
|
|
28
|
+
description="AIMarket Agent — AI-to-AI protocol consumer"
|
|
29
|
+
)
|
|
30
|
+
sub = parser.add_subparsers(dest="command")
|
|
31
|
+
|
|
32
|
+
# run
|
|
33
|
+
run_p = sub.add_parser("run", help="Execute full autonomous cycle")
|
|
34
|
+
run_p.add_argument("task", nargs="?", default="translate spec to 5 langs + legal review")
|
|
35
|
+
run_p.add_argument("--base-url", default="http://127.0.0.1:9083")
|
|
36
|
+
run_p.add_argument("--budget", type=float, default=3.0)
|
|
37
|
+
run_p.add_argument("--affiliate", default="")
|
|
38
|
+
run_p.add_argument("--json", action="store_true")
|
|
39
|
+
|
|
40
|
+
# search
|
|
41
|
+
search_p = sub.add_parser("search", help="Discover capabilities")
|
|
42
|
+
search_p.add_argument("query", nargs="?", default="")
|
|
43
|
+
search_p.add_argument("--base-url", default="http://127.0.0.1:9083")
|
|
44
|
+
search_p.add_argument("--limit", type=int, default=8)
|
|
45
|
+
search_p.add_argument("--json", action="store_true")
|
|
46
|
+
|
|
47
|
+
# invoke
|
|
48
|
+
invoke_p = sub.add_parser("invoke", help="Invoke a single capability")
|
|
49
|
+
invoke_p.add_argument("capability_ref", help="product_id/capability_id")
|
|
50
|
+
invoke_p.add_argument("--base-url", default="http://127.0.0.1:9083")
|
|
51
|
+
invoke_p.add_argument("--input", default="{}", help="JSON input payload")
|
|
52
|
+
invoke_p.add_argument("--budget", type=float, default=3.0)
|
|
53
|
+
|
|
54
|
+
args = parser.parse_args()
|
|
55
|
+
|
|
56
|
+
if args.command == "run":
|
|
57
|
+
return _cmd_run(args)
|
|
58
|
+
elif args.command == "search":
|
|
59
|
+
return _cmd_search(args)
|
|
60
|
+
elif args.command == "invoke":
|
|
61
|
+
return _cmd_invoke(args)
|
|
62
|
+
else:
|
|
63
|
+
parser.print_help()
|
|
64
|
+
return 0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _cmd_run(args) -> int:
|
|
68
|
+
agent = AIMarketAgent(
|
|
69
|
+
base_url=args.base_url,
|
|
70
|
+
budget=args.budget,
|
|
71
|
+
affiliate_id=args.affiliate,
|
|
72
|
+
)
|
|
73
|
+
try:
|
|
74
|
+
result = agent.run(args.task)
|
|
75
|
+
except KeyboardInterrupt:
|
|
76
|
+
print(f"{_YELLOW}Interrupted{_RESET}", file=sys.stderr)
|
|
77
|
+
return 130
|
|
78
|
+
finally:
|
|
79
|
+
agent.close()
|
|
80
|
+
|
|
81
|
+
if args.json:
|
|
82
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
83
|
+
return 0 if result.get("ok") else 1
|
|
84
|
+
|
|
85
|
+
if result.get("error"):
|
|
86
|
+
print(f"[{_RED}error{_RESET}] {result['error']}", file=sys.stderr)
|
|
87
|
+
return 1
|
|
88
|
+
|
|
89
|
+
plan = result.get("plan") or []
|
|
90
|
+
steps = " → ".join(s["capability_id"] for s in plan)
|
|
91
|
+
est = result.get("estimated_total_usd", 0)
|
|
92
|
+
print(f"[{_GREEN}plan{_RESET}] {steps} (est ${est:.2f})")
|
|
93
|
+
|
|
94
|
+
bom = result.get("bill_of_materials") or {}
|
|
95
|
+
for r in bom.get("results") or []:
|
|
96
|
+
if r.get("safety_blocked"):
|
|
97
|
+
print(f"[{_RED}safety{_RESET}] {r['capability_id']} blocked: {r.get('category', '?')}")
|
|
98
|
+
continue
|
|
99
|
+
ok = r.get("success")
|
|
100
|
+
mark = "✓" if ok else "✗"
|
|
101
|
+
color = _GREEN if ok else _RED
|
|
102
|
+
print(f"[{color}call{_RESET}] {r.get('capability_id', '?')} ${r.get('price_usd', 0):.2f} {mark}")
|
|
103
|
+
|
|
104
|
+
settlement = bom.get("settlement") or {}
|
|
105
|
+
used = settlement.get("used_usd", 0)
|
|
106
|
+
refund = settlement.get("refund_usd", 0)
|
|
107
|
+
print(f"[{_GREEN}settle{_RESET}] used ${used:.2f}, refund ${refund:.2f}")
|
|
108
|
+
|
|
109
|
+
total = result.get("total_spent_usd", 0)
|
|
110
|
+
print(f"[{_BOLD}total{_RESET}] ${total:.2f}")
|
|
111
|
+
|
|
112
|
+
out_path = "bill_of_materials.json"
|
|
113
|
+
with open(out_path, "w") as f:
|
|
114
|
+
json.dump(bom, f, indent=2, ensure_ascii=False)
|
|
115
|
+
print(f"[{_DIM}saved{_RESET}] {out_path}")
|
|
116
|
+
|
|
117
|
+
return 0 if result.get("ok") else 1
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _cmd_search(args) -> int:
|
|
121
|
+
agent = AIMarketAgent(base_url=args.base_url)
|
|
122
|
+
try:
|
|
123
|
+
matches = agent.discover(args.query, limit=args.limit)
|
|
124
|
+
finally:
|
|
125
|
+
agent.close()
|
|
126
|
+
|
|
127
|
+
if args.json:
|
|
128
|
+
print(json.dumps(matches, indent=2, ensure_ascii=False))
|
|
129
|
+
return 0
|
|
130
|
+
|
|
131
|
+
print(f"\n{_BOLD}Search: \"{args.query}\"{_RESET}\n")
|
|
132
|
+
for i, m in enumerate(matches, 1):
|
|
133
|
+
print(f" {i}. {_BOLD}{m.get('capability_id', '?')}{_RESET}")
|
|
134
|
+
print(f" ${m.get('price_per_call_usd', 0):.2f} · {m.get('p50_latency_ms', '?')}ms")
|
|
135
|
+
if m.get("source_hub_name"):
|
|
136
|
+
print(f" 🌐 {m['source_hub_name']} (trust: {m.get('trust_score', '?')})")
|
|
137
|
+
print()
|
|
138
|
+
return 0
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _cmd_invoke(args) -> int:
|
|
142
|
+
parts = args.capability_ref.split("/", 1)
|
|
143
|
+
product_id = parts[0]
|
|
144
|
+
capability_id = parts[1] if len(parts) > 1 else parts[0]
|
|
145
|
+
inp = json.loads(args.input)
|
|
146
|
+
|
|
147
|
+
agent = AIMarketAgent(base_url=args.base_url, budget=args.budget)
|
|
148
|
+
try:
|
|
149
|
+
result = agent.invoke_single(product_id, capability_id, inp)
|
|
150
|
+
finally:
|
|
151
|
+
agent.close()
|
|
152
|
+
|
|
153
|
+
if result.get("safety_blocked"):
|
|
154
|
+
print(f"[{_RED}safety{_RESET}] Blocked: {result.get('category')} — {result.get('reason')}")
|
|
155
|
+
return 1
|
|
156
|
+
|
|
157
|
+
ok = result.get("success", False)
|
|
158
|
+
mark = "✓" if ok else "✗"
|
|
159
|
+
color = _GREEN if ok else _RED
|
|
160
|
+
print(f"[{color}invoke{_RESET}] {capability_id} ${result.get('price_usd', 0):.2f} {mark}")
|
|
161
|
+
if ok:
|
|
162
|
+
print(json.dumps(result.get("result", {}), indent=2, ensure_ascii=False))
|
|
163
|
+
return 0 if ok else 1
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == "__main__":
|
|
167
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aimarket-agent
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Reference consumer agent for AIMarket Protocol v2 — AI-to-AI discovery, payment, invoke
|
|
5
|
+
Author-email: AI-Factory <dev@modelmarket.dev>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/alexar76/aimarket-agent
|
|
8
|
+
Project-URL: Documentation, https://github.com/alexar76/aimarket-agent#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/alexar76/aimarket-agent
|
|
10
|
+
Project-URL: Issues, https://github.com/alexar76/aimarket-agent/issues
|
|
11
|
+
Keywords: aimarket,ai-agents,marketplace,mcp,agent,httpx,sdk
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: httpx>=0.28
|
|
16
|
+
Requires-Dist: cryptography>=44
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-httpx>=0.35; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
<!-- aicom-mirror-notice -->
|
|
23
|
+
> **Mirror — read-only.**
|
|
24
|
+
> The canonical source for `aimarket-agent` lives in the AI-Factory monorepo.
|
|
25
|
+
> Open issues and PRs at `Superowner/aicom`; commits pushed here are
|
|
26
|
+
> overwritten by `scripts/mirror_satellites.sh` on the next sync run.
|
|
27
|
+
> See `docs/repository-canonical-policy.md` for the policy.
|
|
28
|
+
|
|
29
|
+
# AIMarket Agent v2.0.0
|
|
30
|
+
|
|
31
|
+
**Reference consumer agent for the AIMarket Protocol.**
|
|
32
|
+
`pip install aimarket-agent` — any AI (Claude, GPT, Cursor, LangChain) can discover, pay, and invoke capabilities across the AIMarket federation. MIT Licensed.
|
|
33
|
+
|
|
34
|
+
## Live Hub
|
|
35
|
+
|
|
36
|
+
This agent connects to **[modelmarket.dev](https://modelmarket.dev)** — the reference hub with 12 capabilities and 14 plugins.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install aimarket-agent
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Full autonomous cycle
|
|
48
|
+
aimarket-agent run "translate spec to 5 languages + legal review" \
|
|
49
|
+
--base-url https://modelmarket.dev \
|
|
50
|
+
--budget 3.00
|
|
51
|
+
|
|
52
|
+
# Search capabilities
|
|
53
|
+
aimarket-agent search "code review" --base-url https://modelmarket.dev
|
|
54
|
+
|
|
55
|
+
# Invoke a single capability
|
|
56
|
+
aimarket-agent invoke prod-translate/translate.multi@v2 \
|
|
57
|
+
--base-url https://modelmarket.dev \
|
|
58
|
+
--input '{"text":"Hello world"}'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Python SDK
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from aimarket_agent import AIMarketAgent
|
|
65
|
+
|
|
66
|
+
agent = AIMarketAgent(
|
|
67
|
+
base_url="https://modelmarket.dev",
|
|
68
|
+
budget=3.00,
|
|
69
|
+
affiliate_id="my_app"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Full cycle: discover → channel → invoke → settle → BOM
|
|
73
|
+
result = agent.run("translate spec to 5 languages + legal review")
|
|
74
|
+
print(f"Spent: ${result['total_spent_usd']:.2f}")
|
|
75
|
+
|
|
76
|
+
# Discovery only
|
|
77
|
+
capabilities = agent.discover("summarize long documents")
|
|
78
|
+
for c in capabilities:
|
|
79
|
+
print(f" {c['capability_id']} — ${c.get('price_per_call_usd', 0):.2f}")
|
|
80
|
+
|
|
81
|
+
# Single invoke
|
|
82
|
+
result = agent.invoke_single(
|
|
83
|
+
"prod-translate", "translate.multi@v2",
|
|
84
|
+
{"text": "Hello world", "locales": ["ru", "fr", "de"]}
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Full Autonomous Cycle
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
① GET /.well-known/ai-market.json → discover hub
|
|
92
|
+
② POST /ai-market/discover → search capabilities
|
|
93
|
+
③ POST /ai-market/channel/open → pre-fund channel
|
|
94
|
+
④ POST /capabilities/{pid}/{cid}/invoke → invoke (safety-gated)
|
|
95
|
+
⑤ POST /ai-market/channel/close → settle + refund
|
|
96
|
+
⑥ Save bill_of_materials.json → signed audit trail
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Safety Gate
|
|
100
|
+
|
|
101
|
+
If an invocation is blocked by the safety gate (injection, PII, etc.), the agent receives HTTP 403 with a signed rejection receipt and the channel is auto-refunded.
|
|
102
|
+
|
|
103
|
+
## Output
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
[discover] 12 capabilities across 12 products
|
|
107
|
+
[plan] translate.multi@v2 (est $0.40)
|
|
108
|
+
[channel] opened ch_a8f3 with $3.00 deposit
|
|
109
|
+
[call] translate.multi@v2 ....... $0.40 ✓ 8.1s
|
|
110
|
+
[settle] used $0.40, refund $2.60
|
|
111
|
+
[saved] bill_of_materials.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Configuration
|
|
115
|
+
|
|
116
|
+
| CLI flag | Default | Description |
|
|
117
|
+
|----------|---------|-------------|
|
|
118
|
+
| `--base-url` | `http://127.0.0.1:9083` | Hub URL |
|
|
119
|
+
| `--budget` | `3.0` | Max budget in USD |
|
|
120
|
+
| `--affiliate` | — | Affiliate ID for revenue share |
|
|
121
|
+
| `--json` | false | Output as JSON |
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT · Maintained by AI-Factory · [modelmarket.dev](https://modelmarket.dev) · [Hub API](https://modelmarket.dev/.well-known/ai-market.json)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
aimarket_agent/__init__.py
|
|
5
|
+
aimarket_agent/agent.py
|
|
6
|
+
aimarket_agent/cli.py
|
|
7
|
+
aimarket_agent.egg-info/PKG-INFO
|
|
8
|
+
aimarket_agent.egg-info/SOURCES.txt
|
|
9
|
+
aimarket_agent.egg-info/dependency_links.txt
|
|
10
|
+
aimarket_agent.egg-info/entry_points.txt
|
|
11
|
+
aimarket_agent.egg-info/requires.txt
|
|
12
|
+
aimarket_agent.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aimarket_agent
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=75", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aimarket-agent"
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "Reference consumer agent for AIMarket Protocol v2 — AI-to-AI discovery, payment, invoke"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{name = "AI-Factory", email = "dev@modelmarket.dev"}]
|
|
13
|
+
keywords = ["aimarket", "ai-agents", "marketplace", "mcp", "agent", "httpx", "sdk"]
|
|
14
|
+
dependencies = ["httpx>=0.28", "cryptography>=44"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://github.com/alexar76/aimarket-agent"
|
|
18
|
+
Documentation = "https://github.com/alexar76/aimarket-agent#readme"
|
|
19
|
+
Repository = "https://github.com/alexar76/aimarket-agent"
|
|
20
|
+
Issues = "https://github.com/alexar76/aimarket-agent/issues"
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
dev = ["pytest>=8", "pytest-httpx>=0.35"]
|
|
24
|
+
|
|
25
|
+
[project.scripts]
|
|
26
|
+
aimarket-agent = "aimarket_agent.cli:main"
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.packages.find]
|
|
29
|
+
include = ["aimarket_agent*"]
|