Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,5 @@ __marimo__/
# Streamlit
.streamlit/secrets.toml
internal/

.DS_Store
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Useful flags:
| `--hubs` | Hub trackers to activate: `huggingface`, `torchhub` |
| `--print-startup-report` | Print per-integration status at startup |
| `--strict-integrations` | Fail if a requested integration can't be loaded |
| `--attachments` | Enable opt-in raw input/output attachment upload |
| `--no-propagate` | Don't pass WildEdge env vars to child processes |

## SDK
Expand Down Expand Up @@ -106,8 +107,9 @@ For unsupported frameworks, see [Manual tracking](https://github.com/wild-edge/w
| `app_identity` | `<project_key>` | Namespace for offline persistence. Set per-app in multi-process workloads (or `WILDEDGE_APP_IDENTITY`) |
| `enable_offline_persistence` | `true` | Persist unsent events to disk and replay on restart |
| `sampling_interval_s` | `30.0` | Seconds between background hardware snapshots. Set to `0` or `None` to disable (or `WILDEDGE_SAMPLING_INTERVAL_S`) |
| `attachments_enabled` | `false` | Opt-in upload of raw inference inputs/outputs (or `WILDEDGE_ATTACHMENTS_ENABLED`). See [Attachments](https://github.com/wild-edge/wildedge-python/blob/main/docs/configuration.md#attachments) |

For advanced options (batching, queue tuning, dead-letter storage), see [Configuration](https://github.com/wild-edge/wildedge-python/blob/main/docs/configuration.md).
For advanced options (batching, queue tuning, dead-letter storage, attachments), see [Configuration](https://github.com/wild-edge/wildedge-python/blob/main/docs/configuration.md).

## Projects using this SDK

Expand All @@ -121,6 +123,10 @@ Using WildEdge in your project? Open a PR to add it to the list.

## Security & Privacy

By default the SDK transmits only anonymized telemetry, never raw model inputs
or outputs. The one exception is opt-in [attachments](https://github.com/wild-edge/wildedge-python/blob/main/docs/configuration.md#attachments)
(`attachments_enabled`), which upload raw bytes you explicitly pass in.

Report security and privacy issues to: support@wildedge.dev

## Links
Expand Down
18 changes: 18 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,21 @@ Full reference for all `WildEdge` client parameters.
| `max_event_age_sec` | `900` | - | Max age in seconds before an event is dropped |
| `enable_dead_letter_persistence` | `false` | - | Persist dropped batches to disk for later inspection |
| `debug` | `false` | `WILDEDGE_DEBUG` | Log SDK internals to console |

## Attachments

Opt-in upload of raw inference inputs/outputs (e.g. the source image or the
generated text) alongside telemetry. Off by default; requires the attachment
feature enabled on your project. Bytes are buffered locally and uploaded in the
background via presigned URLs, so the event flush never waits on the upload.

| Parameter | Default | Env var | Description |
|---|---|---|---|
| `attachments_enabled` | `false` | `WILDEDGE_ATTACHMENTS_ENABLED` | Enable raw input/output upload |
| `max_attachments_per_inference` | `10` | - | Cap on attachments buffered per inference event |
| `max_attachment_size_bytes` | `10485760` | - | Per-attachment size limit (10 MB); larger ones are dropped |
| `attachment_storage_strategy` | `"file"` | - | `"file"` (bytes on disk) or `"inline"` (small blobs embedded in the record) |
| `attachment_filter` | `None` | - | `Callable[[list[Attachment]], list[Attachment]]` to redact/drop before buffering |
| `attachment_dir` | per `app_identity` | - | Override the local buffer directory |

See [Track attachments](manual-tracking.md#track-attachments) for usage.
36 changes: 36 additions & 0 deletions docs/manual-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,42 @@ handle.feedback(FeedbackType.THUMBS_DOWN)

`FeedbackType` values: `THUMBS_UP`, `THUMBS_DOWN`.

## Track attachments

Opt-in upload of the raw bytes behind an inference, such as the source image,
audio clip, or generated text, so you can inspect or curate them later. This is
off by default and requires the attachment feature enabled on your project.
Enable it at init, then pass `attachments=` to `track_inference`:

```python
import wildedge
from wildedge import Attachment

client = wildedge.init(attachments_enabled=True)
handle = client.register_model(model, model_id="doc-classifier-v1")

handle.track_inference(
duration_ms=120,
input_modality="image",
output_modality="text",
attachments=[
Attachment(content_type="image/jpeg", role="input", data=image_bytes),
Attachment(content_type="text/plain", role="output", data=answer.encode()),
],
)
```

An `Attachment` carries either in-memory `data` or a file `path`, plus a
`role` (`"input"` or `"output"`) and `content_type`. The SDK writes a reference
into the inference event immediately and uploads the bytes in the background via
a presigned URL. A failed or disabled upload never blocks telemetry.

Bytes are buffered to disk and survive restarts. Capture is gated by
`max_attachments_per_inference`, `max_attachment_size_bytes`, and an optional
`attachment_filter` hook. See [Configuration](configuration.md#attachments) and
[`examples/attachments_example.py`](../examples/attachments_example.py) for the
full reference.

## Track spans for agentic workflows

Use span events to track non-inference steps like planning, tool calls, retrieval, or memory updates.
Expand Down
62 changes: 62 additions & 0 deletions examples/attachments_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["wildedge-sdk"]
#
# [tool.uv.sources]
# wildedge-sdk = { path = "..", editable = true }
# ///
"""
Attachment upload example. Run with: uv run attachments_example.py

Opt-in raw input/output capture. When `attachments_enabled=True` (and the
project has the paid feature turned on), the SDK buffers the raw bytes locally,
writes a reference into the inference event, and uploads the bytes independently
via a presigned URL, so the batch flush never waits on the upload.

Attachments are off by default and must be explicitly enabled. Set WILDEDGE_DSN
to see real uploads; otherwise the client runs in no-op mode.
"""

import wildedge
from wildedge import Attachment


# Optional: redact / drop attachments before they are buffered.
def redact(attachments: list[Attachment]) -> list[Attachment]:
return [a for a in attachments if a.content_type != "application/secret"]


client = wildedge.init(
app_version="1.0.0",
attachments_enabled=True,
max_attachments_per_inference=5,
max_attachment_size_bytes=5 * 1024 * 1024,
attachment_storage_strategy="file", # or "inline" for small blobs
attachment_filter=redact,
)

handle = client.register_model(
object(),
model_id="doc-classifier-v1",
source="local",
family="custom",
)

# Pretend these came from a real inference call.
image_bytes = b"\xff\xd8\xff\xe0fake-jpeg-bytes"
answer = "This document is an invoice."

inference_id = handle.track_inference(
duration_ms=120,
input_modality="image",
output_modality="text",
attachments=[
Attachment(content_type="image/jpeg", role="input", data=image_bytes),
Attachment(content_type="text/plain", role="output", data=answer.encode()),
],
)

print(f"tracked inference {inference_id[:8]}… with 2 attachments")

# Bytes upload in the background; flush/close lets buffered events drain.
client.close()
Loading
Loading