simpleflow-sdk 0.1.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.
- simpleflow_sdk-0.1.0/PKG-INFO +7 -0
- simpleflow_sdk-0.1.0/README.md +66 -0
- simpleflow_sdk-0.1.0/pyproject.toml +17 -0
- simpleflow_sdk-0.1.0/setup.cfg +4 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk/__init__.py +37 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk/auth.py +88 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk/client.py +873 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk/contracts.py +104 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk.egg-info/PKG-INFO +7 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk.egg-info/SOURCES.txt +13 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk.egg-info/dependency_links.txt +1 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk.egg-info/requires.txt +2 -0
- simpleflow_sdk-0.1.0/simpleflow_sdk.egg-info/top_level.txt +1 -0
- simpleflow_sdk-0.1.0/tests/test_auth.py +109 -0
- simpleflow_sdk-0.1.0/tests/test_client.py +453 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SimpleFlow Python SDK (Remote Runtime)
|
|
2
|
+
|
|
3
|
+
This SDK helps Python remote runtime backends integrate with the SimpleFlow control plane.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- API client for auth/session helpers, runtime registration lifecycle orchestration (`list/activate/deactivate/validate/ensure_active`), invoke, runtime events, chat message writes, queue contract publication, and chat history list/create/update.
|
|
8
|
+
- Invoke token verification helper for control-plane issued tokens (HS256 shared key and RS256 public key/JWKS usage).
|
|
9
|
+
- Method-level auth token overrides on control-plane and lifecycle methods.
|
|
10
|
+
- Typed request errors (`SimpleFlowAuthenticationError`, `SimpleFlowAuthorizationError`, `SimpleFlowLifecycleError`).
|
|
11
|
+
- Typed dataclasses for common runtime payloads and telemetry span envelopes.
|
|
12
|
+
- Telemetry bridge with `simpleflow` and `otlp` modes.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e ./python
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Minimal usage
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from simpleflow_sdk import RuntimeEvent, SimpleFlowClient
|
|
24
|
+
|
|
25
|
+
client = SimpleFlowClient(base_url="https://api.simpleflow.example", api_token="runtime-token")
|
|
26
|
+
client.write_event(
|
|
27
|
+
RuntimeEvent(
|
|
28
|
+
type="runtime.invoke.accepted",
|
|
29
|
+
agent_id="agent-1",
|
|
30
|
+
run_id="run_123"
|
|
31
|
+
)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
telemetry = client.with_telemetry(mode="simpleflow", sample_rate=0.2)
|
|
35
|
+
telemetry.emit_span(
|
|
36
|
+
span={"name": "llm.call", "start_time_ms": 1000, "end_time_ms": 1250},
|
|
37
|
+
trace_id="trace_123",
|
|
38
|
+
run_id="run_123",
|
|
39
|
+
agent_id="agent-1",
|
|
40
|
+
)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Security note: runtime endpoint allowlist
|
|
44
|
+
|
|
45
|
+
If your control-plane backend enables `RUNTIME_ENDPOINT_ALLOWLIST`, runtime registration calls from this SDK (`register_runtime` / `ensure_runtime_registration_active`) will fail with `400` unless the registration `endpoint_url` host is included in that allowlist.
|
|
46
|
+
|
|
47
|
+
## Auth verifier usage
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from simpleflow_sdk import InvokeTokenVerifier
|
|
51
|
+
|
|
52
|
+
hs_verifier = InvokeTokenVerifier.for_hs256_shared_key(
|
|
53
|
+
issuer="https://api.simpleflow.example",
|
|
54
|
+
audience="runtime",
|
|
55
|
+
shared_key="local-dev-secret",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
rs_verifier = InvokeTokenVerifier.for_rs256_public_key(
|
|
59
|
+
issuer="https://api.simpleflow.example",
|
|
60
|
+
audience="runtime",
|
|
61
|
+
public_key=public_key_pem,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# You can also pass a key per call when needed.
|
|
65
|
+
claims = hs_verifier.verify(token)
|
|
66
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "simpleflow-sdk"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "SimpleFlow remote runtime SDK for Python"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"httpx>=0.27.0,<1.0.0",
|
|
8
|
+
"PyJWT>=2.10.0,<3.0.0",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[build-system]
|
|
12
|
+
requires = ["setuptools>=68", "wheel"]
|
|
13
|
+
build-backend = "setuptools.build_meta"
|
|
14
|
+
|
|
15
|
+
[tool.setuptools.packages.find]
|
|
16
|
+
where = ["."]
|
|
17
|
+
include = ["simpleflow_sdk*"]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .auth import InvokeTokenVerifier
|
|
2
|
+
from .client import (
|
|
3
|
+
SimpleFlowAuthenticationError,
|
|
4
|
+
SimpleFlowAuthorizationError,
|
|
5
|
+
SimpleFlowClient,
|
|
6
|
+
SimpleFlowLifecycleError,
|
|
7
|
+
SimpleFlowRequestError,
|
|
8
|
+
TelemetryBridge,
|
|
9
|
+
)
|
|
10
|
+
from .contracts import (
|
|
11
|
+
ChatHistoryMessage,
|
|
12
|
+
ChatMessageWrite,
|
|
13
|
+
InvokeTrace,
|
|
14
|
+
QueueContract,
|
|
15
|
+
RuntimeEvent,
|
|
16
|
+
RuntimeRegistration,
|
|
17
|
+
TelemetrySpan,
|
|
18
|
+
WorkflowTraceTenant,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"SimpleFlowClient",
|
|
23
|
+
"TelemetryBridge",
|
|
24
|
+
"SimpleFlowRequestError",
|
|
25
|
+
"SimpleFlowAuthenticationError",
|
|
26
|
+
"SimpleFlowAuthorizationError",
|
|
27
|
+
"SimpleFlowLifecycleError",
|
|
28
|
+
"InvokeTokenVerifier",
|
|
29
|
+
"RuntimeEvent",
|
|
30
|
+
"InvokeTrace",
|
|
31
|
+
"ChatHistoryMessage",
|
|
32
|
+
"ChatMessageWrite",
|
|
33
|
+
"QueueContract",
|
|
34
|
+
"RuntimeRegistration",
|
|
35
|
+
"TelemetrySpan",
|
|
36
|
+
"WorkflowTraceTenant",
|
|
37
|
+
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import jwt
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class InvokeTokenVerifier:
|
|
9
|
+
"""Verify invoke tokens using HS256 shared keys or RS256 public keys.
|
|
10
|
+
|
|
11
|
+
You can pass a verification key per call via ``verify(token, key=...)`` or
|
|
12
|
+
configure a default key using ``for_hs256_shared_key`` / ``for_rs256_public_key``.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
issuer: str,
|
|
18
|
+
audience: str,
|
|
19
|
+
algorithms: list[str] | None = None,
|
|
20
|
+
verification_key: str | bytes | Any | None = None,
|
|
21
|
+
) -> None:
|
|
22
|
+
if issuer.strip() == "":
|
|
23
|
+
raise ValueError("simpleflow sdk auth config error: issuer is required")
|
|
24
|
+
if audience.strip() == "":
|
|
25
|
+
raise ValueError("simpleflow sdk auth config error: audience is required")
|
|
26
|
+
|
|
27
|
+
self._issuer = issuer
|
|
28
|
+
self._audience = audience
|
|
29
|
+
self._algorithms = algorithms if algorithms is not None else ["HS256", "RS256"]
|
|
30
|
+
self._verification_key = verification_key
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def for_hs256_shared_key(
|
|
34
|
+
cls,
|
|
35
|
+
*,
|
|
36
|
+
issuer: str,
|
|
37
|
+
audience: str,
|
|
38
|
+
shared_key: str | bytes,
|
|
39
|
+
) -> "InvokeTokenVerifier":
|
|
40
|
+
return cls(
|
|
41
|
+
issuer=issuer,
|
|
42
|
+
audience=audience,
|
|
43
|
+
algorithms=["HS256"],
|
|
44
|
+
verification_key=shared_key,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def for_rs256_public_key(
|
|
49
|
+
cls,
|
|
50
|
+
*,
|
|
51
|
+
issuer: str,
|
|
52
|
+
audience: str,
|
|
53
|
+
public_key: str | bytes,
|
|
54
|
+
) -> "InvokeTokenVerifier":
|
|
55
|
+
return cls(
|
|
56
|
+
issuer=issuer,
|
|
57
|
+
audience=audience,
|
|
58
|
+
algorithms=["RS256"],
|
|
59
|
+
verification_key=public_key,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def verify(
|
|
63
|
+
self, token: str, key: str | bytes | Any | None = None
|
|
64
|
+
) -> dict[str, Any]:
|
|
65
|
+
if token.strip() == "":
|
|
66
|
+
raise ValueError("simpleflow sdk auth error: token is required")
|
|
67
|
+
verification_key = key if key is not None else self._verification_key
|
|
68
|
+
if verification_key is None:
|
|
69
|
+
raise ValueError("simpleflow sdk auth error: verification key is required")
|
|
70
|
+
|
|
71
|
+
claims = jwt.decode(
|
|
72
|
+
token,
|
|
73
|
+
key=verification_key,
|
|
74
|
+
algorithms=self._algorithms,
|
|
75
|
+
audience=self._audience,
|
|
76
|
+
issuer=self._issuer,
|
|
77
|
+
options={"require": ["exp", "iat", "iss", "aud"]},
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if (
|
|
81
|
+
str(claims.get("agent_id", "")).strip() == ""
|
|
82
|
+
or str(claims.get("org_id", "")).strip() == ""
|
|
83
|
+
):
|
|
84
|
+
raise ValueError(
|
|
85
|
+
"simpleflow sdk auth error: token missing required agent_id or org_id"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return claims
|