Sending Documents to the Agent
The agent's read tools — docx_read, xlsx_read, pdf_read — can consume documents from three sources:
- Artifacts the agent produced earlier in the same run — referenced by
artifact_id. Zero-config; the run carries its own registry. - Files you uploaded via the Files API — referenced by
file_id. Recommended. OpenAI-compatible, org-scoped, audited. - 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:
| Constraint | Value |
|---|---|
| Max file size | 50 MB |
| Allowed MIME | application/pdf, …wordprocessingml.document (.docx), …spreadsheetml.sheet (.xlsx), text/markdown, text/plain |
| Detection | From 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, not403). - 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:
| Input | Resolution path |
|---|---|
artifact_id | Look up in ComputeContext.artifacts → fetch via worker storage credentials |
file_id | Look up in ComputeContext.files_by_id → fetch via the backend-injected presigned URL |
s3_key | Fetch 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/filespersist 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 onJob.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.pdfare not evaluated. The tools are extraction-only by design.
Appendix: Legacy s3_key flow (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)
| Setting | Value |
|---|---|
| Bucket | job-contexts (the value of S3_CONTEXT_BUCKET on the platform) |
| Region | fr-par (configurable via SCW_S3_REGION) |
| Endpoint | SCW_S3_ENDPOINT |
| Credentials | SCW_S3_ACCESS_KEY / SCW_S3_SECRET_KEY issued by platform admin |
| Key convention | templates/<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
- Attach Files to an Agent — step-by-step tutorial for the recommended flow
- Agent Artifacts — the read/write tools,
ArtifactRef, and download endpoint - Wiring an Artifact-Capable Workflow — how to enable the read tools on a workflow
- Responses API — the request/response shape used to drive the agent