Functions
decoded-text
fn (att: Attachment, max-bytes: Int): Str?
Return decoded text for an attachment, or null when nothing is
extractable. Caps decoded length at max-bytes to bound prompt
cost.
escape-attr
fn (value: Str?): Str
Internal: escape a value for use in pseudo-XML attachment attributes.
extract-text
fn (att: Attachment): Str?
fn (att: Attachment, max-bytes: Int): Str?
Return decoded text for a single attachment. Convenience wrapper
over decoded-text using DEFAULT_MAX_BYTES_PER_FILE.
from-body
fn (body: Any): Vec
Coerce a webhook body's attachments field (or the body itself,
when it's already a list) into a Vec<Attachment>. Drops
malformed entries silently so a single bad attachment never sinks
a request.
from-map
fn (raw: Any): Attachment?
Coerce one raw map into an Attachment. Accepts both kebab-case
(content-text) and snake_case (content_text) keys, mirroring
the JSON conventions Hot Chat and most webhooks use. Returns
null when the input is not a map.
get-text-content
fn (raw: Map): Str?
Internal: dig out an explicit text payload from raw, supporting kebab- and snake-case.
is-text-type
fn (mime: Str?): Bool
Return true when mime is in text-extractable-types. Case-insensitive, ignores any ;charset=… suffix.
ns
Alias of ::ai::agent::attachments/
Normalized attachment shape and helpers for chat-style agents.
Today, transports surface attachments as ad-hoc maps: Telegram
sends a file_id, Slack sends a file object, Hot Chat sends a
base64 content blob in the webhook body. This module gives
agents a single shape and a small toolkit:
Attachment—{name, type, size, content-base64?, content-text?, content-url?, meta?}. At least one of the three content fields should be set.from-body— coerce a rawbody.attachmentsarray intoVec<Attachment>, dropping malformed entries.extract-text— return UTF-8 text for any attachment whosecontent-textis set or whose mime is intext-extractable-types. Decodes base64 only when the type is known to be text. Truncates atmax-bytesto bound prompt size.summarize— Markdown bullet list, one line per attachment, for memory storage and quick prompt context.weave-into-prompt— prepend extracted text from each attachment onto a user message, tagged so the model can see file boundaries and names.
The goal is parity across Slack, Telegram, and the Hot Chat web client without leaking transport details into agent code.
summarize
fn (atts: Vec): Str
Markdown bullet list, one entry per attachment, suitable for memory storage and lightweight prompt context. Returns the empty string when there are no attachments.
truncate-text
fn (text: Str, max-bytes: Int): Str
Internal: hard-truncate text to max-bytes characters. Appends an ellipsis marker when the cap was hit.
weave-folder
fn (total-cap: Int): Fn
Internal: builds the reducer used by weave-into-prompt to honor a total byte cap.
weave-into-prompt
fn (prompt: Str, atts: Vec): Str
fn (prompt: Str, atts: Vec, total-cap: Int): Str
Combine a base prompt with extracted text from each attachment.
Returns a single string the agent can pass as Message.content.
Each attachment that yields text becomes a tagged block:
<attachment name="notes.md" type="text/markdown">
# Project notes
...
</attachment>
Attachments without extractable text are listed but not inlined, so the model can ask for them by name or address them via tool calls.
total-cap bounds the combined byte budget across all
attachments; once exhausted, remaining attachments are listed
by name only.
Types
Attachment
Attachment type {
name: Str,
type: Str,
size: Int,
content-text: Str?,
content-base64: Str?,
content-url: Str?,
meta: Map?
}
Normalized attachment record. Transports populate at least one of
content-text, content-base64, or content-url.
name— display filename. Falls back to"file"when missing.type— best-effort mime type. Falls back to"application/octet-stream".size— byte count when reported by the transport, else0.content-text— UTF-8 text payload (already decoded).content-base64— raw bytes, base64-encoded. Used by Hot Chat, Telegram fetched files, Slack file downloads.content-url— addressable URL. Used when a transport delivers a link (Slackpermalink_public, S3 pre-signed URL, etc.).meta— open map for transport-specific fields the agent might want to read (Slackfile_id, Telegramfile_unique_id, etc.).