codespar 0.1.0__tar.gz → 0.3.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.
- {codespar-0.1.0 → codespar-0.3.0}/PKG-INFO +5 -1
- {codespar-0.1.0 → codespar-0.3.0}/README.md +4 -0
- codespar-0.3.0/examples/README.md +37 -0
- codespar-0.3.0/examples/async_basic.py +46 -0
- codespar-0.3.0/examples/connect_link.py +46 -0
- codespar-0.3.0/examples/ecommerce_checkout.py +73 -0
- codespar-0.3.0/examples/pix_payment.py +48 -0
- codespar-0.3.0/examples/proxy_execute.py +53 -0
- {codespar-0.1.0 → codespar-0.3.0}/pyproject.toml +8 -1
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/__init__.py +1 -1
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/_http.py +1 -1
- codespar-0.3.0/tests/__init__.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/.gitignore +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/_async_client.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/_async_session.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/_presets.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/_sync_client.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/errors.py +0 -0
- /codespar-0.1.0/tests/__init__.py → /codespar-0.3.0/src/codespar/py.typed +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/src/codespar/types.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/tests/test_config.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/tests/test_session.py +0 -0
- {codespar-0.1.0 → codespar-0.3.0}/tests/test_streaming.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codespar
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python SDK for CodeSpar — commerce infrastructure for AI agents in Latin America.
|
|
5
5
|
Project-URL: Homepage, https://codespar.dev
|
|
6
6
|
Project-URL: Documentation, https://docs.codespar.dev
|
|
@@ -179,6 +179,10 @@ This package mirrors [`@codespar/sdk`](https://www.npmjs.com/package/@codespar/s
|
|
|
179
179
|
method-for-method. Same backend, same payloads, same preset names — pick
|
|
180
180
|
the language that fits your stack without giving anything up.
|
|
181
181
|
|
|
182
|
+
## Need more?
|
|
183
|
+
|
|
184
|
+
Need governance, budget limits, and audit trails for agent payments? **[CodeSpar Enterprise](https://codespar.dev/enterprise)** adds policy engine, payment routing, and compliance templates on top of these MCP servers.
|
|
185
|
+
|
|
182
186
|
## Links
|
|
183
187
|
|
|
184
188
|
- [Documentation](https://docs.codespar.dev)
|
|
@@ -148,6 +148,10 @@ This package mirrors [`@codespar/sdk`](https://www.npmjs.com/package/@codespar/s
|
|
|
148
148
|
method-for-method. Same backend, same payloads, same preset names — pick
|
|
149
149
|
the language that fits your stack without giving anything up.
|
|
150
150
|
|
|
151
|
+
## Need more?
|
|
152
|
+
|
|
153
|
+
Need governance, budget limits, and audit trails for agent payments? **[CodeSpar Enterprise](https://codespar.dev/enterprise)** adds policy engine, payment routing, and compliance templates on top of these MCP servers.
|
|
154
|
+
|
|
151
155
|
## Links
|
|
152
156
|
|
|
153
157
|
- [Documentation](https://docs.codespar.dev)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# codespar Python SDK — examples
|
|
2
|
+
|
|
3
|
+
Runnable scripts demonstrating the CodeSpar Python SDK end-to-end.
|
|
4
|
+
Each file is standalone — just `pip install codespar`, set
|
|
5
|
+
`CODESPAR_API_KEY`, and run.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install codespar
|
|
11
|
+
export CODESPAR_API_KEY="csk_live_..." # get one at dashboard.codespar.dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Optionally pin a specific project (staging, prod, etc.):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
export CODESPAR_PROJECT_ID="prj_a1b2c3d4e5f6g7h8"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
| File | What it does | SDK surface |
|
|
23
|
+
|------|--------------|-------------|
|
|
24
|
+
| [`ecommerce_checkout.py`](./ecommerce_checkout.py) | Full Complete Loop: checkout → NF-e → ship → notify via WhatsApp | `send_stream`, typed events |
|
|
25
|
+
| [`pix_payment.py`](./pix_payment.py) | Create a Pix charge and notify the customer | `send`, `tool_calls` |
|
|
26
|
+
| [`proxy_execute.py`](./proxy_execute.py) | Raw HTTP proxy to a provider API with server-side auth injection | `proxy_execute` |
|
|
27
|
+
| [`connect_link.py`](./connect_link.py) | Generate an OAuth Connect Link for an end user | `authorize` |
|
|
28
|
+
| [`async_basic.py`](./async_basic.py) | Same flow using `AsyncCodeSpar` for FastAPI / asyncio stacks | `AsyncCodeSpar` |
|
|
29
|
+
|
|
30
|
+
## Running
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python examples/ecommerce_checkout.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
All examples use `preset="brazilian"` by default. Change to
|
|
37
|
+
`mexican` / `argentinian` / `colombian` to run the LatAm-wide stack.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Same Pix flow as ``pix_payment.py``, but with ``AsyncCodeSpar`` —
|
|
3
|
+
the canonical shape for FastAPI, LangChain, or anything already on
|
|
4
|
+
asyncio. The SDK's async client is the primary implementation; the
|
|
5
|
+
sync ``CodeSpar`` is a thin wrapper on top.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
export CODESPAR_API_KEY="csk_live_..."
|
|
9
|
+
python examples/async_basic.py
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from codespar import AsyncCodeSpar
|
|
19
|
+
|
|
20
|
+
PROMPT = "Crie um Pix de R$200 e envie o QR code para +5511999887766."
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def run() -> int:
|
|
24
|
+
api_key = os.environ.get("CODESPAR_API_KEY")
|
|
25
|
+
if not api_key:
|
|
26
|
+
print("error: set CODESPAR_API_KEY first", file=sys.stderr)
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
async with AsyncCodeSpar(api_key=api_key) as cs:
|
|
30
|
+
session = await cs.create("demo_user", preset="brazilian")
|
|
31
|
+
try:
|
|
32
|
+
async for event in session.send_stream(PROMPT):
|
|
33
|
+
if event.type == "assistant_text":
|
|
34
|
+
print(event.content, end="", flush=True)
|
|
35
|
+
elif event.type == "tool_use":
|
|
36
|
+
print(f"\n→ {event.name}")
|
|
37
|
+
elif event.type == "done":
|
|
38
|
+
print(f"\n✓ done · {event.result.iterations} iterations")
|
|
39
|
+
finally:
|
|
40
|
+
await session.close()
|
|
41
|
+
|
|
42
|
+
return 0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
raise SystemExit(asyncio.run(run()))
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Connect Links example — generate the OAuth URL your end user opens
|
|
3
|
+
to grant provider access. CodeSpar stores the tokens in the
|
|
4
|
+
per-project vault once the user completes the flow, then forwards
|
|
5
|
+
them back to ``redirect_uri`` with ``?status=connected`` appended.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
export CODESPAR_API_KEY="csk_live_..."
|
|
9
|
+
python examples/connect_link.py
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
from codespar import AuthConfig, CodeSpar
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main() -> int:
|
|
21
|
+
api_key = os.environ.get("CODESPAR_API_KEY")
|
|
22
|
+
if not api_key:
|
|
23
|
+
print("error: set CODESPAR_API_KEY first", file=sys.stderr)
|
|
24
|
+
return 1
|
|
25
|
+
|
|
26
|
+
with CodeSpar(api_key=api_key) as cs:
|
|
27
|
+
session = cs.create("demo_user", servers=["stripe-acp"])
|
|
28
|
+
try:
|
|
29
|
+
link = session.authorize(
|
|
30
|
+
"stripe-acp",
|
|
31
|
+
AuthConfig(
|
|
32
|
+
redirect_uri="https://your-app.example/connected",
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
print("Open this URL to connect Stripe:")
|
|
36
|
+
print(f" {link.authorize_url}")
|
|
37
|
+
print(f"\nLink token: {link.link_token}")
|
|
38
|
+
print(f"Expires at: {link.expires_at}")
|
|
39
|
+
finally:
|
|
40
|
+
session.close()
|
|
41
|
+
|
|
42
|
+
return 0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
End-to-end e-commerce checkout — the canonical Complete Loop demo.
|
|
3
|
+
|
|
4
|
+
Drives a single natural-language turn through four tools:
|
|
5
|
+
codespar_checkout → codespar_invoice → codespar_ship → codespar_notify
|
|
6
|
+
|
|
7
|
+
Exactly what the dashboard's Sandbox / E-Commerce Checkout runs, just
|
|
8
|
+
from Python instead of the browser. Streams events so you can watch
|
|
9
|
+
the agent progress through each step in real time.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
export CODESPAR_API_KEY="csk_live_..."
|
|
13
|
+
python examples/ecommerce_checkout.py
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
from codespar import CodeSpar
|
|
22
|
+
|
|
23
|
+
PROMPT = (
|
|
24
|
+
"Quero comprar o Starter Kit por R$149,00. "
|
|
25
|
+
"Meu CEP é 01310-100. Pode processar tudo: "
|
|
26
|
+
"checkout via Stripe, NF-e via Nuvem Fiscal, "
|
|
27
|
+
"frete via Correios, e me avise pelo WhatsApp."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def main() -> int:
|
|
32
|
+
api_key = os.environ.get("CODESPAR_API_KEY")
|
|
33
|
+
if not api_key:
|
|
34
|
+
print("error: set CODESPAR_API_KEY first — see dashboard.codespar.dev", file=sys.stderr)
|
|
35
|
+
return 1
|
|
36
|
+
|
|
37
|
+
with CodeSpar(
|
|
38
|
+
api_key=api_key,
|
|
39
|
+
project_id=os.environ.get("CODESPAR_PROJECT_ID"),
|
|
40
|
+
) as cs:
|
|
41
|
+
session = cs.create("demo_user", preset="brazilian")
|
|
42
|
+
try:
|
|
43
|
+
print(f"→ session {session.id}")
|
|
44
|
+
print(f"→ servers: {', '.join(session.servers)}\n")
|
|
45
|
+
|
|
46
|
+
for event in session.send_stream(PROMPT):
|
|
47
|
+
# Stream type is a discriminated union — pattern match
|
|
48
|
+
# on the event.type literal so mypy can narrow the
|
|
49
|
+
# attributes each branch touches.
|
|
50
|
+
if event.type == "assistant_text":
|
|
51
|
+
print(event.content, end="", flush=True)
|
|
52
|
+
elif event.type == "tool_use":
|
|
53
|
+
print(f"\n\n → calling {event.name}")
|
|
54
|
+
elif event.type == "tool_result":
|
|
55
|
+
tc = event.tool_call
|
|
56
|
+
status = "ok" if tc.status == "success" else f"error ({tc.error_code})"
|
|
57
|
+
print(f" {status} · {tc.duration_ms}ms")
|
|
58
|
+
elif event.type == "done":
|
|
59
|
+
tool_count = len(event.result.tool_calls)
|
|
60
|
+
iterations = event.result.iterations
|
|
61
|
+
print("\n\n✓ complete")
|
|
62
|
+
print(f" {tool_count} tools · {iterations} iterations")
|
|
63
|
+
elif event.type == "error":
|
|
64
|
+
print(f"\n✗ error: {event.error}", file=sys.stderr)
|
|
65
|
+
return 2
|
|
66
|
+
finally:
|
|
67
|
+
session.close()
|
|
68
|
+
|
|
69
|
+
return 0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minimal Pix example — create a charge, send the QR code via WhatsApp.
|
|
3
|
+
|
|
4
|
+
Uses ``send`` (blocking) instead of ``send_stream`` because this flow
|
|
5
|
+
is short enough that streaming would be overkill; you get the full
|
|
6
|
+
transcript back in one call.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
export CODESPAR_API_KEY="csk_live_..."
|
|
10
|
+
python examples/pix_payment.py
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from codespar import CodeSpar
|
|
19
|
+
|
|
20
|
+
PROMPT = (
|
|
21
|
+
"Crie uma cobrança Pix de R$500,00 e envie o QR code "
|
|
22
|
+
"pelo WhatsApp para +5511999887766."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main() -> int:
|
|
27
|
+
api_key = os.environ.get("CODESPAR_API_KEY")
|
|
28
|
+
if not api_key:
|
|
29
|
+
print("error: set CODESPAR_API_KEY first", file=sys.stderr)
|
|
30
|
+
return 1
|
|
31
|
+
|
|
32
|
+
with CodeSpar(api_key=api_key) as cs:
|
|
33
|
+
session = cs.create("demo_user", preset="brazilian")
|
|
34
|
+
try:
|
|
35
|
+
result = session.send(PROMPT)
|
|
36
|
+
print(result.message)
|
|
37
|
+
print(f"\n{len(result.tool_calls)} tools called over {result.iterations} iterations:")
|
|
38
|
+
for tc in result.tool_calls:
|
|
39
|
+
marker = "✓" if tc.status == "success" else "✗"
|
|
40
|
+
print(f" {marker} {tc.tool_name} · {tc.server_id} · {tc.duration_ms}ms")
|
|
41
|
+
finally:
|
|
42
|
+
session.close()
|
|
43
|
+
|
|
44
|
+
return 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Raw HTTP proxy example — bypass the agent loop and call a provider
|
|
3
|
+
endpoint directly through CodeSpar's credential vault.
|
|
4
|
+
|
|
5
|
+
CodeSpar injects the Stripe API key server-side; your code never
|
|
6
|
+
sees it. Same pattern works for every connected server — swap
|
|
7
|
+
``server="stripe-acp"`` for ``"asaas"``, ``"nuvem-fiscal"``, etc.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
export CODESPAR_API_KEY="csk_live_..."
|
|
11
|
+
python examples/proxy_execute.py
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
from codespar import CodeSpar, ProxyRequest
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main() -> int:
|
|
24
|
+
api_key = os.environ.get("CODESPAR_API_KEY")
|
|
25
|
+
if not api_key:
|
|
26
|
+
print("error: set CODESPAR_API_KEY first", file=sys.stderr)
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
with CodeSpar(api_key=api_key) as cs:
|
|
30
|
+
session = cs.create("demo_user", servers=["stripe-acp"])
|
|
31
|
+
try:
|
|
32
|
+
response = session.proxy_execute(
|
|
33
|
+
ProxyRequest(
|
|
34
|
+
server="stripe-acp",
|
|
35
|
+
endpoint="/v1/charges",
|
|
36
|
+
method="POST",
|
|
37
|
+
body={
|
|
38
|
+
"amount": 14900, # R$149.00 in cents
|
|
39
|
+
"currency": "brl",
|
|
40
|
+
"description": "Starter Kit",
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
print(f"HTTP {response.status} · {response.duration}ms")
|
|
45
|
+
print(json.dumps(response.data, indent=2, ensure_ascii=False))
|
|
46
|
+
finally:
|
|
47
|
+
session.close()
|
|
48
|
+
|
|
49
|
+
return 0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
raise SystemExit(main())
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codespar"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Python SDK for CodeSpar — commerce infrastructure for AI agents in Latin America."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -47,6 +47,13 @@ Issues = "https://github.com/codespar/codespar/issues"
|
|
|
47
47
|
[tool.hatch.build.targets.wheel]
|
|
48
48
|
packages = ["src/codespar"]
|
|
49
49
|
|
|
50
|
+
# PEP 561 — the empty `py.typed` marker signals to mypy / pyright /
|
|
51
|
+
# pyrefly that this package ships inline type hints. Without it,
|
|
52
|
+
# downstream projects lose type info even though every public fn
|
|
53
|
+
# is annotated.
|
|
54
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
55
|
+
"src/codespar/py.typed" = "codespar/py.typed"
|
|
56
|
+
|
|
50
57
|
[tool.pytest.ini_options]
|
|
51
58
|
testpaths = ["tests"]
|
|
52
59
|
asyncio_mode = "auto"
|
|
@@ -28,7 +28,7 @@ def build_headers(
|
|
|
28
28
|
headers = {
|
|
29
29
|
"Content-Type": "application/json",
|
|
30
30
|
"Authorization": f"Bearer {api_key}",
|
|
31
|
-
"User-Agent": "codespar-python/0.1.
|
|
31
|
+
"User-Agent": "codespar-python/0.1.1",
|
|
32
32
|
}
|
|
33
33
|
if project_id:
|
|
34
34
|
headers["x-codespar-project"] = project_id
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|