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.
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: simpleflow-sdk
3
+ Version: 0.1.0
4
+ Summary: SimpleFlow remote runtime SDK for Python
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: httpx<1.0.0,>=0.27.0
7
+ Requires-Dist: PyJWT<3.0.0,>=2.10.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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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