跳到主要内容

附件:图片与文件 (Attachments)

给 Agent 发图片或文件分两步:先上传字节拿到一个稳定的 URL,再把 URL 作为消息的「部件 (part)」随消息发出。反过来,Agent 生成的图片会带着 URL 回到流里,它产出的文档则带着一个工作区路径,需要通过接口取回。 SDK 把这几步都封装好了;浏览器里的聊天组件连调用都不用写。

上传并发送​

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 });
  • 消息文本放 message,附件放 parts。 不要自己把附件链接拼进文本,服务端会生成规范的附件说明,自己拼会出现两份。
  • 传 agentId(或 chatGroupId):服务端在保存文件的同时,把它放进 Agent 的工作区,Agent 里需要真实文件路径的工具(脚本、数据处理、读文档)才读得到。只是让 Agent「看一眼」图片可以不传。

在浏览器里直接把 File / Blob 交给 uploadPart,File 自带文件名:

const part = await client.files.uploadPart(fileInput.files[0], { agentId });

上传选项​

选项说明
agentId把文件放进该 Agent 的工作区
chatGroupId把文件放进该对话的工作区
filename存储用的文件名。裸 Blob 必填;传入时覆盖 File 自带的名字
contentTypeMIME 类型。默认取 Blob.type,其次按扩展名推断,最后是 application/octet-stream
as仅 uploadPart:强制部件类型,'image' 或 'file'
signal取消上传

例如让一张图片以文件形式发送,让 Agent 当附件处理而不是「看图」:

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

只要 URL​

client.files.upload 只上传,返回上传结果,适合保存 URL 复用到多条消息:

const uploaded = await client.files.upload({ data: bytes, filename: 'chart.png' }, { agentId });
// → { url, filename, size, mimeType, provider, nasPath?, agentPath? }

const part = client.files.toPart(uploaded); // 之后随时转成部件

已经有公开 URL​

文件已经在别处且可以公开访问,就跳过上传,自己拼部件:

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

读取 Agent 生成的图片​

Agent 生成的图片带着 URL 回到流里,用 extractImages 取出:

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

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

读取 Agent 产出的文件​

Agent 写完一份报告、一个页面或一份表格时,会把它作为一条单独的记录发出来。这条记录携带的是文件在对话工作区里的路径,而不是 URL——文件需要通过带鉴权的接口读取,裸链接访问不到。

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

const convo = client.conversation();

for await (const record of convo.stream('把设计方案写成一份 markdown 文档')) {
const file = extractFileAttachment(record);
if (!file) continue;

console.log(file.name, file.workspacePath); // report.md /outputs/report.md

// 文本文件:直接读内容
const { content, encoding, mimeType } = await client.files.readConversationFile(
convo.id!,
file.workspacePath
);
const text = encoding === 'base64' ? Buffer.from(content, 'base64').toString('utf8') : content;

// 任意文件:拿到 Blob,适合下载或预览
const blob = await client.files.downloadConversationFile(convo.id!, file.workspacePath);
}
方法返回适合
readConversationFile(conversationId, path){ content, encoding, mimeType },二进制文件为 base64文本、小文件
downloadConversationFile(conversationId, path)Blob大文件、二进制文件、给用户下载

路径不存在时返回 404 File not found。

在 React 组件里​

内置聊天组件默认支持附件:选择按钮、粘贴(⌘/Ctrl+V 贴图)、拖拽都能用,组件替你上传,并在发送前显示预览。消息里的附件直接渲染在气泡里:图片显示缩略图,文件显示为可下载的卡片——包括 Agent 产出的文件,点击时组件会通过鉴权接口取回内容。

<ChatBox agentId="…" getToken={getToken} /> {/* 默认全开 */}
<ChatBox agentId="…" getToken={getToken} acceptFileTypes="image/*" /> {/* 只允许选图片 */}
<ChatBox agentId="…" getToken={getToken} allowAttachments={false} /> {/* 关闭附件 */}

acceptFileTypes 就是文件选择框的 accept 属性(如 ".pdf,.docx"),只限制选择按钮,不限制粘贴和拖拽。

用无头 Hook 时,send 的第二个参数接受原始 files(替你上传)或已经拼好的 parts,downloadAttachment 取回 Agent 产出的文件:

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

await send('帮我看看这个', { files: [myFile] });
const blob = await downloadAttachment(message.attachments![0]);

下一步​