Skip to content
Open
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
36 changes: 22 additions & 14 deletions docs/migrate_detect_v1_to_v2.md → docs/migrate_detect.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
# Migrate Detect from V1 to V2 (skyvault Python SDK)

The skyvault Python SDK replaces the Detect V1 methods with the V2 methods, using the
same method and class names as the flowvault Detect SDK. There is no `V2` suffix
anywhere. `deidentify_file` keeps its name and takes the V2 `DeidentifyFileRequest`,
returning the V2 `DeidentifyFileResponse`. Because the V1 methods and classes are
removed, there is no name conflict. All V2 classes live in `skyflow.vault.detect` and
the enums in `skyflow.utils.enums`.

V1 callers must migrate when they upgrade, so this ships as a major release. Client
creation and the `skyflow_client.detect()` accessor do not change.
# Migrate to the new Detect methods (skyflow 3.0.0)

The skyvault Python SDK replaces the previous Detect methods with the new Detect methods,
using the same method and class names as the flowvault Detect SDK — there is no version
suffix on any of them. `deidentify_file` keeps its name and now takes the new
`DeidentifyFileRequest`, returning the new `DeidentifyFileResponse`. Because the previous
methods and classes are removed, there is no name conflict. All Detect classes live in
`skyflow.vault.detect` and the enums in `skyflow.utils.enums`.

Callers of the previous Detect methods must migrate when they upgrade, so this ships in the
next major release, **skyflow 3.0.0** — pin or upgrade accordingly (`pip install "skyflow==3.0.0"`).
Client creation and the `skyflow_client.detect()` accessor do not change.

> **⚠️ Biggest behaviour change:** `deidentify_file` **no longer waits for the result by
> default.** It used to always poll; now, without `poll_options`, it submits and returns
> immediately — `status` is `None`, `output` is empty, and nothing is written to disk. Pass
> `poll_options` to block until the run finishes, or retrieve the result later with `get_run`.
> Code ported unchanged runs without error but produces no outputs, so the failure surfaces
> downstream rather than at the call site.

## What changes

Expand Down Expand Up @@ -355,7 +363,7 @@ fields as the V2 `DeidentifyFileResponse` (`run_id`, `status`, `output_type`, `o

## Timeline

| Release | V1 methods | V2 methods |
| Release | Previous Detect methods | New Detect methods |
| --- | --- | --- |
| skyvault 2.1.x | available | not available |
| next major | removed | available under the flowvault names |
| skyflow 2.1.x | available | not available |
| skyflow 3.0.0 | removed | available under the flowvault names |
100 changes: 85 additions & 15 deletions flowvault/README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion flowvault/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ python flowvault/samples/vault_api/insert_records.py
| [upload_files.py](vault_api/upload_files.py) | Upload files to file columns (`file_path` / `base64` / `file_object`) |
| [delete_files.py](vault_api/delete_files.py) | Delete files from file columns (by `skyflow_id` or `unique_values`) |

## Detect V2
## Detect

| Sample | Demonstrates |
|---|---|
Expand Down
1 change: 1 addition & 0 deletions flowvault/samples/detect_api/check_guardrails.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def perform_check_guardrails():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
3 changes: 3 additions & 0 deletions flowvault/samples/detect_api/deidentify_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def perform_deidentify_file_submit_only():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down Expand Up @@ -75,6 +76,7 @@ def perform_deidentify_file_poll():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down Expand Up @@ -110,6 +112,7 @@ def perform_deidentify_file_presigned():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
2 changes: 2 additions & 0 deletions flowvault/samples/detect_api/deidentify_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def perform_deidentify_string():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down Expand Up @@ -85,6 +86,7 @@ def perform_deidentify_string_inline():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions flowvault/samples/detect_api/get_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def perform_get_run():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions flowvault/samples/detect_api/reidentify_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def perform_reidentify_file():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions flowvault/samples/detect_api/reidentify_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def perform_reidentify_string():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
46 changes: 35 additions & 11 deletions skyvault/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> **This is the current, recommended version of the Skyflow SDK.** V2.1.0 brings flexible auth, multi-vault support, native data types, and rich error diagnostics.
>
> Migrating from v1? See the **[Migration Guide](https://github.com/skyflowapi/skyflow-python/blob/main/docs/migrate_to_v2.md)** for step-by-step instructions. V1 is in maintenance mode and will reach End of Life on October 31, 2026.
> Migrating from v1? See the **[Migration Guide](https://github.com/skyflowapi/skyflow-python/blob/main/docs/migrate_to_v2.md)** for step-by-step instructions. V1 reached End of Life on October 31, 2026 and is no longer supported.

The Skyflow Python SDK is designed to help with integrating Skyflow into a Python backend.

Expand Down Expand Up @@ -552,7 +552,7 @@ Tokenization result: TokenizeResponse(tokenized_fields=[{'token': 'a1b2c3d4-...'

## Detect

Skyflow Detect finds and de-identifies sensitive data in strings and files, re-identifies tokens on demand, and screens text against guardrails. The SDK exposes the Detect V2 API through `DetectController`, returned by `skyflow_client.detect()` and `skyflow_client.detect('<VAULT_ID>')`. Every request is scoped to that vault, and the controller shares the same credentials, timeouts and retries as `vault()`; the `vault_id` is filled in from the vault config for every method.
Skyflow Detect finds and de-identifies sensitive data in strings and files, re-identifies tokens on demand, and screens text against guardrails. The SDK exposes the Detect API through `DetectController`, returned by `skyflow_client.detect()` and `skyflow_client.detect('<VAULT_ID>')`. Every request is scoped to that vault, and the controller shares the same credentials, timeouts and retries as `vault()`; the `vault_id` is filled in from the vault config for every method.

Detect configurations are created in Studio or through the management API — the SDK does not create, update or delete them. Import request/response models from `skyflow.vault.detect` and enums from `skyflow.utils.enums`.

Expand Down Expand Up @@ -677,6 +677,8 @@ configuration = DetectConfiguration(

De-identifies a file. The API is asynchronous: the submit call returns a run id and the result is retrieved from the run. Build the request with `DeidentifyFileRequest`.

> **⚠️ Behaviour change from Detect V1:** `deidentify_file` **no longer waits for the result by default.** Without `poll_options` it submits and returns immediately — `status` is `None`, `output` is empty, and nothing is written to disk. Pass `poll_options` to block until the run finishes, or retrieve the result later with [`get_run`](#get-run-get_runrequest). Code ported from the old blocking behaviour runs without error but produces no outputs, so the failure surfaces downstream rather than at the call site.

Supply the file in exactly one of three ways: `file_path`, `file`, or `value` plus a `DeidentifySourceType` `data_source` (`BASE64`, the `SKYFLOW_ID` of a file record in the vault, or `PRESIGNED_URL`). A local `file` / `file_path` is read when the request is sent, base64-encoded, and its `data_format` inferred from the extension. Passing more than one of them, or none, fails client-side validation before any network call. `configuration_id` / `configuration` follow the same rules as for strings (see [Before you start](#before-you-start)).

- **Submit only** (default): one call, returns `run_id`. `status` is `None` and nothing is written to disk — retrieve the result later with [`get_run`](#get-run-get_runrequest).
Expand Down Expand Up @@ -769,13 +771,31 @@ Synchronous. Re-identification looks tokens up in the vault, so it applies only

Build the request with `ReidentifyStringRequest`: the tokenized text and an optional list of `RedactionLevel` rules. On skyvault vaults each rule names an `entity_name` and a `redaction_type` — `PLAIN_TEXT` reveals the original value, `MASKED` masks it, `REDACTED` keeps the token, `DEFAULT` applies the vault's default. Without rules every token is replaced by its original value.

Only text that contains vault tokens can be re-identified, so the example is a round trip: de-identify with `VAULT_TOKEN` (which stores each value in a `table.column`), then re-identify the `processed_text` that comes back. A vault token is an opaque value like `a1b2c3d4-...`, not the `[NAME_1]` counter placeholder produced by `ENTITY_UNIQUE_COUNTER`.

```python
from skyflow.vault.detect import ReidentifyStringRequest, RedactionLevel
from skyflow.utils.enums import EntityType, RedactionType
from skyflow.vault.detect import (
DeidentifyStringRequest, DetectConfiguration, Detect, Entity,
ReidentifyStringRequest, RedactionLevel,
)
from skyflow.utils.enums import EntityType, DeidentificationType, RedactionType

# 1. De-identify with VAULT_TOKEN so each value is stored in a table.column and can be re-identified.
deidentified = skyflow_client.detect().deidentify_string(
DeidentifyStringRequest(
text='My name is John Doe and my email is johndoe@acme.com.',
configuration=DetectConfiguration(detect=Detect(entities=[
Entity(entity_type=EntityType.NAME, deidentification_type=DeidentificationType.VAULT_TOKEN, destination='persons.name'),
Entity(entity_type=EntityType.EMAIL_ADDRESS, deidentification_type=DeidentificationType.VAULT_TOKEN, destination='persons.email'),
])),
)
)
# deidentified.processed_text now holds vault tokens, e.g. 'My name is a1b2c3d4-... and my email is e5f6a7b8-...'

# 2. Re-identify those tokens; on skyvault each rule names an entity_name + redaction_type.
response = skyflow_client.detect().reidentify_string(
ReidentifyStringRequest(
text='My name is [NAME_1] and my email is [EMAIL_ADDRESS_1].',
text=deidentified.processed_text,
redaction_level=[
RedactionLevel(entity_name=EntityType.NAME, redaction_type=RedactionType.PLAIN_TEXT),
RedactionLevel(entity_name=EntityType.EMAIL_ADDRESS, redaction_type=RedactionType.MASKED),
Expand All @@ -799,30 +819,34 @@ import base64
from skyflow.vault.detect import ReidentifyFileRequest, RedactionLevel
from skyflow.utils.enums import ReidentifySourceType, FileDataFormat, EntityType, RedactionType, DetectRunStatus

data_format = FileDataFormat.TXT
with open('/data/redacted/notes.txt', 'rb') as handle:
encoded = base64.b64encode(handle.read()).decode('utf-8')

response = skyflow_client.detect().reidentify_file(
ReidentifyFileRequest(
data_source=ReidentifySourceType.BASE64,
value=encoded,
data_format=FileDataFormat.TXT,
data_format=data_format,
redaction_level=[RedactionLevel(entity_name=EntityType.NAME, redaction_type=RedactionType.PLAIN_TEXT)],
)
)

if response.status == DetectRunStatus.SUCCESS:
for index, output in enumerate(response.output):
# output.processed_file is base64 or a presigned URL, per response.output_type
with open(f'reidentified-{index}.txt', 'wb') as out:
out.write(base64.b64decode(output.processed_file))
# Branch on output_type: base64 bytes are decoded, a presigned URL is downloaded.
if response.output_type == ReidentifySourceType.BASE64:
with open(f'reidentified-{index}.{data_format.value}', 'wb') as out:
out.write(base64.b64decode(output.processed_file))
else: # ReidentifySourceType.PRESIGNED_URL — processed_file is a URL to fetch
print('download re-identified file from', output.processed_file)
```

Returns a `ReidentifyFileResponse` with `status`, `output_type`, `output` (a list of `FileOutput`) and `metrics`.
Returns a `ReidentifyFileResponse` with `status`, `output_type` (a `ReidentifySourceType`), `output` (a list of `FileOutput`) and `metrics`.

### Check Guardrails: `.check_guardrails(request)`

Synchronous. Screens text for toxicity and a list of denied topics — a natural pre-LLM check. Build the request with `CheckGuardrailsRequest`. `check_toxicity` and `deny_topics` are optional; the SDK sends each only when set and fills in no default. The response is passed through as the API returns it.
Synchronous. Screens text for toxicity and a list of denied topics — a natural pre-LLM check. Build the request with `CheckGuardrailsRequest`. `check_toxicity` and `deny_topics` are optional; the SDK sends each only when set and fills in no default. **When `check_toxicity` is omitted, the server still checks toxicity by default.** The response is passed through as the API returns it.

```python
from skyflow.vault.detect import CheckGuardrailsRequest
Expand Down
1 change: 1 addition & 0 deletions skyvault/samples/detect_api/check_guardrails.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def perform_check_guardrails():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions skyvault/samples/detect_api/deidentify_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def perform_deidentify_file():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
2 changes: 2 additions & 0 deletions skyvault/samples/detect_api/deidentify_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def perform_deidentify_string():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down Expand Up @@ -78,6 +79,7 @@ def perform_deidentify_string_inline():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions skyvault/samples/detect_api/get_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def perform_get_run():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions skyvault/samples/detect_api/reidentify_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def perform_reidentify_file():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
1 change: 1 addition & 0 deletions skyvault/samples/detect_api/reidentify_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def perform_reidentify_string():
'code': error.http_code,
'message': error.message,
'details': error.details,
'request_id': error.request_id,
})


Expand Down
Loading