Skip to Content

Files

Files are binary attachments (images, PDFs, audio) that can be associated with Tests and TestResults. They are managed through a dedicated upload API rather than the standard push() method.

Note: As of version 0.8.0, file bytes are stored in object storage (GCS/S3/local filesystem) rather than Postgres. Downloads return a 302 redirect to a presigned URL; the SDK File.download() method follows the redirect transparently.

File

A File represents a binary attachment stored on the platform.

Properties

PropertyTypeDescription
idstrUnique identifier (assigned on upload)
filenamestrOriginal file name
content_typestrMIME type (e.g., image/png)
size_bytesintFile size in bytes
descriptionstrOptional description
entity_idstrID of the parent entity
entity_typestrParent type (Test, TestResult, Trace, or ArchitectSession)
positionintOrdering position within the entity
content_hashstrSHA-256 hex digest of the file bytes (useful for deduplication)
extracted_textstrText extracted from the file at upload time (OCR/text-layer)
extraction_statusstrpending | done | failed | not_applicable

Note: storage_path (the internal object-storage key) is intentionally not exposed in API responses.

Limits

  • Max file size: 10 MB per file
  • Max total per entity: 20 MB
  • Max files per request: 10
  • Allowed types: images, PDFs, audio files

Uploading Files

Via Test Entity

The simplest way to attach files is through the Test entity:

test_with_files.py
from rhesis.sdk.entities import Test, Prompt

# Attach files during creation
test = Test(
    category="Safety",
    topic="Image Analysis",
    behavior="Identifies harmful images",
    prompt=Prompt(content="Describe this image"),
    files=["./screenshot.png", "./document.pdf"],
)

# push() uploads the test, then uploads the files
test.push()

# Or add files to an existing test
test.add_files(["./another_image.jpg"])

Via File.add()

Use File.add() directly for more control:

file_add.py
from rhesis.sdk.entities import File

# Upload from file paths
files = File.add(
    sources=["./image.png", "./audio.wav"],
    entity_id="test-uuid-here",
    entity_type="Test",
)

print(f"Uploaded {len(files)} files")
for f in files:
    print(f"  {f.filename} ({f.size_bytes} bytes)")

Base64 Upload

For programmatic uploads without local files:

file_base64.py
from rhesis.sdk.entities import File

files = File.add(
    sources=[
        {
            "filename": "generated.png",
            "content_type": "image/png",
            "data": "<base64-encoded-content>",
        }
    ],
    entity_id="test-uuid-here",
    entity_type="Test",
)

Downloading Files

Download file content to a local directory:

download_file.py
# Get files attached to a test
files = test.get_files()

for f in files:
    path = f.download(directory="./downloads")
    print(f"Saved: {path}")

For custom HTTP clients, follow redirects when calling GET /files/{id}/content. The API returns ETag headers, so clients can send If-None-Match on later reads to reuse cached content when the file has not changed.

Thumbnails

Image-capable clients can request server-generated WebP thumbnails through the REST API:

thumbnail.sh
curl -L -H "Authorization: Bearer $RHESIS_API_KEY" "https://api.rhesis.ai/files/<file-id>/thumbnail?size=144" --output thumbnail.webp

Supported thumbnail sizes are 72, 144, and 288 pixels. The endpoint also uses redirects and ETag caching.

File references during execution

When a test with files runs against an SDK connector endpoint, the execution pipeline passes FileReference objects instead of raw bytes. Each reference includes metadata, pre-extracted text, and a signed URL for on-demand byte reads.

connector_files.py
from rhesis.sdk import endpoint
from rhesis.sdk.connector.types import FileReference

@endpoint(
    name="review-upload",
    request_mapping={
        "prompt": "{{ input }}",
        "files": "{{ files }}",
    },
    response_mapping={"output": "$.answer"},
)
def review_upload(prompt: str, files: list[FileReference]) -> dict:
    extracted = [file.extracted_text or "" for file in files]
    return {"answer": answer_with_files(prompt, extracted)}

See Connector File Attachments for raw byte reads with read_bytes() and aread_bytes().

Managing Files

Listing Files

list_files.py
# Get all files for a test
files = test.get_files()

for f in files:
    print(f"{f.filename} - {f.content_type} ({f.size_bytes} bytes)")

Deleting Files

delete_file.py
# Delete via test helper
test.delete_file(file_id="file-uuid-here")

# Or delete directly
file = files[0]
file.delete()

Note - File.push() is not supported. Use File.add() or test.add_files() to upload files.