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.
- rippletide_python-0.1.0/PKG-INFO +101 -0
- rippletide_python-0.1.0/README.md +93 -0
- rippletide_python-0.1.0/pyproject.toml +14 -0
- rippletide_python-0.1.0/rippletide/__init__.py +5 -0
- rippletide_python-0.1.0/rippletide/client.py +654 -0
- rippletide_python-0.1.0/rippletide_python.egg-info/PKG-INFO +101 -0
- rippletide_python-0.1.0/rippletide_python.egg-info/SOURCES.txt +9 -0
- rippletide_python-0.1.0/rippletide_python.egg-info/dependency_links.txt +1 -0
- rippletide_python-0.1.0/rippletide_python.egg-info/top_level.txt +1 -0
- rippletide_python-0.1.0/setup.cfg +4 -0
- rippletide_python-0.1.0/tests/test_client.py +345 -0
|
@@ -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"]
|