forgeintel-sdk 0.1.0b1__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.
- forgeintel_sdk-0.1.0b1/.gitignore +17 -0
- forgeintel_sdk-0.1.0b1/LICENSE +21 -0
- forgeintel_sdk-0.1.0b1/PKG-INFO +160 -0
- forgeintel_sdk-0.1.0b1/README.md +134 -0
- forgeintel_sdk-0.1.0b1/pyproject.toml +46 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/__init__.py +7 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/asgi.py +303 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/core.py +616 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/ids.py +44 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/openapi.py +363 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/py.typed +0 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/reporter.py +101 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/signals.py +147 -0
- forgeintel_sdk-0.1.0b1/src/forgeintel/wire.py +163 -0
- forgeintel_sdk-0.1.0b1/tests/conftest.py +110 -0
- forgeintel_sdk-0.1.0b1/tests/fixtures/feedback-ids.json +16 -0
- forgeintel_sdk-0.1.0b1/tests/test_ids.py +45 -0
- forgeintel_sdk-0.1.0b1/tests/test_lifecycle.py +226 -0
- forgeintel_sdk-0.1.0b1/tests/test_openapi.py +186 -0
- forgeintel_sdk-0.1.0b1/tests/test_sdk.py +359 -0
- forgeintel_sdk-0.1.0b1/tests/test_x402.py +166 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Forge Intel
|
|
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,160 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: forgeintel-sdk
|
|
3
|
+
Version: 0.1.0b1
|
|
4
|
+
Summary: Forge telemetry, agent context and feedback for Python x402 APIs
|
|
5
|
+
Project-URL: Documentation, https://docs.development.forgeintel.co/integrations/python
|
|
6
|
+
Project-URL: Repository, https://github.com/ClawCash/forge-feedback
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Framework :: FastAPI
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Requires-Dist: httpx<1,>=0.27
|
|
18
|
+
Provides-Extra: test
|
|
19
|
+
Requires-Dist: build>=1.2; extra == 'test'
|
|
20
|
+
Requires-Dist: fastapi<1,>=0.115; extra == 'test'
|
|
21
|
+
Requires-Dist: pytest-asyncio<2,>=0.24; extra == 'test'
|
|
22
|
+
Requires-Dist: pytest<10,>=8; extra == 'test'
|
|
23
|
+
Requires-Dist: ruff>=0.11; extra == 'test'
|
|
24
|
+
Requires-Dist: x402[evm,fastapi]==2.5.0; extra == 'test'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Forge SDK for Python
|
|
28
|
+
|
|
29
|
+
`forgeintel-sdk` (import `forgeintel`) brings Forge telemetry, agent context and
|
|
30
|
+
feedback to x402 services running FastAPI, Starlette, or another ASGI app.
|
|
31
|
+
Python 3.11+. Beta source package; **not yet published to PyPI**.
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
# From this repository
|
|
35
|
+
python -m pip install ./packages/sdk-python
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import os
|
|
40
|
+
from fastapi import FastAPI
|
|
41
|
+
from forgeintel import Forge, ForgeMiddleware
|
|
42
|
+
|
|
43
|
+
app = FastAPI()
|
|
44
|
+
# Install your x402 payment middleware here, FIRST.
|
|
45
|
+
|
|
46
|
+
forge = Forge(
|
|
47
|
+
api_key=os.environ["FORGE_API_KEY"],
|
|
48
|
+
backend_url="https://api.forgeintel.co/api/sdk/v2",
|
|
49
|
+
public_url="https://api.example.com",
|
|
50
|
+
)
|
|
51
|
+
# Starlette runs the LAST added middleware FIRST.
|
|
52
|
+
app.add_middleware(ForgeMiddleware, forge=forge)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See the complete runnable merchant in [`examples/fastapi`](../../examples/fastapi).
|
|
56
|
+
Plain ASGI: `app = forge.wrap(app)`. Use one Forge instance per application/event
|
|
57
|
+
loop. ASGI lifespan shutdown flushes and closes Forge automatically. When lifespan
|
|
58
|
+
is disabled, call `await forge.shutdown()` in your application's shutdown hook.
|
|
59
|
+
|
|
60
|
+
## What ships
|
|
61
|
+
|
|
62
|
+
- x402 v1 JSON challenges / `X-PAYMENT` and v2 `PAYMENT-REQUIRED` /
|
|
63
|
+
`PAYMENT-SIGNATURE` / `PAYMENT-RESPONSE`. Existing payment terms and merchant
|
|
64
|
+
extensions, including Bazaar, remain intact.
|
|
65
|
+
- Locally signed feedback IDs, byte-compatible with the TypeScript SDK and Forge
|
|
66
|
+
v2 collector. IDs, response decoration and context parsing need **no Forge
|
|
67
|
+
network round trip on the merchant request path**. This is not a payment
|
|
68
|
+
processor: the existing x402 middleware still verifies and settles payments.
|
|
69
|
+
- Background discovery, challenge and interaction telemetry with the same header
|
|
70
|
+
allowlist as TypeScript. AgentCash, awal and pay.sh hints reach the backend,
|
|
71
|
+
where caller classification and generic-traffic filtering happen.
|
|
72
|
+
- Agent context required on paid requests when enabled and stripped before
|
|
73
|
+
merchant validation, in JSON bodies or query parameters. Configured
|
|
74
|
+
independently from feedback.
|
|
75
|
+
- Feedback ID header, optional JSON body fields and optional plain-text trailer;
|
|
76
|
+
structured feedback in v2 challenge and successful settlement extensions.
|
|
77
|
+
- Public feedback form, GET rating, POST rating with note, cached summary.
|
|
78
|
+
Only these explicit rating/summary routes await the Forge backend. The backend
|
|
79
|
+
owns rating idempotency and the correction window.
|
|
80
|
+
- OpenAPI 3.0–3.2 / Swagger 2.0 JSON enrichment. Shared schema components remain
|
|
81
|
+
untouched. Composed schemas are conservatively header-only; JSON/YAML that
|
|
82
|
+
cannot be safely enriched is served unchanged.
|
|
83
|
+
- Bounded event queue (1,000), batches (100), 5-second delivery timeout, retry
|
|
84
|
+
after failure, diagnostics and a bounded shutdown flush. Best-effort delivery,
|
|
85
|
+
not durable storage; separate queues per worker. Requires an asyncio event loop.
|
|
86
|
+
|
|
87
|
+
## Options
|
|
88
|
+
|
|
89
|
+
All option names use Python `snake_case`; pass keyword arguments to `Forge` or a
|
|
90
|
+
`ForgeOptions` dataclass. The Python beta deliberately supports the core options,
|
|
91
|
+
not TypeScript's custom tone/wording overrides.
|
|
92
|
+
|
|
93
|
+
| Option | Default | Behavior |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `api_key`, `backend_url`, `public_url` | required | Merchant credentials, collector and public service URL. Never infer URLs from Host. Use the `/api/sdk/v2` collector URL; an origin-only backend URL selects `/v1`. |
|
|
96
|
+
| `feedback` | `True` | Feedback IDs, prompts and routes. False retains telemetry with an internal interaction UUID. |
|
|
97
|
+
| `base_path` | `/feedback` | Free feedback routes; must not collide with merchant routes. |
|
|
98
|
+
| `agent_context` | `True` | Require context on paid requests. `AgentContextOptions(search_query=False)` requires only the agent name; `False` disables context. Legacy `required=False` is ignored. |
|
|
99
|
+
| `describe_challenges`, `challenge_extension`, `receipt_extension` | `True` | Feedback additions on x402 challenges/receipts. |
|
|
100
|
+
| `inject_body`, `rate_hint` | `True` | Paid JSON object fields and rating sentence. |
|
|
101
|
+
| `inject_text` | `False` | Opt-in trailer on paid `text/plain` responses. |
|
|
102
|
+
| `openapi` | `True` | Boolean or `OpenAPIOptions(paths=("/openapi.json",), document=None, is_paid_operation=None)`. Document can be a dict or sync/async provider. |
|
|
103
|
+
| `ttl_ms` | `86400000` | Must match backend feedback TTL. |
|
|
104
|
+
| `flush_interval_ms` | `2000` | Background event flush interval. |
|
|
105
|
+
| `strict` | `False` | Raise on invalid options in CI; otherwise disable Forge and leave the API unchanged. |
|
|
106
|
+
| `on_error` | logging warning | Optional error callback; callback failures are isolated. |
|
|
107
|
+
|
|
108
|
+
`Forge(..., http_client=client)` accepts a caller-owned `httpx.AsyncClient` for
|
|
109
|
+
custom transports/testing. The caller closes an injected client.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from forgeintel import AgentContextOptions, OpenAPIOptions
|
|
113
|
+
|
|
114
|
+
forge = Forge(
|
|
115
|
+
api_key="ffk_...",
|
|
116
|
+
backend_url="https://api.forgeintel.co/api/sdk/v2",
|
|
117
|
+
public_url="https://api.example.com",
|
|
118
|
+
agent_context=AgentContextOptions(search_query=True),
|
|
119
|
+
# FastAPI doesn't infer 402 responses from payment middleware. Declare them
|
|
120
|
+
# on paid routes, or explicitly select the paid operations here.
|
|
121
|
+
openapi=OpenAPIOptions(is_paid_operation=lambda method, path, op: path == "/weather"),
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Required context rejects payment-bearing requests with HTTP 400 **before** x402
|
|
126
|
+
processing. It requires a listed `agent_type` and `search_query` (`direct` when no
|
|
127
|
+
search was used), unless `search_query=False`. Initial unpaid challenges,
|
|
128
|
+
inspection and feedback routes remain available. This mode is opt-in.
|
|
129
|
+
|
|
130
|
+
JSON requests are read up to 1 MiB. Optional mode replays oversized, compressed or
|
|
131
|
+
invalid bodies unchanged; use query parameters for those bodies. Required mode
|
|
132
|
+
rejects unreadable JSON. Binary uploads are never buffered by Forge. Agent context
|
|
133
|
+
is still stripped when collection is disabled, where the body can be inspected.
|
|
134
|
+
|
|
135
|
+
JSON responses are rewritten only when bounded to 1 MiB (5 MiB for OpenAPI).
|
|
136
|
+
Unknown-length multi-chunk streams, SSE, compressed bodies, partial responses and
|
|
137
|
+
binary files remain unchanged; successful paid responses still receive the ID
|
|
138
|
+
header. Forge removes stale validators when it changes bytes and preserves repeated
|
|
139
|
+
headers such as `Set-Cookie`. No feedback is injected into redirects or errors.
|
|
140
|
+
|
|
141
|
+
For strict response schemas, provide `OpenAPIOptions(document=app.openapi)` or a
|
|
142
|
+
static document **and call `forge.enrich_openapi(app.openapi())` before serving
|
|
143
|
+
traffic**. Otherwise schema-aware body injection starts after the first spec fetch.
|
|
144
|
+
For a mounted app or reverse-proxy `root_path` such as `/api`, configure public paths: `base_path="/api/feedback"` and `OpenAPIOptions(paths=("/api/openapi.json",), ...)`.
|
|
145
|
+
Place Forge inside response compression and outside payment middleware. Framework
|
|
146
|
+
exceptions propagate normally; Forge never retries a merchant handler.
|
|
147
|
+
|
|
148
|
+
## Development
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
python -m venv packages/sdk-python/.venv
|
|
152
|
+
packages/sdk-python/.venv/bin/pip install -e './packages/sdk-python[test]'
|
|
153
|
+
packages/sdk-python/.venv/bin/python -m pytest packages/sdk-python/tests
|
|
154
|
+
packages/sdk-python/.venv/bin/python -m build packages/sdk-python
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Tests include the real `x402==2.5.0` FastAPI middleware and client, with a fake
|
|
158
|
+
facilitator (no funds spent), ASGI streaming/body limits and shared TypeScript ID
|
|
159
|
+
vectors. Live merchant rollout and PyPI publication are separate release steps.
|
|
160
|
+
MPP and Flask/WSGI are deferred.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Forge SDK for Python
|
|
2
|
+
|
|
3
|
+
`forgeintel-sdk` (import `forgeintel`) brings Forge telemetry, agent context and
|
|
4
|
+
feedback to x402 services running FastAPI, Starlette, or another ASGI app.
|
|
5
|
+
Python 3.11+. Beta source package; **not yet published to PyPI**.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
# From this repository
|
|
9
|
+
python -m pip install ./packages/sdk-python
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import os
|
|
14
|
+
from fastapi import FastAPI
|
|
15
|
+
from forgeintel import Forge, ForgeMiddleware
|
|
16
|
+
|
|
17
|
+
app = FastAPI()
|
|
18
|
+
# Install your x402 payment middleware here, FIRST.
|
|
19
|
+
|
|
20
|
+
forge = Forge(
|
|
21
|
+
api_key=os.environ["FORGE_API_KEY"],
|
|
22
|
+
backend_url="https://api.forgeintel.co/api/sdk/v2",
|
|
23
|
+
public_url="https://api.example.com",
|
|
24
|
+
)
|
|
25
|
+
# Starlette runs the LAST added middleware FIRST.
|
|
26
|
+
app.add_middleware(ForgeMiddleware, forge=forge)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
See the complete runnable merchant in [`examples/fastapi`](../../examples/fastapi).
|
|
30
|
+
Plain ASGI: `app = forge.wrap(app)`. Use one Forge instance per application/event
|
|
31
|
+
loop. ASGI lifespan shutdown flushes and closes Forge automatically. When lifespan
|
|
32
|
+
is disabled, call `await forge.shutdown()` in your application's shutdown hook.
|
|
33
|
+
|
|
34
|
+
## What ships
|
|
35
|
+
|
|
36
|
+
- x402 v1 JSON challenges / `X-PAYMENT` and v2 `PAYMENT-REQUIRED` /
|
|
37
|
+
`PAYMENT-SIGNATURE` / `PAYMENT-RESPONSE`. Existing payment terms and merchant
|
|
38
|
+
extensions, including Bazaar, remain intact.
|
|
39
|
+
- Locally signed feedback IDs, byte-compatible with the TypeScript SDK and Forge
|
|
40
|
+
v2 collector. IDs, response decoration and context parsing need **no Forge
|
|
41
|
+
network round trip on the merchant request path**. This is not a payment
|
|
42
|
+
processor: the existing x402 middleware still verifies and settles payments.
|
|
43
|
+
- Background discovery, challenge and interaction telemetry with the same header
|
|
44
|
+
allowlist as TypeScript. AgentCash, awal and pay.sh hints reach the backend,
|
|
45
|
+
where caller classification and generic-traffic filtering happen.
|
|
46
|
+
- Agent context required on paid requests when enabled and stripped before
|
|
47
|
+
merchant validation, in JSON bodies or query parameters. Configured
|
|
48
|
+
independently from feedback.
|
|
49
|
+
- Feedback ID header, optional JSON body fields and optional plain-text trailer;
|
|
50
|
+
structured feedback in v2 challenge and successful settlement extensions.
|
|
51
|
+
- Public feedback form, GET rating, POST rating with note, cached summary.
|
|
52
|
+
Only these explicit rating/summary routes await the Forge backend. The backend
|
|
53
|
+
owns rating idempotency and the correction window.
|
|
54
|
+
- OpenAPI 3.0–3.2 / Swagger 2.0 JSON enrichment. Shared schema components remain
|
|
55
|
+
untouched. Composed schemas are conservatively header-only; JSON/YAML that
|
|
56
|
+
cannot be safely enriched is served unchanged.
|
|
57
|
+
- Bounded event queue (1,000), batches (100), 5-second delivery timeout, retry
|
|
58
|
+
after failure, diagnostics and a bounded shutdown flush. Best-effort delivery,
|
|
59
|
+
not durable storage; separate queues per worker. Requires an asyncio event loop.
|
|
60
|
+
|
|
61
|
+
## Options
|
|
62
|
+
|
|
63
|
+
All option names use Python `snake_case`; pass keyword arguments to `Forge` or a
|
|
64
|
+
`ForgeOptions` dataclass. The Python beta deliberately supports the core options,
|
|
65
|
+
not TypeScript's custom tone/wording overrides.
|
|
66
|
+
|
|
67
|
+
| Option | Default | Behavior |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| `api_key`, `backend_url`, `public_url` | required | Merchant credentials, collector and public service URL. Never infer URLs from Host. Use the `/api/sdk/v2` collector URL; an origin-only backend URL selects `/v1`. |
|
|
70
|
+
| `feedback` | `True` | Feedback IDs, prompts and routes. False retains telemetry with an internal interaction UUID. |
|
|
71
|
+
| `base_path` | `/feedback` | Free feedback routes; must not collide with merchant routes. |
|
|
72
|
+
| `agent_context` | `True` | Require context on paid requests. `AgentContextOptions(search_query=False)` requires only the agent name; `False` disables context. Legacy `required=False` is ignored. |
|
|
73
|
+
| `describe_challenges`, `challenge_extension`, `receipt_extension` | `True` | Feedback additions on x402 challenges/receipts. |
|
|
74
|
+
| `inject_body`, `rate_hint` | `True` | Paid JSON object fields and rating sentence. |
|
|
75
|
+
| `inject_text` | `False` | Opt-in trailer on paid `text/plain` responses. |
|
|
76
|
+
| `openapi` | `True` | Boolean or `OpenAPIOptions(paths=("/openapi.json",), document=None, is_paid_operation=None)`. Document can be a dict or sync/async provider. |
|
|
77
|
+
| `ttl_ms` | `86400000` | Must match backend feedback TTL. |
|
|
78
|
+
| `flush_interval_ms` | `2000` | Background event flush interval. |
|
|
79
|
+
| `strict` | `False` | Raise on invalid options in CI; otherwise disable Forge and leave the API unchanged. |
|
|
80
|
+
| `on_error` | logging warning | Optional error callback; callback failures are isolated. |
|
|
81
|
+
|
|
82
|
+
`Forge(..., http_client=client)` accepts a caller-owned `httpx.AsyncClient` for
|
|
83
|
+
custom transports/testing. The caller closes an injected client.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from forgeintel import AgentContextOptions, OpenAPIOptions
|
|
87
|
+
|
|
88
|
+
forge = Forge(
|
|
89
|
+
api_key="ffk_...",
|
|
90
|
+
backend_url="https://api.forgeintel.co/api/sdk/v2",
|
|
91
|
+
public_url="https://api.example.com",
|
|
92
|
+
agent_context=AgentContextOptions(search_query=True),
|
|
93
|
+
# FastAPI doesn't infer 402 responses from payment middleware. Declare them
|
|
94
|
+
# on paid routes, or explicitly select the paid operations here.
|
|
95
|
+
openapi=OpenAPIOptions(is_paid_operation=lambda method, path, op: path == "/weather"),
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Required context rejects payment-bearing requests with HTTP 400 **before** x402
|
|
100
|
+
processing. It requires a listed `agent_type` and `search_query` (`direct` when no
|
|
101
|
+
search was used), unless `search_query=False`. Initial unpaid challenges,
|
|
102
|
+
inspection and feedback routes remain available. This mode is opt-in.
|
|
103
|
+
|
|
104
|
+
JSON requests are read up to 1 MiB. Optional mode replays oversized, compressed or
|
|
105
|
+
invalid bodies unchanged; use query parameters for those bodies. Required mode
|
|
106
|
+
rejects unreadable JSON. Binary uploads are never buffered by Forge. Agent context
|
|
107
|
+
is still stripped when collection is disabled, where the body can be inspected.
|
|
108
|
+
|
|
109
|
+
JSON responses are rewritten only when bounded to 1 MiB (5 MiB for OpenAPI).
|
|
110
|
+
Unknown-length multi-chunk streams, SSE, compressed bodies, partial responses and
|
|
111
|
+
binary files remain unchanged; successful paid responses still receive the ID
|
|
112
|
+
header. Forge removes stale validators when it changes bytes and preserves repeated
|
|
113
|
+
headers such as `Set-Cookie`. No feedback is injected into redirects or errors.
|
|
114
|
+
|
|
115
|
+
For strict response schemas, provide `OpenAPIOptions(document=app.openapi)` or a
|
|
116
|
+
static document **and call `forge.enrich_openapi(app.openapi())` before serving
|
|
117
|
+
traffic**. Otherwise schema-aware body injection starts after the first spec fetch.
|
|
118
|
+
For a mounted app or reverse-proxy `root_path` such as `/api`, configure public paths: `base_path="/api/feedback"` and `OpenAPIOptions(paths=("/api/openapi.json",), ...)`.
|
|
119
|
+
Place Forge inside response compression and outside payment middleware. Framework
|
|
120
|
+
exceptions propagate normally; Forge never retries a merchant handler.
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
python -m venv packages/sdk-python/.venv
|
|
126
|
+
packages/sdk-python/.venv/bin/pip install -e './packages/sdk-python[test]'
|
|
127
|
+
packages/sdk-python/.venv/bin/python -m pytest packages/sdk-python/tests
|
|
128
|
+
packages/sdk-python/.venv/bin/python -m build packages/sdk-python
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Tests include the real `x402==2.5.0` FastAPI middleware and client, with a fake
|
|
132
|
+
facilitator (no funds spent), ASGI streaming/body limits and shared TypeScript ID
|
|
133
|
+
vectors. Live merchant rollout and PyPI publication are separate release steps.
|
|
134
|
+
MPP and Flask/WSGI are deferred.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25,<1.28"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "forgeintel-sdk"
|
|
7
|
+
version = "0.1.0b1"
|
|
8
|
+
description = "Forge telemetry, agent context and feedback for Python x402 APIs"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
dependencies = ["httpx>=0.27,<1"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Framework :: FastAPI",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Typing :: Typed",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
test = ["pytest>=8,<10", "pytest-asyncio>=0.24,<2", "fastapi>=0.115,<1", "x402[fastapi,evm]==2.5.0", "ruff>=0.11", "build>=1.2"]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Documentation = "https://docs.development.forgeintel.co/integrations/python"
|
|
28
|
+
Repository = "https://github.com/ClawCash/forge-feedback"
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["src/forgeintel"]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.sdist.force-include]
|
|
34
|
+
"../conformance/fixtures/feedback-ids.json" = "tests/fixtures/feedback-ids.json"
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
asyncio_mode = "auto"
|
|
38
|
+
testpaths = ["tests"]
|
|
39
|
+
pythonpath = ["src"]
|
|
40
|
+
|
|
41
|
+
[tool.ruff]
|
|
42
|
+
target-version = "py311"
|
|
43
|
+
line-length = 100
|
|
44
|
+
|
|
45
|
+
[tool.ruff.lint]
|
|
46
|
+
select = ["E4", "E7", "E9", "F", "I"]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Forge SDK for Python x402 merchants."""
|
|
2
|
+
|
|
3
|
+
from .asgi import ForgeMiddleware
|
|
4
|
+
from .core import AgentContextOptions, Forge, ForgeOptions, OpenAPIOptions
|
|
5
|
+
|
|
6
|
+
__version__ = "0.1.0b1"
|
|
7
|
+
__all__ = ["AgentContextOptions", "Forge", "ForgeMiddleware", "ForgeOptions", "OpenAPIOptions"]
|