Metadata-Version: 2.4
Name: rippletide-python
Version: 0.1.0
Summary: Monitor-first Python SDK for Rippletide-connected agents
License: UNLICENSED
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# Rippletide Python

`rippletide-python` connects a code-owned Python agent to Rippletide without
taking ownership of its model traffic. It has no provider dependencies: wrap a
hand-written provider or internal HTTP call at the existing model seam.

```python
from rippletide import Rippletide, load_rippletide_env

# Keep these values aligned with the agent's existing provider call.
PROVIDER_NAME = "existing-provider"
PROVIDER_API_KEY_ENV = "EXISTING_PROVIDER_API_KEY"
MODEL_OPERATION = "existing-provider.request"

load_rippletide_env("/path/to/connected-repo/.env")
rippletide = Rippletide(name="Support agent")

try:
    rippletide.register_prompts({"system": {"fallback": SYSTEM_PROMPT}})  # prompt text is withheld by default
    rippletide.tools("core", TOOLS)
    rippletide.connection(PROVIDER_NAME, env={"api_key": PROVIDER_API_KEY_ENV})
    with rippletide.run(name="inbound_request", input=request, conversation_id=conversation_id):
        with rippletide.agent(name="orchestrator"):
            call_model = rippletide.traced(raw_model_call, name=MODEL_OPERATION, kind="model")
            candidate = call_model(messages)
            return rippletide.deliver_response(
                request=request, response=candidate, context=trusted_context,
                deliver=send_to_caller,
            )
finally:
    rippletide.flush()
```

The CLI writes an agent-scoped `RIPPLETIDE=rippletide://…` connection string
into the connected repository's `.env`. `load_rippletide_env()` loads it without
overriding the process environment. The SDK also accepts the legacy
`RIPPLETIDE_API_KEY`, `RIPPLETIDE_AGENT_ID` (or `RIPPLETIDE_APP`), and optional
`RIPPLETIDE_BASE_URL` generated by the Connection page. A valid `RIPPLETIDE`
connection takes precedence over those legacy values; explicit constructor
arguments take precedence over either format. Never use a Platform key in the
agent or commit the `.env`.

The client starts disabled when no Connection key is present. Network, 5xx, and
rate-limit failures fail open; a valid enforce-mode policy `BLOCK` is the only
case that prevents a protected callback. Runtime capture defaults to metadata;
use `RIPPLETIDE_CAPTURE_MODE=redacted` or explicitly opt into `full` when the
privacy posture allows it. Always call `flush()` before a short-lived worker,
CLI, or serverless invocation exits.

Malformed or interrupted HTTP responses also fail open.

Tool and response policy spans include the invocation ID; once a decision arrives, their end
events and the protected action spans include its decision ID, including in
metadata capture mode. These IDs correlate the action with its policy receipt.

Prompt inventory is recorded with its content withheld by default. Pass
`allow_content_export=True` to `register_prompts(...)` only when the prompt
owner has explicitly approved storing the prompt text in Rippletide.

## Filter a completed tool result (explicit opt-in)

For an eligible collection returned by a tool, declare its result contract and
pass `allow_result_export=True`. This evaluates the complete result transiently
at Rippletide; do this only with the owner's explicit approval. It is false by
default, and unavailable policy service forwards every item unchanged.

```python
rippletide.tools("catalog", TOOLS, results={
    "list_products": {
        "resultSchema": {"type": "object", "properties": {"products": {"type": "array"}}},
        "resultCollection": {"itemsPath": ["products"], "itemIdPath": ["id"]},
    },
})

result = list_products(params)
return rippletide.guard_tool_result(
    toolset="catalog", tool="list_products", params=params,
    result=result, result_items=result["products"], context=trusted_context,
    allow_result_export=True,
    apply=lambda guarded: {**guarded["result"], "products": guarded["deliveredItems"]},
)
```

`ALLOW` and observe-only `WOULD_BLOCK` items are delivered; only enforce-mode
`BLOCK` items are excluded. The callback receives the original result snapshot,
the delivered and excluded items, and the decision. It is responsible for the
native response shape, and the SDK records the applied outcome as a receipt.
Result fingerprints use the server's ECMAScript JSON encoding, including its
number formatting and UTF-16 object-key ordering.

This first release supports synchronous Python call sites. Python MCP servers,
async generators, and response streaming remain unsupported rather than being
silently represented as complete response-delivery protection.
