Skip to content

Allow Your Agent to Ask for Uploads

Walk-through for enabling the asset-upload tool on an agent and verifying end-to-end that a user can upload a file in the chat, the agent can read it back, and the asset persists across sessions.

For the conceptual picture (limits, lifecycle, encryption, deferred follow-ups), see the asset upload reference. For the design rationale of why assets and references are separate primitives, see Assets vs. References.

Prerequisites

  • An organization you're an admin of (the toggle requires admin role on the agent's organization).
  • An agent that already has an AI config and at least one read-write memory attached. Asset upload binds uploaded files to the user's per-agent memory, so the agent needs somewhere to put them.
  • A chat surface to test from — the Chat tab on the agent detail page is the simplest option.

Step 1: Turn on the asset-upload tool

  1. Open the agent detail page.
  2. Switch to the Settings tab.
  3. Find the Capabilities section.
  4. Check Allow this agent to ask users for uploads.

The toggle saves on click. Behind the scenes it adds the canonical key asset:upload to the App's agentTools allowlist for the App that shares the agent's URN.

If the toggle is greyed out with a "No caller-identity App for this agent" message, the agent doesn't have a 1:1 App backing it yet. Create an App at the agent's URN first (Step 3 of Building an agent) and come back.

Step 2: How the agent invokes it

With the toggle on, the agent gets a new tool in its schema: h-asset-request-upload. The agent calls it mid-turn with a prompt and (optionally) constraints:

{
  "prompt": "Could you upload your business plan PDF?",
  "allowedMimeTypes": ["application/pdf"],
  "maxSizeBytes": 10485760
}

The platform suspends the turn, surfaces the prompt to the user, and resumes once the user uploads, declines, or times out. The agent doesn't poll — the tool call returns when there's a result.

Without the toggle, calling this tool returns TOOL_NOT_ENABLED and the chat continues without the prompt being shown.

Step 3: What the user sees

In the portal Chat tab the user sees:

  • An in-chat upload card with the agent's prompt, an "Attach file" button, and a "Decline" button.
  • A paperclip icon in the composer, available any time the agent is enabled — users can volunteer an upload without being asked.

When the user picks a file, the bytes go directly from the browser to object storage (R2 or MinIO in dev). The portal never proxies the bytes. A chip appears above the composer showing the filename, size, and scan status.

Possible outcomes:

  • uploaded — the bytes are in. Agent receives assetId, filename, mimeType, sizeBytes, description.
  • declined — the user dismissed the prompt.
  • timeout — 5 minutes elapsed without a response.

Step 4: What the agent does with the result

In the next turn, the agent's tool result includes the asset metadata. From there it can:

  • Reference the asset by URN in subsequent messages — <memory-urn>:assets:<asset-id> is stable.
  • Read the bytes — call the platform's download endpoint to mint a short-TTL presigned URL (default 5 min, max 1 hour), then fetch and feed into a model context, OCR, or whatever the next step needs.
  • List prior uploadsagentAssets(agentUrn, mimeType?, ...) returns assets in the user's per-agent memory, paginated and filterable by MIME type.

Downloads are gated on scanStatus = CLEAN. PENDING returns SCAN_PENDING (try again in a few seconds), BLOCKED returns SCAN_BLOCKED (the asset failed virus scanning and cannot be downloaded).

Step 5: Verify end-to-end

A 60-second smoke test:

  1. With the toggle on, open the agent's Chat tab.
  2. In the composer, click the paperclip and pick a small PDF or image.
  3. Confirm the chip appears above the composer with the filename, size, and "✓ Clean" once the scan completes.
  4. Reload the page. The chat resumes; the upload chip is part of the message history.
  5. Open the agent's conversations editor or call agentAssets directly from the GraphQL API — the asset shows up in the user's per-agent memory.
  6. Toggle the capability off, start a new chat, and ask the agent (in plain English) to request an upload. The agent should reply that the upload tool is unavailable rather than surfacing a prompt.

Troubleshooting

Symptom What to check
Toggle disabled, "No caller-identity App" message Agent doesn't have a 1:1 App at the same URN. Create one (see Building an agent).
PERMISSION_DENIED on toggle save The mutation is gated to org admin. Ask an admin to flip it, or have your role upgraded.
Paperclip icon missing in composer Toggle is off, or the agent's agentUrn isn't being passed into <AgentChat>. Reload after enabling.
Upload returns SIZE_EXCEEDED The agent's per-call cap (maxSizeBytes) or the platform default (50 MB) was exceeded. Either send a smaller file or have the agent raise its cap.
Upload returns MIME_NOT_ALLOWED File's MIME type isn't in the agent's allowedMimeTypes list. The list is set per call.
Download returns SCAN_PENDING Scanner hasn't finished. Retry in a few seconds; scan latency is typically <10s.
Download returns SCAN_BLOCKED Asset flagged by virus scanning. Cannot be downloaded; the user should re-upload a clean copy.