Pass files and images into workflows — as inputs, thread context, or saved messages
Every file a workflow touches — an uploaded screenshot, a referenced PDF, a local source file — is an attachment: a database row carrying a filename, a MIME type, and bytes. Workflows never reach into the filesystem directly. They interact with files through one of three surfaces described below: declared inputs, saved thread messages, or inject attachments on a spawned child thread.One thing that surprises people: there is no attachments field on call_llm. The CallLLM activity loads the current thread’s message history and hands it to the provider driver — attachments reach the model only because they’re already on a message the thread contains. If you need a file in front of the LLM, your job is to get it onto the right thread before call_llm runs.
There are two paths, and both work by placing an attachment onto a thread message that call_llm will later read:
Save it into the current thread on a prior node, using either the save_message hook available on every node or a standalone save_message node.
Inject it into a fresh child thread via thread.inject.attachments on a structural workflow, loop, or router node.
Once an attachment is on a message in the thread, the provider driver does the rest. Image types (jpg, png, gif, webp) are rendered as image content blocks for vision-capable models; text and source files are inlined as text content. Unsupported types are rejected at save time.There is no workflow-level mechanism to attach a file to a single call_llm invocation in isolation — ad-hoc one-shot attachments aren’t currently expressible in the workflow model.
The caller must pass an array of attachment IDs for the screenshots key. The value is referenced in CEL as inputs.screenshots and must resolve to a []string of attachment IDs.
The chat UI does not auto-populate inputs.attachments from the message composer. When a user drags a file into chat, the frontend attaches it to the user message (stored directly on the message row), not to workflow_params. That means the attachment ends up on the thread’s first user message and is visible to call_llm through thread history — but inputs.attachments will be empty unless the caller explicitly plumbs attachment IDs through workflow_params. If your workflow needs inputs.attachments specifically (for example, to forward them to a sub-workflow), the calling surface has to set it.
The min_items / max_items bounds are enforced by validation/inputs.go — the workflow fails to start if the caller passes too few or too many attachment IDs.
Every node supports a save_message hook that runs after the node completes. Its attachments field is a CEL expression — it must evaluate to a []string of attachment IDs.
The ternary guard is the canonical pattern. When inputs.attachments isn’t present, the expression returns null, which evaluateSaveMessageConfig treats as “no attachments”. Without the guard, referencing a missing key raises a CEL error.
The CEL expression must return a list of strings. A bare string like "{{inputs.my_file_id}}" resolves to a scalar, which the evaluator coerces using fmt.Sprintf — you’ll end up with a single-element list whose element is the literal text "<attachment_id>", which almost never matches a real row. Wrap single IDs in a list: "{{[inputs.my_file_id]}}".
A few common shapes:
# Forward all attachments the caller passedattachments: "{{has(inputs.attachments) ? inputs.attachments : null}}"# Forward a single ID (wrap in a list!)attachments: "{{[inputs.cover_image]}}"# Filter to a subsetattachments: "{{inputs.files.filter(f, f.endsWith('.png'))}}"# Empty array — valid, saves a message with no attachmentsattachments: "{{[]}}"
The save_message node takes the same fields as the hook but runs as its own graph step. Use it when you want the save to be a first-class node you can reference from other nodes (nodes.save_files.message_id), gate with a condition, or place at a point in the graph that doesn’t correspond to another node’s post-execution.
The semantics are identical — both paths resolve the CEL expression, load the referenced attachment rows, and attach them to the message. The hook is slightly terser; the standalone node is clearer when the save is the logical step.
Structural parents — type: workflow, type: loop, and type: router — can configure a thread.inject block that seeds the child thread with an initial message. That inject message can carry attachments from three sources.
inject.attachments is only available on the thread-capable node types. It lives on SubWorkflowArgs / LoopArgs / RouterArgs, not on the common node base. Leaf nodes like call_llm don’t have a thread field of their own.
Each entry in thread.inject.attachments is an InjectAttachment with exactly one of id, path, or data set, plus optional filename and mime_type overrides.
This is the most common shape: forward an attachment that’s already in the database into a child thread.
- id: analyst type: workflow ref: builtin://agent thread: mode: new inject: role: user content: | Analyze the attached screenshot and report what you see. attachments: - id: att_01HXYZ
The attachment must already exist in the database. No bytes are read, no file I/O happens — only an association.
Per-item InjectAttachment fields are plain strings, not CEL expressions. You cannot write - id: "{{inputs.file_id}}" and have it interpolate at runtime. The field is a literal proto string, so CEL evaluation never runs over it. If you need dynamic attachment IDs forwarded into a child thread, see Forwarding dynamic attachments to a child below.
The daemon reads bytes from the local filesystem and creates a fresh attachment row for the child thread.
- id: analyst type: workflow ref: builtin://agent thread: mode: new inject: role: user content: Review the attached spec. attachments: - path: docs/specs/feature-x.md - path: /tmp/screenshot.png filename: reference-ui.png mime_type: image/png
filename defaults to filepath.Base(path) and mime_type is detected from the extension. Both can be overridden per entry.
path is daemon-local, and missing files are silently skipped. Reliant’s daemon is the only component with filesystem access in distributed mode; the API server, worker, and daemon gateway cannot read disk. The path is resolved relative to the daemon’s current working directory at execution time (typically the project/worktree path). If the file doesn’t exist or can’t be read, resolveInjectAttachments logs a warning and drops that entry — the node does not fail. Treat missing paths as a quiet no-op you have to notice in logs.
Each evaluation of inject.attachments creates a new attachment row per iteration. In loops, this means the same path: source is read from disk and persisted separately for every iteration, which has memory and I/O implications for large files. See Parallel loops and attachments below.
data is the programmatic escape hatch: raw bytes embedded in the workflow or injected by code that builds the proto directly. In hand-written YAML you’ll almost never use it, but it exists for callers that already have the content in memory.
filename is effectively required — without it there’s no MIME hint and no sensible display name. If mime_type is omitted it’s detected from filename’s extension.
Because per-item InjectAttachment fields aren’t CEL-evaluated, you can’t write something like this and expect it to work:
# ❌ This does NOT interpolate. The child sees no attachments.thread: mode: new inject: content: "Look at these files" attachments: - id: "{{inputs.file_ids[0]}}"
There are two recommended patterns for “forward whatever the user sent into a sub-agent”:Option 1: Save onto the parent thread, use mode: inherit (or fork) on the child. The child sees the parent’s thread history, including the message that carries the attachments.
This is the right answer most of the time. The attachments live on a real thread message; the child inherits (or forks) the thread and reads them the same way any other participant would.Option 2: Save them onto the spawning node’s hook and use a fresh child thread. If you want the child to start clean but still see the attachments, save on the parent hook and then fork:
- id: analyst type: workflow ref: builtin://agent save_message: role: user content: "{{inputs.message}}" attachments: "{{has(inputs.attachments) ? inputs.attachments : null}}" thread: mode: fork inject: role: user content: You are the analyst. Review what's above.
The save hook runs on the parent thread before the child is spawned, then mode: fork copies the parent’s messages (including your saved attachments) into the new child thread.The one pattern that simply doesn’t work is per-item dynamic inject.attachments: [{ id: "{{...}}" }]. If you find yourself reaching for it, restructure around save_message instead.
Reliant’s attachment type registry lives in internal/attachment/filetypes.go and divides files into three buckets: images (sent as image content blocks), text/file references (inlined as text), and unsupported (rejected).Images are binary files the provider driver renders as image content blocks on vision-capable models:
.jpg .jpeg .png .gif .webp
Text and file references are read and inlined as text content. The list is broad, covering:
There’s also a list of special filenames that are treated as text regardless of extension: Dockerfile, Makefile, Gemfile, Rakefile, LICENSE, README, CHANGELOG, .gitignore, .editorconfig, and similar. Call attachment.SupportedExtensions() or read internal/attachment/filetypes.go for the exhaustive list.Anything outside these lists is classified as TypeUnsupported and will be rejected at save time with an invalid attachment type error. If you need an extension added, that’s a change to filetypes.go, not to any workflow config.
Every loop iteration calls resolveInjectAttachments independently. That matters for the three sources in different ways:
id — cheap. The same attachment ID is reused across iterations; no new DB rows are created.
path — the file is re-read from disk on every iteration and a fresh attachment row is persisted each time. For a parallel loop with N iterations, that’s N file reads and N new attachment rows, even if the file hasn’t changed.
data — the raw bytes are duplicated across N child threads, one attachment row per iteration.
None of this is a correctness issue, but it’s worth knowing before you put a large file behind path: or data: in a wide parallel loop. If a file is large or shared across iterations, persist it as a DB attachment once and reference it by id: instead.
Setting thread.memo: true tells the runtime to create the child thread exactly once and reuse it across loop iterations. The inject (content, attachments, everything) is applied only on the first iteration — subsequent iterations see the thread that already exists.
- id: evaluator type: loop thread: mode: new memo: true inject: role: user content: You are evaluating candidates. Here are the reference files. attachments: - id: att_reference_spec
This is the right shape for “seed the agent once, then have it accumulate context as the loop runs.” It’s the wrong shape if you expected each iteration to see a different attachment — with memo: true, the attachments on iteration 2+ are whatever’s already on the memoized thread.See Threads → Memo behavior for the full discussion of memo and inject frequency.
There is no explicit workflow-level cap on path or data injects. However, the SaveMessage activity serializes InjectFileMsg (filename, MIME type, raw bytes) as a Temporal activity payload, and Temporal’s default payload limit is 2 MiB. A large file pushed through path: or data: can silently fail that activity when the encoded payload exceeds the limit — the workflow will surface a Temporal error rather than a nice validation message.
For anything meaningfully large, upload the file once (outside the workflow) to create a DB attachment row, then reference it by id:. id-based inject passes a UUID through activities, not bytes, so the payload stays small regardless of file size.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Reliant","colors":{"primary":"#6E39FF","light":"#8B5CF6","dark":"#6E39FF"},"logo":{"light":"https://mintcdn.com/reliantlabs/NoVh64u5lvQ64evP/images/reliant-logo.svg?fit=max\u0026auto=format\u0026n=NoVh64u5lvQ64evP\u0026q=85\u0026s=23abaccb8c58fa15c19b8080b9ed23ca","dark":"https://mintcdn.com/reliantlabs/NoVh64u5lvQ64evP/images/reliant-logo.svg?fit=max\u0026auto=format\u0026n=NoVh64u5lvQ64evP\u0026q=85\u0026s=23abaccb8c58fa15c19b8080b9ed23ca","href":"/"},"favicon":"https://mintcdn.com/reliantlabs/-3ixAWphy8BqD5FC/favicon.ico?fit=max\u0026auto=format\u0026n=-3ixAWphy8BqD5FC\u0026q=85\u0026s=6f3063bf97699e04c9e99b03d4b29630","navbar":{"links":[{"href":"/changelog","label":"Changelog"},{"href":"https://reliantlabs.io","label":"Main Site"},{"href":"https://github.com/reliant-labs/reliant","label":"GitHub"}],"primary":{"type":"button","label":"Download","href":"https://reliantlabs.io/#downloads"}},"footer":{"socials":{"github":"https://github.com/reliant-labs/reliant","x":"https://x.com/reliantlabs"}},"seo":{"indexing":"navigable"},"icons":{"library":"lucide"},"styling":{"latex":true},"navigation":{"global":{"anchors":[{"anchor":"Main Site","icon":"globe","href":"https://reliantlabs.io"},{"anchor":"GitHub","icon":"github","href":"https://github.com/reliant-labs/reliant"},{"anchor":"Slack","icon":"slack","href":"https://join.slack.com/t/reliant-pn51441/shared_invite/zt-4c7wet6o2-W_Tksw80LaRGxZqUz9GQdA"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"reliantlabs","hasAudioNarration":false,"actualSubdomain":"reliantlabs","customDomains":["docs.reliantlabs.io"],"gitSource":{"type":"github","owner":"reliant-labs","repo":"reliant","deployBranch":"main","contentDirectory":"docs","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6adca6a9f631fa2a8cdb6d4b","collectionId":"e35694f4-90e2-477a-8c4d-9ad4b96a93f9","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6adca6a9f631fa2a8cdb6d4b"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6adcb16ef631fa2a8cdb7cb5","clientVersion":"0.0.3964","searchFilterCounts":[{"language":"default","tag":"Docs","count":80},{"language":"default","tag":"Automations \u0026 integrations","count":11},{"language":"default","tag":"Build \u0026 host with Forge","count":10},{"language":"default","tag":"Use Reliant","count":9},{"language":"default","tag":"Reference","count":9},{"language":"default","tag":"Help","count":7},{"language":"default","tag":"Command line","count":7},{"language":"default","tag":"Build workflows","count":7},{"language":"default","tag":"Built-in workflows","count":6},{"language":"default","tag":"Integrations","count":6}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":true,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"email":"support@reliantlabs.io","showHelpButton":true}},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"starterQuestions":[{"_id":"69b4351bb4eb429b59805b4e","deploymentId":"69b2f13ec3efe3e81c3160ad","questionText":"How does Reliant work?","status":"active","generatedBy":"manual","createdAt":"2026-03-13T16:02:35.042Z","updatedAt":"2026-03-13T16:02:35.042Z","__v":0},{"_id":"69b43515b4eb429b59805b27","deploymentId":"69b2f13ec3efe3e81c3160ad","questionText":"What is Reliant used for?","status":"active","generatedBy":"manual","createdAt":"2026-03-13T16:02:29.723Z","updatedAt":"2026-03-13T16:02:29.723Z","__v":0},{"_id":"69b4350fb4eb429b59805afc","deploymentId":"69b2f13ec3efe3e81c3160ad","questionText":"What can Reliant do?","status":"active","generatedBy":"manual","createdAt":"2026-03-13T16:02:23.336Z","updatedAt":"2026-03-13T16:02:23.336Z","__v":0}],"isAtlas":false,"googleFontsInlined":false},"customCss":[{"filePath":"styles.css","content":":root{--reliant-accent:#6E39FF}#navbar{border-bottom:1px solid rgba(110,57,255,.16)}#footer{border-top:1px solid rgba(110,57,255,.16)}#navbar a[href=\"/\"]{display:inline-flex;align-items:center;gap:.625rem}#navbar a[href=\"/\"] .nav-logo{height:1.5rem;width:auto}#navbar a[href=\"/\"]::after{content:\"Reliant\";display:inline-block;font-size:1.5rem;line-height:1;font-weight:700;letter-spacing:-.04em;color:inherit}#assistant-entry,#assistant-entry button,#assistant-entry-mobile,#assistant-entry-mobile button{font-weight:600}"}],"page":{"pagePath":"features/attachments","slug":"/features/attachments","pageMetadata":{"title":"Attachments","description":"Pass files and images into workflows — as inputs, thread context, or saved messages","href":"/features/attachments"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Pass files and images into workflows — as inputs, thread context, or saved messages\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Mermaid,Note,Tip,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Mermaid)_missingMdxReference(`Mermaid`,true);if(!Note)_missingMdxReference(`Note`,true);if(!Tip)_missingMdxReference(`Tip`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`Every file a workflow touches — an uploaded screenshot, a referenced PDF, a local source file — is an `,_jsx(_components.strong,{children:`attachment`}),`: a database row carrying a filename, a MIME type, and bytes. Workflows never reach into the filesystem directly. They interact with files through one of three surfaces described below: declared inputs, saved thread messages, or inject attachments on a spawned child thread.`]}),`\n`,_jsxs(_components.p,{children:[`One thing that surprises people: there is `,_jsxs(_components.strong,{children:[`no `,_jsx(_components.code,{children:`attachments`}),` field on `,_jsx(_components.code,{children:`call_llm`})]}),`. The `,_jsx(_components.code,{children:`CallLLM`}),` activity loads the current thread’s message history and hands it to the provider driver — attachments reach the model only because they’re already on a message the thread contains. If you need a file in front of the LLM, your job is to get it onto the right thread before `,_jsx(_components.code,{children:`call_llm`}),` runs.`]}),`\n`,_jsx(Heading,{level:`2`,id:`how-attachments-reach-an-llm-call`,children:`How attachments reach an LLM call`}),`\n`,_jsxs(_components.p,{children:[`There are two paths, and both work by placing an attachment onto a thread message that `,_jsx(_components.code,{children:`call_llm`}),` will later read:`]}),`\n`,_jsx(Mermaid,{chart:`flowchart LR\n A[Attachment in DB] --> B{Placed on a thread}\n B -->|via save_message\u003cbr/>hook or node| C[Current thread]\n B -->|via thread.inject.attachments\u003cbr/>on workflow/loop/router| D[Child thread]\n C --> E[call_llm reads history]\n D --> E\n E --> F[Provider driver renders\u003cbr/>image blocks or inline text]`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Save it into the current thread`}),` on a prior node, using either the `,_jsx(_components.code,{children:`save_message`}),` hook available on every node or a standalone `,_jsx(_components.code,{children:`save_message`}),` node.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Inject it into a fresh child thread`}),` via `,_jsx(_components.code,{children:`thread.inject.attachments`}),` on a structural `,_jsx(_components.code,{children:`workflow`}),`, `,_jsx(_components.code,{children:`loop`}),`, or `,_jsx(_components.code,{children:`router`}),` node.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`Once an attachment is on a message in the thread, the provider driver does the rest. Image types (jpg, png, gif, webp) are rendered as image content blocks for vision-capable models; text and source files are inlined as text content. Unsupported types are rejected at save time.`}),`\n`,_jsxs(_components.p,{children:[`There is no workflow-level mechanism to attach a file to a single `,_jsx(_components.code,{children:`call_llm`}),` invocation in isolation — ad-hoc one-shot attachments aren’t currently expressible in the workflow model.`]}),`\n`,_jsxs(Heading,{level:`2`,id:`workflow-inputs-type-attachments`,children:[`Workflow inputs: `,_jsx(_components.code,{children:`type: attachments`})]}),`\n`,_jsx(_components.p,{children:`Workflows can declare an attachments input just like any other typed input:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`20`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`20`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`image-annotator`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`inputs`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` message`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`message`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` screenshots`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`attachments`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` description`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Screenshots to annotate`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` min_items`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` max_items`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`10`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`nodes`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`describe`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`call_llm`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` args`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` model`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` tags`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`flagship`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` save_message`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.message}}\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.screenshots.map(id, string(id))}}\"`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The caller must pass an array of attachment IDs for the `,_jsx(_components.code,{children:`screenshots`}),` key. The value is referenced in CEL as `,_jsx(_components.code,{children:`inputs.screenshots`}),` and must resolve to a `,_jsx(_components.code,{children:`[]string`}),` of attachment IDs.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[`The chat UI does not auto-populate `,_jsx(_components.code,{children:`inputs.attachments`}),` from the message composer.`]}),` When a user drags a file into chat, the frontend attaches it to the user `,_jsx(_components.strong,{children:`message`}),` (stored directly on the message row), not to `,_jsx(_components.code,{children:`workflow_params`}),`. That means the attachment ends up on the thread’s first user message and is visible to `,_jsx(_components.code,{children:`call_llm`}),` through thread history — but `,_jsx(_components.code,{children:`inputs.attachments`}),` will be empty unless the caller explicitly plumbs attachment IDs through `,_jsx(_components.code,{children:`workflow_params`}),`. If your workflow needs `,_jsx(_components.code,{children:`inputs.attachments`}),` specifically (for example, to forward them to a sub-workflow), the calling surface has to set it.`]})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`min_items`}),` / `,_jsx(_components.code,{children:`max_items`}),` bounds are enforced by `,_jsx(_components.a,{href:`/reference/workflow-schema`,children:_jsx(_components.code,{children:`validation/inputs.go`})}),` — the workflow fails to start if the caller passes too few or too many attachment IDs.`]}),`\n`,_jsx(Heading,{level:`2`,id:`saving-attachments-on-a-message`,children:`Saving attachments on a message`}),`\n`,_jsxs(Heading,{level:`3`,id:`the-save_message-hook`,children:[`The `,_jsx(_components.code,{children:`save_message`}),` hook`]}),`\n`,_jsxs(_components.p,{children:[`Every node supports a `,_jsx(_components.code,{children:`save_message`}),` hook that runs after the node completes. Its `,_jsx(_components.code,{children:`attachments`}),` field is a CEL expression — it must evaluate to a `,_jsx(_components.code,{children:`[]string`}),` of attachment IDs.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`echo_user_message`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`call_llm`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` args`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` model`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` tags`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`fast`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` save_message`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.message}}\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{has(inputs.attachments) ? inputs.attachments : null}}\"`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The ternary guard is the canonical pattern. When `,_jsx(_components.code,{children:`inputs.attachments`}),` isn’t present, the expression returns `,_jsx(_components.code,{children:`null`}),`, which `,_jsx(_components.code,{children:`evaluateSaveMessageConfig`}),` treats as “no attachments”. Without the guard, referencing a missing key raises a CEL error.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`The CEL expression `,_jsx(_components.strong,{children:`must return a list of strings`}),`. A bare string like `,_jsx(_components.code,{children:`\"{{inputs.my_file_id}}\"`}),` resolves to a scalar, which the evaluator coerces using `,_jsx(_components.code,{children:`fmt.Sprintf`}),` — you’ll end up with a single-element list whose element is the literal text `,_jsx(_components.code,{children:`\"\u003cattachment_id>\"`}),`, which almost never matches a real row. Wrap single IDs in a list: `,_jsx(_components.code,{children:`\"{{[inputs.my_file_id]}}\"`}),`.`]})}),`\n`,_jsx(_components.p,{children:`A few common shapes:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`11`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`11`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Forward all attachments the caller passed`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{has(inputs.attachments) ? inputs.attachments : null}}\"`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Forward a single ID (wrap in a list!)`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{[inputs.cover_image]}}\"`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Filter to a subset`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.files.filter(f, f.endsWith('.png'))}}\"`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Empty array — valid, saves a message with no attachments`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{[]}}\"`})]}),`\n`]})})}),`\n`,_jsxs(Heading,{level:`3`,id:`the-standalone-save_message-node`,children:[`The standalone `,_jsx(_components.code,{children:`save_message`}),` node`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsxs(_components.a,{href:`/reference/nodes#save-message`,children:[_jsx(_components.code,{children:`save_message`}),` node`]}),` takes the same fields as the hook but runs as its own graph step. Use it when you want the save to be a first-class node you can reference from other nodes (`,_jsx(_components.code,{children:`nodes.save_files.message_id`}),`), gate with a condition, or place at a point in the graph that doesn’t correspond to another node’s post-execution.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`6`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`stash_inputs`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`save_message`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` args`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.message}}\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{has(inputs.attachments) ? inputs.attachments : null}}\"`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The semantics are identical — both paths resolve the CEL expression, load the referenced attachment rows, and attach them to the message. The hook is slightly terser; the standalone node is clearer when the save is the logical step.`}),`\n`,_jsx(Heading,{level:`2`,id:`injecting-files-into-a-child-thread`,children:`Injecting files into a child thread`}),`\n`,_jsxs(_components.p,{children:[`Structural parents — `,_jsx(_components.code,{children:`type: workflow`}),`, `,_jsx(_components.code,{children:`type: loop`}),`, and `,_jsx(_components.code,{children:`type: router`}),` — can configure a `,_jsx(_components.code,{children:`thread.inject`}),` block that seeds the child thread with an initial message. That inject message can carry attachments from three sources.`]}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`inject.attachments`}),` is only available on the thread-capable node types. It lives on `,_jsx(_components.code,{children:`SubWorkflowArgs`}),` / `,_jsx(_components.code,{children:`LoopArgs`}),` / `,_jsx(_components.code,{children:`RouterArgs`}),`, not on the common node base. Leaf nodes like `,_jsx(_components.code,{children:`call_llm`}),` don’t have a `,_jsx(_components.code,{children:`thread`}),` field of their own.`]})}),`\n`,_jsx(Heading,{level:`3`,id:`the-three-sources`,children:`The three sources`}),`\n`,_jsxs(_components.p,{children:[`Each entry in `,_jsx(_components.code,{children:`thread.inject.attachments`}),` is an `,_jsx(_components.code,{children:`InjectAttachment`}),` with exactly one of `,_jsx(_components.code,{children:`id`}),`, `,_jsx(_components.code,{children:`path`}),`, or `,_jsx(_components.code,{children:`data`}),` set, plus optional `,_jsx(_components.code,{children:`filename`}),` and `,_jsx(_components.code,{children:`mime_type`}),` overrides.`]}),`\n`,_jsxs(Heading,{level:`4`,id:`id-—-reference-an-existing-attachment`,children:[_jsx(_components.code,{children:`id`}),` — reference an existing attachment`]}),`\n`,_jsx(_components.p,{children:`This is the most common shape: forward an attachment that’s already in the database into a child thread.`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`11`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`11`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`analyst`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`workflow`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ref`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`builtin://agent`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` thread`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mode`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`new`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` inject`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`|`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` Analyze the attached screenshot and report what you see.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`att_01HXYZ`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The attachment must already exist in the database. No bytes are read, no file I/O happens — only an association.`}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[`Per-item `,_jsx(_components.code,{children:`InjectAttachment`}),` fields are plain strings, not CEL expressions.`]}),` You cannot write `,_jsx(_components.code,{children:`- id: \"{{inputs.file_id}}\"`}),` and have it interpolate at runtime. The field is a literal proto `,_jsx(_components.code,{children:`string`}),`, so CEL evaluation never runs over it. If you need dynamic attachment IDs forwarded into a child thread, see `,_jsx(_components.a,{href:`#forwarding-dynamic-attachments-to-a-child`,children:`Forwarding dynamic attachments to a child`}),` below.`]})}),`\n`,_jsxs(Heading,{level:`4`,id:`path-—-read-a-file-from-disk-at-runtime`,children:[_jsx(_components.code,{children:`path`}),` — read a file from disk at runtime`]}),`\n`,_jsx(_components.p,{children:`The daemon reads bytes from the local filesystem and creates a fresh attachment row for the child thread.`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`13`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`13`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`analyst`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`workflow`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ref`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`builtin://agent`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` thread`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mode`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`new`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` inject`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Review the attached spec.`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`path`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`docs/specs/feature-x.md`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`path`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/tmp/screenshot.png`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` filename`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`reference-ui.png`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mime_type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`image/png`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`filename`}),` defaults to `,_jsx(_components.code,{children:`filepath.Base(path)`}),` and `,_jsx(_components.code,{children:`mime_type`}),` is detected from the extension. Both can be overridden per entry.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`path`}),` is daemon-local, and missing files are silently skipped.`]}),` Reliant’s daemon is the only component with filesystem access in distributed mode; the API server, worker, and daemon gateway cannot read disk. The path is resolved relative to the daemon’s current working directory at execution time (typically the project/worktree path). If the file doesn’t exist or can’t be read, `,_jsx(_components.code,{children:`resolveInjectAttachments`}),` logs a warning and drops that entry — `,_jsx(_components.strong,{children:`the node does not fail`}),`. Treat missing paths as a quiet no-op you have to notice in logs.`]})}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`Each evaluation of `,_jsx(_components.code,{children:`inject.attachments`}),` creates a `,_jsx(_components.strong,{children:`new attachment row per iteration`}),`. In loops, this means the same `,_jsx(_components.code,{children:`path:`}),` source is read from disk and persisted separately for every iteration, which has memory and I/O implications for large files. See `,_jsx(_components.a,{href:`#parallel-loops-and-attachments`,children:`Parallel loops and attachments`}),` below.`]})}),`\n`,_jsxs(Heading,{level:`4`,id:`data-—-raw-bytes`,children:[_jsx(_components.code,{children:`data`}),` — raw bytes`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`data`}),` is the programmatic escape hatch: raw `,_jsx(_components.code,{children:`bytes`}),` embedded in the workflow or injected by code that builds the proto directly. In hand-written YAML you’ll almost never use it, but it exists for callers that already have the content in memory.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`data`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\u003cbase64 bytes>`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` filename`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`report.pdf`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mime_type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`application/pdf`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`filename`}),` is effectively required — without it there’s no MIME hint and no sensible display name. If `,_jsx(_components.code,{children:`mime_type`}),` is omitted it’s detected from `,_jsx(_components.code,{children:`filename`}),`’s extension.`]}),`\n`,_jsx(Heading,{level:`3`,id:`forwarding-dynamic-attachments-to-a-child`,children:`Forwarding dynamic attachments to a child`}),`\n`,_jsxs(_components.p,{children:[`Because per-item `,_jsx(_components.code,{children:`InjectAttachment`}),` fields aren’t CEL-evaluated, you can’t write something like this and expect it to work:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`7`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`7`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# ❌ This does NOT interpolate. The child sees no attachments.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`thread`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mode`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`new`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` inject`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Look at these files\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.file_ids[0]}}\"`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`There are two recommended patterns for “forward whatever the user sent into a sub-agent”:`}),`\n`,_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[`Option 1: Save onto the parent thread, use `,_jsx(_components.code,{children:`mode: inherit`}),` (or `,_jsx(_components.code,{children:`fork`}),`) on the child.`]}),` The child sees the parent’s thread history, including the message that carries the attachments.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`25`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`25`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`inputs`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` message`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`message`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`attachments`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`entry`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`stash`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`nodes`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`stash`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`save_message`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` args`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.message}}\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.attachments}}\"`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`analyst`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`workflow`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ref`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`builtin://agent`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` thread`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mode`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`inherit`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # or: fork`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`edges`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`from`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`stash`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` default`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`analyst`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`This is the right answer most of the time. The attachments live on a real thread message; the child inherits (or forks) the thread and reads them the same way any other participant would.`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Option 2: Save them onto the spawning node’s hook and use a fresh child thread.`}),` If you want the child to start clean but still see the attachments, save on the parent hook and then fork:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`12`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`12`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`analyst`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`workflow`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` ref`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`builtin://agent`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` save_message`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{inputs.message}}\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{has(inputs.attachments) ? inputs.attachments : null}}\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` thread`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mode`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`fork`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` inject`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`You are the analyst. Review what's above.`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The save hook runs on the parent thread before the child is spawned, then `,_jsx(_components.code,{children:`mode: fork`}),` copies the parent’s messages (including your saved attachments) into the new child thread.`]}),`\n`,_jsxs(_components.p,{children:[`The one pattern that simply doesn’t work is per-item dynamic `,_jsx(_components.code,{children:`inject.attachments: [{ id: \"{{...}}\" }]`}),`. If you find yourself reaching for it, restructure around `,_jsx(_components.code,{children:`save_message`}),` instead.`]}),`\n`,_jsx(Heading,{level:`2`,id:`supported-file-types`,children:`Supported file types`}),`\n`,_jsxs(_components.p,{children:[`Reliant’s attachment type registry lives in `,_jsx(_components.code,{children:`internal/attachment/filetypes.go`}),` and divides files into three buckets: images (sent as image content blocks), text/file references (inlined as text), and unsupported (rejected).`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Images`}),` are binary files the provider driver renders as image content blocks on vision-capable models:`]}),`\n`,_jsx(CodeBlock,{numberOfLines:`2`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`2`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`.jpg .jpeg .png .gif .webp`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Text and file references`}),` are read and inlined as text content. The list is broad, covering:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Docs and data`}),`: `,_jsx(_components.code,{children:`.md`}),`, `,_jsx(_components.code,{children:`.markdown`}),`, `,_jsx(_components.code,{children:`.mdx`}),`, `,_jsx(_components.code,{children:`.txt`}),`, `,_jsx(_components.code,{children:`.rst`}),`, `,_jsx(_components.code,{children:`.json`}),`, `,_jsx(_components.code,{children:`.yaml`}),`, `,_jsx(_components.code,{children:`.yml`}),`, `,_jsx(_components.code,{children:`.toml`}),`, `,_jsx(_components.code,{children:`.xml`}),`, `,_jsx(_components.code,{children:`.csv`}),`, `,_jsx(_components.code,{children:`.tsv`}),`, `,_jsx(_components.code,{children:`.ini`}),`, `,_jsx(_components.code,{children:`.conf`}),`, `,_jsx(_components.code,{children:`.cfg`}),`, `,_jsx(_components.code,{children:`.env`}),`, `,_jsx(_components.code,{children:`.properties`}),`, `,_jsx(_components.code,{children:`.log`}),`, `,_jsx(_components.code,{children:`.diff`}),`, `,_jsx(_components.code,{children:`.patch`}),`, `,_jsx(_components.code,{children:`.proto`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Documents`}),`: `,_jsx(_components.code,{children:`.pdf`}),`, `,_jsx(_components.code,{children:`.docx`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Source code`}),`: `,_jsx(_components.code,{children:`.go`}),`, `,_jsx(_components.code,{children:`.py`}),`, `,_jsx(_components.code,{children:`.js`}),`, `,_jsx(_components.code,{children:`.jsx`}),`, `,_jsx(_components.code,{children:`.ts`}),`, `,_jsx(_components.code,{children:`.tsx`}),`, `,_jsx(_components.code,{children:`.rs`}),`, `,_jsx(_components.code,{children:`.java`}),`, `,_jsx(_components.code,{children:`.kt`}),`, `,_jsx(_components.code,{children:`.scala`}),`, `,_jsx(_components.code,{children:`.c`}),`, `,_jsx(_components.code,{children:`.cpp`}),`, `,_jsx(_components.code,{children:`.h`}),`, `,_jsx(_components.code,{children:`.hpp`}),`, `,_jsx(_components.code,{children:`.cs`}),`, `,_jsx(_components.code,{children:`.swift`}),`, `,_jsx(_components.code,{children:`.rb`}),`, `,_jsx(_components.code,{children:`.php`}),`, `,_jsx(_components.code,{children:`.lua`}),`, `,_jsx(_components.code,{children:`.r`}),`, `,_jsx(_components.code,{children:`.dart`}),`, `,_jsx(_components.code,{children:`.ex`}),`, `,_jsx(_components.code,{children:`.erl`}),`, `,_jsx(_components.code,{children:`.clj`}),`, `,_jsx(_components.code,{children:`.hs`}),`, `,_jsx(_components.code,{children:`.ml`}),`, `,_jsx(_components.code,{children:`.zig`}),`, `,_jsx(_components.code,{children:`.jl`}),`, and many others`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Shell and build`}),`: `,_jsx(_components.code,{children:`.sh`}),`, `,_jsx(_components.code,{children:`.bash`}),`, `,_jsx(_components.code,{children:`.zsh`}),`, `,_jsx(_components.code,{children:`.ps1`}),`, `,_jsx(_components.code,{children:`.dockerfile`}),`, `,_jsx(_components.code,{children:`.makefile`}),`, `,_jsx(_components.code,{children:`.cmake`}),`, `,_jsx(_components.code,{children:`.gradle`}),`, `,_jsx(_components.code,{children:`.tf`}),`, `,_jsx(_components.code,{children:`.hcl`}),`, `,_jsx(_components.code,{children:`.sql`}),`, `,_jsx(_components.code,{children:`.graphql`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Web`}),`: `,_jsx(_components.code,{children:`.html`}),`, `,_jsx(_components.code,{children:`.css`}),`, `,_jsx(_components.code,{children:`.scss`}),`, `,_jsx(_components.code,{children:`.vue`}),`, `,_jsx(_components.code,{children:`.svelte`}),`, `,_jsx(_components.code,{children:`.astro`})]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`There’s also a list of `,_jsx(_components.strong,{children:`special filenames`}),` that are treated as text regardless of extension: `,_jsx(_components.code,{children:`Dockerfile`}),`, `,_jsx(_components.code,{children:`Makefile`}),`, `,_jsx(_components.code,{children:`Gemfile`}),`, `,_jsx(_components.code,{children:`Rakefile`}),`, `,_jsx(_components.code,{children:`LICENSE`}),`, `,_jsx(_components.code,{children:`README`}),`, `,_jsx(_components.code,{children:`CHANGELOG`}),`, `,_jsx(_components.code,{children:`.gitignore`}),`, `,_jsx(_components.code,{children:`.editorconfig`}),`, and similar. Call `,_jsx(_components.code,{children:`attachment.SupportedExtensions()`}),` or read `,_jsx(_components.code,{children:`internal/attachment/filetypes.go`}),` for the exhaustive list.`]}),`\n`,_jsxs(_components.p,{children:[`Anything outside these lists is classified as `,_jsx(_components.code,{children:`TypeUnsupported`}),` and will be rejected at save time with an `,_jsx(_components.code,{children:`invalid attachment type`}),` error. If you need an extension added, that’s a change to `,_jsx(_components.code,{children:`filetypes.go`}),`, not to any workflow config.`]}),`\n`,_jsx(Heading,{level:`2`,id:`parallel-loops-and-attachments`,children:`Parallel loops and attachments`}),`\n`,_jsxs(_components.p,{children:[`Every loop iteration calls `,_jsx(_components.code,{children:`resolveInjectAttachments`}),` independently. That matters for the three sources in different ways:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:_jsx(_components.code,{children:`id`})}),` — cheap. The same attachment ID is reused across iterations; no new DB rows are created.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:_jsx(_components.code,{children:`path`})}),` — the file is `,_jsx(_components.strong,{children:`re-read from disk on every iteration`}),` and a fresh attachment row is persisted each time. For a parallel loop with N iterations, that’s N file reads and N new attachment rows, even if the file hasn’t changed.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:_jsx(_components.code,{children:`data`})}),` — the raw bytes are `,_jsx(_components.strong,{children:`duplicated across N child threads`}),`, one attachment row per iteration.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`None of this is a correctness issue, but it’s worth knowing before you put a large file behind `,_jsx(_components.code,{children:`path:`}),` or `,_jsx(_components.code,{children:`data:`}),` in a wide parallel loop. If a file is large or shared across iterations, persist it as a DB attachment once and reference it by `,_jsx(_components.code,{children:`id:`}),` instead.`]}),`\n`,_jsx(Heading,{level:`2`,id:`memoized-threads-and-attachments`,children:`Memoized threads and attachments`}),`\n`,_jsxs(_components.p,{children:[`Setting `,_jsx(_components.code,{children:`thread.memo: true`}),` tells the runtime to create the child thread exactly once and reuse it across loop iterations. The inject (content, attachments, everything) is applied only on the first iteration — subsequent iterations see the thread that already exists.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`10`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`10`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`- `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`evaluator`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` type`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`loop`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` thread`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` mode`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`new`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` memo`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` inject`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` role`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`user`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` content`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`You are evaluating candidates. Here are the reference files.`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` attachments`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`id`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`att_reference_spec`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`This is the right shape for “seed the agent once, then have it accumulate context as the loop runs.” It’s the wrong shape if you expected each iteration to see a different attachment — with `,_jsx(_components.code,{children:`memo: true`}),`, the attachments on iteration 2+ are whatever’s already on the memoized thread.`]}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`/features/threads#memo-behavior`,children:`Threads → Memo behavior`}),` for the full discussion of `,_jsx(_components.code,{children:`memo`}),` and `,_jsx(_components.code,{children:`inject`}),` frequency.`]}),`\n`,_jsx(Heading,{level:`2`,id:`size-and-payload-limits`,children:`Size and payload limits`}),`\n`,_jsxs(_components.p,{children:[`There is no explicit workflow-level cap on `,_jsx(_components.code,{children:`path`}),` or `,_jsx(_components.code,{children:`data`}),` injects. However, the `,_jsx(_components.code,{children:`SaveMessage`}),` activity serializes `,_jsx(_components.code,{children:`InjectFileMsg`}),` (filename, MIME type, raw bytes) as a Temporal activity payload, and Temporal’s default payload limit is `,_jsx(_components.strong,{children:`2 MiB`}),`. A large file pushed through `,_jsx(_components.code,{children:`path:`}),` or `,_jsx(_components.code,{children:`data:`}),` can silently fail that activity when the encoded payload exceeds the limit — the workflow will surface a Temporal error rather than a nice validation message.`]}),`\n`,_jsx(Tip,{children:_jsxs(_components.p,{children:[`For anything meaningfully large, upload the file once (outside the workflow) to create a DB attachment row, then reference it by `,_jsx(_components.code,{children:`id:`}),`. `,_jsx(_components.code,{children:`id`}),`-based inject passes a UUID through activities, not bytes, so the payload stays small regardless of file size.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`related`,children:`Related`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/features/threads`,children:`Threads`}),` — thread modes, inject context, and memoization`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/reference/nodes`,children:`Node types reference`}),` — `,_jsx(_components.a,{href:`/reference/nodes#save-message`,children:`Save Message`}),`, `,_jsx(_components.a,{href:`/reference/nodes#loop`,children:`Loop`}),`, `,_jsx(_components.a,{href:`/reference/nodes#agent`,children:`Agent / sub-workflow`}),`, `,_jsx(_components.a,{href:`/reference/nodes#router`,children:`Router`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/reference/types`,children:`Types reference`}),` — `,_jsx(_components.a,{href:`/reference/types#injectconfig`,children:`InjectConfig`}),`, `,_jsx(_components.a,{href:`/reference/types#savemessageconfig`,children:`SaveMessageConfig`}),`, `,_jsx(_components.a,{href:`/reference/types#threadconfig`,children:`ThreadConfig`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/reference/cel-expressions`,children:`CEL Expressions Reference`}),` — working with `,_jsx(_components.code,{children:`inputs.*`}),` and `,_jsx(_components.code,{children:`nodes.*`}),` in save_message expressions`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Attachments","description":"Pass files and images into workflows — as inputs, thread context, or saved messages","href":"/features/attachments"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"How attachments reach an LLM call","slug":"how-attachments-reach-an-llm-call","depth":2,"children":[]},{"title":"Workflow inputs: type: attachments","slug":"workflow-inputs-type-attachments","depth":2,"children":[]},{"title":"Saving attachments on a message","slug":"saving-attachments-on-a-message","depth":2,"children":[{"title":"The save_message hook","slug":"the-save_message-hook","depth":3,"children":[]},{"title":"The standalone save_message node","slug":"the-standalone-save_message-node","depth":3,"children":[]}]},{"title":"Injecting files into a child thread","slug":"injecting-files-into-a-child-thread","depth":2,"children":[{"title":"The three sources","slug":"the-three-sources","depth":3,"children":[]},{"title":"id — reference an existing attachment","slug":"id-—-reference-an-existing-attachment","depth":4,"children":[]},{"title":"path — read a file from disk at runtime","slug":"path-—-read-a-file-from-disk-at-runtime","depth":4,"children":[]},{"title":"data — raw bytes","slug":"data-—-raw-bytes","depth":4,"children":[]},{"title":"Forwarding dynamic attachments to a child","slug":"forwarding-dynamic-attachments-to-a-child","depth":3,"children":[]}]},{"title":"Supported file types","slug":"supported-file-types","depth":2,"children":[]},{"title":"Parallel loops and attachments","slug":"parallel-loops-and-attachments","depth":2,"children":[]},{"title":"Memoized threads and attachments","slug":"memoized-threads-and-attachments","depth":2,"children":[]},{"title":"Size and payload limits","slug":"size-and-payload-limits","depth":2,"children":[]},{"title":"Related","slug":"related","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"reliantlabs","siteName":"Reliant","title":"Attachments - Reliant","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-07T02:18:03.829Z","originalFileLocation":"features/attachments.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Pass files and images into workflows — as inputs, thread context, or saved messages\">\u003cmeta data-mint-head name=\"application-name\" content=\"Reliant\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Attachments - Reliant\">\u003cmeta data-mint-head property=\"og:description\" content=\"Pass files and images into workflows — as inputs, thread context, or saved messages\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Reliant\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.reliantlabs.io/features/attachments\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://reliantlabs.mintlify.app/_mintlify/api/og/v2?division=Use+Reliant\u0026amp;title=Attachments\u0026amp;description=Pass+files+and+images+into+workflows+%E2%80%94+as+inputs%2C+thread+context%2C+or+saved+messages\u0026amp;theme=2e2356f1fb9be6216c35506c\u0026amp;signature=a40fa8d77d82b2f5eea9388c75cd71cf5bac23639bc13d4ee66647c00a411909\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Attachments - Reliant\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Pass files and images into workflows — as inputs, thread context, or saved messages\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://reliantlabs.mintlify.app/_mintlify/api/og/v2?division=Use+Reliant\u0026amp;title=Attachments\u0026amp;description=Pass+files+and+images+into+workflows+%E2%80%94+as+inputs%2C+thread+context%2C+or+saved+messages\u0026amp;theme=2e2356f1fb9be6216c35506c\u0026amp;signature=a40fa8d77d82b2f5eea9388c75cd71cf5bac23639bc13d4ee66647c00a411909\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/reliantlabs/uVGZZjE6OJeONTe_/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Reliant\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#6E39FF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.reliantlabs.io/features/attachments\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/features/attachments.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.reliantlabs.io/#organization\",\"name\":\"Reliant\",\"url\":\"https://docs.reliantlabs.io\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/reliantlabs/NoVh64u5lvQ64evP/images/reliant-logo.svg?fit=max\u0026auto=format\u0026n=NoVh64u5lvQ64evP\u0026q=85\u0026s=23abaccb8c58fa15c19b8080b9ed23ca\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.reliantlabs.io#website\",\"name\":\"Reliant\",\"url\":\"https://docs.reliantlabs.io\",\"publisher\":{\"@id\":\"https://docs.reliantlabs.io/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.reliantlabs.io/features/attachments#webpage\",\"url\":\"https://docs.reliantlabs.io/features/attachments\",\"name\":\"Attachments\",\"description\":\"Pass files and images into workflows — as inputs, thread context, or saved messages\",\"dateModified\":\"2026-10-07T02:18:03.829Z\",\"isPartOf\":{\"@id\":\"https://docs.reliantlabs.io#website\"},\"breadcrumb\":{\"@id\":\"https://docs.reliantlabs.io/features/attachments#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.reliantlabs.io/features/attachments#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Use Reliant\",\"item\":\"https://docs.reliantlabs.io/workflows/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Attachments\",\"item\":\"https://docs.reliantlabs.io/features/attachments\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.reliantlabs.io/features/attachments#article\",\"headline\":\"Attachments\",\"name\":\"Attachments\",\"description\":\"Pass files and images into workflows — as inputs, thread context, or saved messages\",\"url\":\"https://docs.reliantlabs.io/features/attachments\",\"mainEntityOfPage\":{\"@id\":\"https://docs.reliantlabs.io/features/attachments#webpage\"},\"dateModified\":\"2026-10-07T02:18:03.829Z\",\"publisher\":{\"@id\":\"https://docs.reliantlabs.io/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.reliantlabs.io#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Reliant\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Reliant","nav":{"global":{"anchors":[{"anchor":"Main Site","icon":"globe","href":"https://reliantlabs.io"},{"anchor":"GitHub","icon":"github","href":"https://github.com/reliant-labs/reliant"},{"anchor":"Slack","icon":"slack","href":"https://join.slack.com/t/reliant-pn51441/shared_invite/zt-4c7wet6o2-W_Tksw80LaRGxZqUz9GQdA"}]},"tabs":[{"tab":"Docs","groups":[{"group":"Get started","pages":[{"title":"Quick Start","href":"/getting-started/quick-start"},{"title":"Installation","href":"/getting-started/installation"},{"title":"Key Concepts","href":"/getting-started/concepts"}]},{"group":"Use Reliant","pages":[{"title":"Workflows Overview","href":"/workflows/overview"},{"title":"Workflow Control","href":"/workflows/workflow-control"},{"title":"Branching","href":"/features/branching"},{"title":"Worktrees \u0026 Workspaces","href":"/features/worktrees"},{"title":"Git Integration","href":"/features/git-integration"},{"title":"Threads","href":"/features/threads"},{"title":"Spawn Tool","description":"Delegate tasks to sub-workflows from within an agent","href":"/workflows/spawn"},{"title":"Attachments","href":"/features/attachments"},{"title":"Run project commands","description":"Run commands discovered from package.json, Makefile, and Taskfile from the Processes tab","href":"/features/processes"}]},{"group":"Built-in workflows","pages":[{"title":"Built-in workflows","href":"/guides/overview"},{"title":"Get It Right","href":"/guides/get-it-right"},{"title":"Best of Three","href":"/guides/best-of-three"},{"title":"Autopilot","href":"/guides/autopilot"},{"title":"Create a Workflow","href":"/guides/create-a-workflow"},{"title":"Import from Claude Code / Cursor","href":"/guides/import"}]},{"group":"Machines","pages":[{"title":"Machines","href":"/machines/overview"},{"title":"Your own computer","href":"/machines/your-computer"},{"title":"Cloud machines \u0026 plans","href":"/machines/cloud"},{"title":"Choosing a machine in workflows","href":"/machines/choosing"}]},{"group":"Command line","pages":[{"title":"The reliant command line","href":"/cli/overview"},{"title":"Sign in and tokens","href":"/cli/sign-in"},{"title":"Run a machine from the terminal","href":"/cli/run-a-machine"},{"title":"Workflows from the terminal","href":"/cli/workflows"},{"title":"Forge through Reliant","href":"/cli/forge"},{"title":"Preview a running app","href":"/cli/previews"},{"title":"Scripting and CI","href":"/cli/scripting"}]},{"group":"Automations \u0026 integrations","pages":[{"title":"Automations","href":"/automations/overview"},{"title":"Schedules","href":"/automations/schedules"},{"title":"Webhooks","href":"/automations/webhooks"},{"title":"Workflow events","href":"/automations/workflow-events"},{"title":"No-machine runs","href":"/automations/no-machine-runs"},{"group":"Integrations","pages":[{"title":"Integrations","href":"/integrations/overview"},{"title":"GitHub","href":"/integrations/github"},{"title":"Gmail","href":"/integrations/gmail"},{"title":"Slack","href":"/integrations/slack"},{"title":"HTTP","href":"/integrations/http"},{"title":"Twilio (SMS and WhatsApp)","href":"/integrations/twilio"}]}]},{"group":"Build workflows","pages":[{"title":"Creating Custom Workflows","href":"/workflows/custom-workflows"},{"title":"Presets","href":"/workflows/presets"},{"title":"Multi-Agent Patterns","href":"/workflows/patterns"},{"title":"Router Nodes","href":"/workflows/routing"},{"title":"Testing Workflows","href":"/workflows/testing"},{"title":"Workflow Examples","href":"/examples/workflow-snippets"},{"title":"Improve Reliant itself","href":"/guides/self-improvement"}]},{"group":"Customize","pages":[{"title":"AI Providers","href":"/settings/api-keys"},{"title":"Model Configuration","href":"/settings/model-config"},{"title":"Memories \u0026 Context","href":"/settings/memories"},{"title":"Skills","href":"/features/skills"},{"title":"MCP Servers","href":"/settings/mcp-servers"}]},{"group":"Build \u0026 host with Forge","pages":[{"title":"Forge quick start","href":"/forge/overview"},{"title":"Project anatomy","href":"/forge/project-anatomy"},{"title":"Adding a feature","href":"/forge/adding-features"},{"title":"Environments \u0026 deploys","href":"/forge/environments-and-deploys"},{"title":"Hosting on Reliant","href":"/forge/hosting"},{"title":"Secrets","href":"/forge/secrets"},{"title":"Custom domains","href":"/forge/custom-domains"},{"title":"Forge sign-in","href":"/forge/sign-in"},{"title":"Observability","href":"/forge/observability"},{"title":"Troubleshooting","href":"/forge/troubleshooting"}]},{"group":"Account \u0026 billing","pages":[{"title":"Billing, wallet \u0026 Reliant AI","href":"/account/billing"},{"title":"Privacy \u0026 Security: what leaves your machine","href":"/help/privacy"}]},{"group":"Reference","pages":[{"title":"Node Types Reference","href":"/reference/nodes"},{"title":"Types Reference","href":"/reference/types"},{"title":"Workflow Schema Reference","href":"/reference/workflow-schema"},{"title":"CEL Expressions Reference","href":"/reference/cel-expressions"},{"title":"Models Reference","href":"/reference/models"},{"title":"Tools Quick Reference","href":"/reference/tools"},{"title":"Scenario Schema","href":"/reference/scenario-schema"},{"title":"LLM Integration Guide","href":"/reference/llm-guide"},{"title":"CLI Reference","href":"/reference/cli"}]},{"group":"Help","pages":[{"title":"FAQ","href":"/help/faq"},{"title":"Troubleshooting","href":"/help/troubleshooting"},{"title":"Feedback \u0026 Support","href":"/help/feedback"},{"title":"Architecture Overview","href":"/architecture/overview"},{"title":"Server Components","href":"/architecture/distributed"},{"title":"Changelog","href":"/changelog"},{"title":"License FAQ","href":"/license-faq"}]}]}]},"title":"Attachments - Reliant","buildId":"dpl_HcHmUS6i3UwswnTHJUEdcTtwfdTQ","deploymentId":"dpl_HcHmUS6i3UwswnTHJUEdcTtwfdTQ","dynamics":[],"chunks":[]}