Skip to main content

Sending Documents to the Agent

The agent's read tools — docx_read, xlsx_read, pdf_read — can consume documents from three sources:

  1. Artifacts the agent produced earlier in the same run — referenced by artifact_id. Zero-config; the run carries its own registry.
  2. Files you uploaded via the Files API — referenced by file_id. Recommended. OpenAI-compatible, org-scoped, audited.
  3. A raw S3 key — referenced by s3_key. Deprecated — kept working for one release cycle for backwards compatibility.

This page documents the second and third options. For a step-by-step tutorial, see Attach Files to an Agent.

Recommended: POST /v1/files + file_id

The platform exposes an OpenAI-compatible Files API at /v1/files. Upload a file with multipart, get back an opaque file_id, then reference it from a Responses-API request as an input_file content part.

Upload

import httpx

with open("quarterly-report.docx", "rb") as f:
response = httpx.post(
"https://api.alpha.alien.club/v1/files",
headers={"Authorization": "Bearer oat_YOUR_TOKEN"},
files={"file": (
"quarterly-report.docx",
f.read(),
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)},
data={"purpose": "user_data"},
)

file_id = response.json()["id"] # file_8pauo0KQA-g_Bi7LHx5RA

Limits and allowlist:

ConstraintValue
Max file size50 MB
Allowed MIMEapplication/pdf, …wordprocessingml.document (.docx), …spreadsheetml.sheet (.xlsx), text/markdown, text/plain
DetectionFrom file bytes (magic number), not the Content-Type header

Reference from a Responses API request

Use OpenAI's standard input_file content part:

POST /agent/{agent_id}/responses
Authorization: Bearer oat_YOUR_TOKEN
Content-Type: application/json

{
"model": "claude-sonnet-4-6",
"input": [{
"role": "user",
"content": [
{ "type": "input_file", "file_id": "file_8pauo0KQA-g_Bi7LHx5RA" },
{ "type": "input_text", "text": "Summarise the attached quarterly report." }
]
}],
"stream": true
}

The backend automatically prefixes the agent's prompt with a structured preamble listing every attached file (id, filename, mime type), so the model calls the matching read tool on its own:

# Tool call emitted by the agent
docx_read_tool({ "file_id": "file_8pauo0KQA-g_Bi7LHx5RA" })

Properties

  • Org-scoped. A file uploaded while org A is active is invisible to org B (cross-org access returns 404, not 403).
  • No platform credentials leave the backend. The worker fetches the bytes via a freshly-signed S3 URL minted at job-dispatch time.
  • Audited. Every upload, download, and delete is logged with the uploader's identity.
  • OpenAI SDK compatible. Point an OpenAI SDK at the platform and client.files.create(file=..., purpose="user_data") Just Works.

See Attach Files to an Agent for the full walkthrough with multi-language examples, list/delete endpoints, and troubleshooting.

Multiple files in a single turn

Pass any number of input_file parts in the same content array. The agent typically issues the read tool calls in parallel:

"content": [
{ "type": "input_file", "file_id": "file_aaa..." },
{ "type": "input_file", "file_id": "file_bbb..." },
{ "type": "input_file", "file_id": "file_ccc..." },
{ "type": "input_text", "text": "Compare the three reports." }
]

How read tools resolve the reference

All three input modes go through the same resolution path inside the worker. The schema, identical across docx_read / xlsx_read / pdf_read:

class InputSchema(BaseModel):
artifact_id: str | None = Field(default=None,
description="ULID-prefixed artifact id emitted earlier in the job.")
file_id: str | None = Field(default=None,
description="File id from a POST /v1/files upload (`file_<base64url>`).")
s3_key: str | None = Field(default=None,
description="DEPRECATED: raw S3 key. Use file_id instead.")

Exactly one of the three must be set. Resolution:

InputResolution path
artifact_idLook up in ComputeContext.artifacts → fetch via worker storage credentials
file_idLook up in ComputeContext.files_by_id → fetch via the backend-injected presigned URL
s3_keyFetch directly via worker storage credentials (deprecated, logs a warning)

Setting more than one or none is a validation error returned to the agent.

Lifecycle

  • Files uploaded via /v1/files persist until DELETE or until the owning organization is deleted (cascade). No automatic TTL.
  • Inputs are not mirrored onto Job.result.artifacts — that field exclusively reflects artifacts the agent produced. If you need to track which file a job consumed, the file_id is persisted on Job.input_file_ids.

Security notes

  • The agent sees the file_id. Do not encode sensitive identifiers in the file id (the backend mints opaque IDs anyway, but treat any field surfaced to the model as model-readable).
  • Read tools do not execute documents — they parse text, headings, tables, and bytes. Macros in .docx, formulas in .xlsx, and JavaScript in .pdf are not evaluated. The tools are extraction-only by design.

Appendix: Legacy s3_key flow (deprecated)

Deprecated

The s3_key parameter and direct uploads to job-contexts still work but are scheduled for removal one major release after the Files API ships. Migrate to POST /v1/files + file_id.

The deprecated flow requires clients to hold raw SCW_S3_* credentials, has no org-scoping (any client can read any other client's templates/), and produces no audit trail.

The legacy approach uploads directly to the platform's context bucket via S3-compatible credentials, then references the file by S3 key in the prompt.

Upload location (legacy)

SettingValue
Bucketjob-contexts (the value of S3_CONTEXT_BUCKET on the platform)
Regionfr-par (configurable via SCW_S3_REGION)
EndpointSCW_S3_ENDPOINT
CredentialsSCW_S3_ACCESS_KEY / SCW_S3_SECRET_KEY issued by platform admin
Key conventiontemplates/<your-filename>

Upload with the AWS SDK (Python)

import boto3

s3 = boto3.client(
"s3",
endpoint_url=SCW_S3_ENDPOINT,
aws_access_key_id=SCW_S3_ACCESS_KEY,
aws_secret_access_key=SCW_S3_SECRET_KEY,
region_name="fr-par",
)

with open("quarterly-report-template.docx", "rb") as f:
s3.put_object(
Bucket="job-contexts",
Key="templates/quarterly-report-template.docx",
Body=f.read(),
ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
)

Reference from a Responses API prompt (legacy)

Mention the s3_key in the user prompt — the agent will pass it through to the read tool:

{
"model": "claude-sonnet-4-6",
"input": "Read this template and tell me what placeholders it uses.\n\nDOCX template: s3_key='templates/quarterly-report-template.docx'",
"stream": true
}

The worker logs a WARNING every time a read tool resolves through the s3_key branch — these warnings disappear once the deprecation window closes and the parameter is removed.

See also