跳到主要内容

附件:图片与文件 (Attachments)

给 Agent 发图片或文件分两步:先把字节上传拿到一个稳定的 URL,再把这个 URL 作为消息的一个「部件 (part)」随消息发出去。 SDK 把这两步合成了一个调用,浏览器端的聊天组件更是连调用都省了——选择、粘贴、拖拽都开箱即用。

Agent 回复里带的图片(图表、处理过的照片)同样能取出来,见下文读取 Agent 发回的图片

需要 @openhex-ai/agent-sdk 0.4.0 及以上。

上传并发送

client.files.uploadPart 上传字节并直接返回一个可发送的部件:图片类型返回 image_url 部件,其余返回 file 部件(按 MIME / 扩展名判断)。

import { readFile } from 'node:fs/promises';

const parts = [
await client.files.uploadPart(
{ data: await readFile('chart.png'), filename: 'chart.png' },
{ agentId }
),
await client.files.uploadPart(
{ data: await readFile('report.pdf'), filename: 'report.pdf' },
{ agentId }
),
];

// 文本和附件一起发出去
const turn = await client.sendMessage('这两份材料里有什么值得注意的?', { parts });

agentId 的作用:服务端在存下文件的同时,会把它放进该 Agent 的 NAS 工作区,这样 Agent 里那些需要真实文件路径的工具(脚本、数据处理等)才能读到它。只是想让 Agent「看一眼」图片的话,不传也可以。

在浏览器里直接把 File / Blob 交给 uploadPart 即可,不用另外给文件名:

const part = await client.files.uploadPart(fileFromInput, { agentId });

强制部件类型

类型判断走 MIME 与扩展名。想覆盖它(例如让一张图以文件形式发送,让 Agent 当附件处理而不是「看图」),用 as

await client.files.uploadPart(blob, { agentId, as: 'file' });

已经有 URL 了

文件如果已经传到别处并且是公开可访问的,跳过上传,自己拼部件就行:

const parts = [
{ type: 'image_url', image_url: { url: 'https://…/chart.png' } },
{ type: 'file', file: { filename: 'report.pdf', file_url: 'https://…/report.pdf' } },
];

只要 URL,不要部件

client.files.upload 是更低一层的调用,返回上传结果本身(urlfilenamesizemimeType 等),适合你想自己保存 URL 或复用到多条消息的场景:

const uploaded = await client.files.upload(
{ data: bytes, filename: 'chart.png' },
{ agentId }
);
uploaded.url; // 稳定 URL,可反复引用

读取 Agent 发回的图片

Agent 生成的图片以图片内容块的形式回到流里。extractImages 从记录中把 URL 取出来:

import { extractImages } from '@openhex-ai/agent-sdk';

for await (const record of client.runTurn('把这份数据画成柱状图', { parts })) {
for (const url of extractImages(record)) {
console.log('agent image:', url);
}
}

它和 extractText / extractToolCalls 是一组辅助函数,用法一致:传入一条记录,拿到你关心的那部分。

在 React 组件里

内置聊天组件默认就支持附件——选择按钮粘贴(⌘/Ctrl+V 贴图)、拖拽三种方式都能用,上传由组件代劳,发送前还会显示预览条。消息携带的附件(用户自己发的,以及 Agent 回复的图片)会直接渲染在气泡里:图片显示为缩略图,文件显示为可下载的卡片。

// 默认全开,什么都不用写
<ChatBox agentId="" token={token} />

// 只允许图片
<ChatBox agentId="" token={token} acceptFileTypes="image/*" />

// 完全关掉附件
<ChatBox agentId="" token={token} allowAttachments={false} />

acceptFileTypes 的取值就是 HTML 文件选择框的 accept,例如 "image/*"".pdf,.docx"

用无头 Hook 时,send 的第二个参数接收原始 files(组件替你上传)或已经拼好的 parts

const { send } = useOpenhexChat({ agentId: '…', token });

await send('帮我看看这个', { files: [myFile] }); // 交给 SDK 上传
await send('帮我看看这个', { parts }); // 自己上传好的部件

组件的完整用法见示例:3 分钟做一个客服组件

下一步