rippletide-python 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,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: rippletide-python
3
+ Version: 0.1.0
4
+ Summary: Monitor-first Python SDK for Rippletide-connected agents
5
+ License: UNLICENSED
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
9
+ # Rippletide Python
10
+
11
+ `rippletide-python` connects a code-owned Python agent to Rippletide without
12
+ taking ownership of its model traffic. It has no provider dependencies: wrap a
13
+ hand-written provider or internal HTTP call at the existing model seam.
14
+
15
+ ```python
16
+ from rippletide import Rippletide, load_rippletide_env
17
+
18
+ # Keep these values aligned with the agent's existing provider call.
19
+ PROVIDER_NAME = "existing-provider"
20
+ PROVIDER_API_KEY_ENV = "EXISTING_PROVIDER_API_KEY"
21
+ MODEL_OPERATION = "existing-provider.request"
22
+
23
+ load_rippletide_env("/path/to/connected-repo/.env")
24
+ rippletide = Rippletide(name="Support agent")
25
+
26
+ try:
27
+ rippletide.register_prompts({"system": {"fallback": SYSTEM_PROMPT}}) # prompt text is withheld by default
28
+ rippletide.tools("core", TOOLS)
29
+ rippletide.connection(PROVIDER_NAME, env={"api_key": PROVIDER_API_KEY_ENV})
30
+ with rippletide.run(name="inbound_request", input=request, conversation_id=conversation_id):
31
+ with rippletide.agent(name="orchestrator"):
32
+ call_model = rippletide.traced(raw_model_call, name=MODEL_OPERATION, kind="model")
33
+ candidate = call_model(messages)
34
+ return rippletide.deliver_response(
35
+ request=request, response=candidate, context=trusted_context,
36
+ deliver=send_to_caller,
37
+ )
38
+ finally:
39
+ rippletide.flush()
40
+ ```
41
+
42
+ The CLI writes an agent-scoped `RIPPLETIDE=rippletide://…` connection string
43
+ into the connected repository's `.env`. `load_rippletide_env()` loads it without
44
+ overriding the process environment. The SDK also accepts the legacy
45
+ `RIPPLETIDE_API_KEY`, `RIPPLETIDE_AGENT_ID` (or `RIPPLETIDE_APP`), and optional
46
+ `RIPPLETIDE_BASE_URL` generated by the Connection page. A valid `RIPPLETIDE`
47
+ connection takes precedence over those legacy values; explicit constructor
48
+ arguments take precedence over either format. Never use a Platform key in the
49
+ agent or commit the `.env`.
50
+
51
+ The client starts disabled when no Connection key is present. Network, 5xx, and
52
+ rate-limit failures fail open; a valid enforce-mode policy `BLOCK` is the only
53
+ case that prevents a protected callback. Runtime capture defaults to metadata;
54
+ use `RIPPLETIDE_CAPTURE_MODE=redacted` or explicitly opt into `full` when the
55
+ privacy posture allows it. Always call `flush()` before a short-lived worker,
56
+ CLI, or serverless invocation exits.
57
+
58
+ Malformed or interrupted HTTP responses also fail open.
59
+
60
+ Tool and response policy spans include the invocation ID; once a decision arrives, their end
61
+ events and the protected action spans include its decision ID, including in
62
+ metadata capture mode. These IDs correlate the action with its policy receipt.
63
+
64
+ Prompt inventory is recorded with its content withheld by default. Pass
65
+ `allow_content_export=True` to `register_prompts(...)` only when the prompt
66
+ owner has explicitly approved storing the prompt text in Rippletide.
67
+
68
+ ## Filter a completed tool result (explicit opt-in)
69
+
70
+ For an eligible collection returned by a tool, declare its result contract and
71
+ pass `allow_result_export=True`. This evaluates the complete result transiently
72
+ at Rippletide; do this only with the owner's explicit approval. It is false by
73
+ default, and unavailable policy service forwards every item unchanged.
74
+
75
+ ```python
76
+ rippletide.tools("catalog", TOOLS, results={
77
+ "list_products": {
78
+ "resultSchema": {"type": "object", "properties": {"products": {"type": "array"}}},
79
+ "resultCollection": {"itemsPath": ["products"], "itemIdPath": ["id"]},
80
+ },
81
+ })
82
+
83
+ result = list_products(params)
84
+ return rippletide.guard_tool_result(
85
+ toolset="catalog", tool="list_products", params=params,
86
+ result=result, result_items=result["products"], context=trusted_context,
87
+ allow_result_export=True,
88
+ apply=lambda guarded: {**guarded["result"], "products": guarded["deliveredItems"]},
89
+ )
90
+ ```
91
+
92
+ `ALLOW` and observe-only `WOULD_BLOCK` items are delivered; only enforce-mode
93
+ `BLOCK` items are excluded. The callback receives the original result snapshot,
94
+ the delivered and excluded items, and the decision. It is responsible for the
95
+ native response shape, and the SDK records the applied outcome as a receipt.
96
+ Result fingerprints use the server's ECMAScript JSON encoding, including its
97
+ number formatting and UTF-16 object-key ordering.
98
+
99
+ This first release supports synchronous Python call sites. Python MCP servers,
100
+ async generators, and response streaming remain unsupported rather than being
101
+ silently represented as complete response-delivery protection.
@@ -0,0 +1,93 @@
1
+ # Rippletide Python
2
+
3
+ `rippletide-python` connects a code-owned Python agent to Rippletide without
4
+ taking ownership of its model traffic. It has no provider dependencies: wrap a
5
+ hand-written provider or internal HTTP call at the existing model seam.
6
+
7
+ ```python
8
+ from rippletide import Rippletide, load_rippletide_env
9
+
10
+ # Keep these values aligned with the agent's existing provider call.
11
+ PROVIDER_NAME = "existing-provider"
12
+ PROVIDER_API_KEY_ENV = "EXISTING_PROVIDER_API_KEY"
13
+ MODEL_OPERATION = "existing-provider.request"
14
+
15
+ load_rippletide_env("/path/to/connected-repo/.env")
16
+ rippletide = Rippletide(name="Support agent")
17
+
18
+ try:
19
+ rippletide.register_prompts({"system": {"fallback": SYSTEM_PROMPT}}) # prompt text is withheld by default
20
+ rippletide.tools("core", TOOLS)
21
+ rippletide.connection(PROVIDER_NAME, env={"api_key": PROVIDER_API_KEY_ENV})
22
+ with rippletide.run(name="inbound_request", input=request, conversation_id=conversation_id):
23
+ with rippletide.agent(name="orchestrator"):
24
+ call_model = rippletide.traced(raw_model_call, name=MODEL_OPERATION, kind="model")
25
+ candidate = call_model(messages)
26
+ return rippletide.deliver_response(
27
+ request=request, response=candidate, context=trusted_context,
28
+ deliver=send_to_caller,
29
+ )
30
+ finally:
31
+ rippletide.flush()
32
+ ```
33
+
34
+ The CLI writes an agent-scoped `RIPPLETIDE=rippletide://…` connection string
35
+ into the connected repository's `.env`. `load_rippletide_env()` loads it without
36
+ overriding the process environment. The SDK also accepts the legacy
37
+ `RIPPLETIDE_API_KEY`, `RIPPLETIDE_AGENT_ID` (or `RIPPLETIDE_APP`), and optional
38
+ `RIPPLETIDE_BASE_URL` generated by the Connection page. A valid `RIPPLETIDE`
39
+ connection takes precedence over those legacy values; explicit constructor
40
+ arguments take precedence over either format. Never use a Platform key in the
41
+ agent or commit the `.env`.
42
+
43
+ The client starts disabled when no Connection key is present. Network, 5xx, and
44
+ rate-limit failures fail open; a valid enforce-mode policy `BLOCK` is the only
45
+ case that prevents a protected callback. Runtime capture defaults to metadata;
46
+ use `RIPPLETIDE_CAPTURE_MODE=redacted` or explicitly opt into `full` when the
47
+ privacy posture allows it. Always call `flush()` before a short-lived worker,
48
+ CLI, or serverless invocation exits.
49
+
50
+ Malformed or interrupted HTTP responses also fail open.
51
+
52
+ Tool and response policy spans include the invocation ID; once a decision arrives, their end
53
+ events and the protected action spans include its decision ID, including in
54
+ metadata capture mode. These IDs correlate the action with its policy receipt.
55
+
56
+ Prompt inventory is recorded with its content withheld by default. Pass
57
+ `allow_content_export=True` to `register_prompts(...)` only when the prompt
58
+ owner has explicitly approved storing the prompt text in Rippletide.
59
+
60
+ ## Filter a completed tool result (explicit opt-in)
61
+
62
+ For an eligible collection returned by a tool, declare its result contract and
63
+ pass `allow_result_export=True`. This evaluates the complete result transiently
64
+ at Rippletide; do this only with the owner's explicit approval. It is false by
65
+ default, and unavailable policy service forwards every item unchanged.
66
+
67
+ ```python
68
+ rippletide.tools("catalog", TOOLS, results={
69
+ "list_products": {
70
+ "resultSchema": {"type": "object", "properties": {"products": {"type": "array"}}},
71
+ "resultCollection": {"itemsPath": ["products"], "itemIdPath": ["id"]},
72
+ },
73
+ })
74
+
75
+ result = list_products(params)
76
+ return rippletide.guard_tool_result(
77
+ toolset="catalog", tool="list_products", params=params,
78
+ result=result, result_items=result["products"], context=trusted_context,
79
+ allow_result_export=True,
80
+ apply=lambda guarded: {**guarded["result"], "products": guarded["deliveredItems"]},
81
+ )
82
+ ```
83
+
84
+ `ALLOW` and observe-only `WOULD_BLOCK` items are delivered; only enforce-mode
85
+ `BLOCK` items are excluded. The callback receives the original result snapshot,
86
+ the delivered and excluded items, and the decision. It is responsible for the
87
+ native response shape, and the SDK records the applied outcome as a receipt.
88
+ Result fingerprints use the server's ECMAScript JSON encoding, including its
89
+ number formatting and UTF-16 object-key ordering.
90
+
91
+ This first release supports synchronous Python call sites. Python MCP servers,
92
+ async generators, and response streaming remain unsupported rather than being
93
+ silently represented as complete response-delivery protection.
@@ -0,0 +1,14 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "rippletide-python"
7
+ version = "0.1.0"
8
+ description = "Monitor-first Python SDK for Rippletide-connected agents"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "UNLICENSED" }
12
+
13
+ [tool.setuptools]
14
+ packages = ["rippletide"]
@@ -0,0 +1,5 @@
1
+ """Monitor-first tracing and policy guards for code-owned Python agents."""
2
+
3
+ from .client import Rippletide, RippletidePolicyBlockedError, RippletidePolicyDecisionError, load_rippletide_env
4
+
5
+ __all__ = ["Rippletide", "RippletidePolicyBlockedError", "RippletidePolicyDecisionError", "load_rippletide_env"]