Skip to main content
Version: 2026.1

File Attachments

Users can upload files into a chat session. The agent reads them with path-sandboxed SDK tools (view, grep), or — for Pimcore assets — uses the stage_asset MCP tool to pull an asset copy into the session's scratch directory.

What the user does

Drag a file into the chat input area (or paste an image). The file uploads to the agent-server and is attached to the next message. The agent sees it as part of the conversation context and can reference it by name.

Images are sent as native SDK attachments for multimodal processing (the model sees the image directly). Other file types — text, CSV, PDF, logs — are not sent inline; instead the agent gets a hint saying "use read_file to inspect filename" and fetches the content when needed.

Directory layout

Each session has two scratch subdirectories. Both are session-scoped, and both are wiped when the session is deleted.

/app/uploads/{chatSessionId}/
├── uploaded/ ← User-uploaded files
│ └── {uuid}.png
└── staged/ ← Copies of Pimcore assets, pulled in by the agent
└── {assetId}-{filename}
  • uploaded/ holds what the user dropped into chat.
  • staged/ holds copies of Pimcore assets that the agent requested via stage_asset — typically because the agent needs to grep or view an asset that is too large for the context window.

Lifecycle

1. User uploads file    → POST /agent-server/api/upload
Stored in {tempSessionId}/uploaded/

2. First message sent → POST /agent-server/api/chat (with context.fileIds)
Files moved to {chatSessionId}/uploaded/

3. During conversation → SDK tools (view, grep) access files
Path-sandboxed to /app/uploads/{chatSessionId}/
→ stage_asset stages Pimcore assets
Written to {chatSessionId}/staged/

4. Session deleted → DELETE /agent-server/api/sessions/:id
Entire {chatSessionId}/ cleaned up

5. Periodic cleanup → Every AGENT_SERVER_STAGED_FILE_CLEANUP_INTERVAL_MS (default 1 h)
Staged files older than
AGENT_SERVER_STAGED_FILE_MAX_AGE_MS (default 24 h) removed
User uploads are never auto-cleaned

Session scoping is load-bearing

Path sandboxing is what keeps one user's files out of another user's chat. FileManager.getFilePath(fileId, sessionId) searches uploaded/ then staged/ within the supplied session — it never looks at other sessions' directories. The chat session id reaches stage_asset (and other chat-scoped tools) via the bound _mcp_token_reference request attribute, which McpAccessTokenAuthenticator derives from the validated bearer. Calls authenticated by any other mechanism (PAT, SessionBridge) carry no session context and are rejected by the tool.

The SDK security hook (see Architecture → Tool Security) checks every file tool invocation against the session's allowed directories. An agent cannot escape the session scratch area even if it tries.

Docker layout

The upload directory is a bind mount shared between the agent-server and php containers:

./var/tmp/agent-uploads:/app/uploads

Both containers must run as the same user (user: '1000:1000') so they can read/write session directories. FileManager creates session subdirectories on demand.

Cleanup configuration

Environment variableDefaultPurpose
AGENT_SERVER_STAGED_FILE_MAX_AGE_MS86 400 000 (24 h)Maximum age before a staged asset file is removed.
AGENT_SERVER_STAGED_FILE_CLEANUP_INTERVAL_MS3 600 000 (1 h)How often the cleanup sweep runs.

See Configuration → Environment Variables for every file-related setting.