@astropods/适应器核心
TypeScript代理和Astropods通讯服务之间的框架-不可知桥.
安装
bun add @astropods/adapter-core
# or
npm install @astropods/adapter-core
使用量
如果您使用一个被支持的框架,则使用预建的适配器包取而代之(例如. @astropods/adapter-mastra) (中文(简体) ). 直接使用此软件包连接自定义或不支持的框架.
执行 AgentAdapter 接口,然后调用 serve()数字 :
import { serve } from "@astropods/adapter-core";
import type { AgentAdapter } from "@astropods/adapter-core";
const adapter: AgentAdapter = {
name: "My Agent",
async stream(prompt, hooks, options) {
try {
hooks.onChunk("Hello!");
hooks.onFinish();
} catch (err) {
hooks.onError(err as Error);
}
},
getConfig() {
return { systemPrompt: "You are a helpful assistant.", tools: [] };
},
};
serve(adapter);
serve() 块到 SIGINT 或者说 SIGTERM下调 ast dev, (中文(简体) ), GRPC_SERVER_ADDR 自动注入.
API 密码
AgentAdapter
| 成员 | 说明 |
|---|---|
name: string | 显示日志和注册中使用的名称 |
stream(prompt, hooks, options): Promise<void> | 流出一个响应, 使用钩子进行代理 |
streamAudio?(audio, hooks, options): Promise<void> | 可选的——处理语音输入 |
getConfig(): AgentConfig | 返回时 { systemPrompt, tools } 用于操场展示 |
onFeedback?(event): void | Promise<void> | 可选 – 接收入站平台反馈(thumbs上下行,评论,按钮点击) |
StreamHooks
把这些叫进去 stream() 由于代理输出 :
| 方法 | 何时打电话 |
|---|---|
onChunk(text) | 来自 LLM 的每个文本符号或片段 |
onStatusUpdate({ status }) | 代理状态更改 - 有效值 : THINKING, (中文(简体) ), SEARCHING, (中文(简体) ), GENERATING, (中文(简体) ), PROCESSING, (中文(简体) ), ANALYZING, (中文(简体) ), CUSTOM |
onFinish() | 答复完成——每个请求打一次电话 |
onError(error) | 发生错误——呼叫而不是 onFinish |
onTraceContext({ traceparent }) | 可选——每转一次,提供助手转弯的W3C跟踪上下文. 桥面上贴满了它为转弯而发出的所有响应,因此消费者可以将任何响应与它的追踪联系起来。 如果 traceparent 为空. |
onFile({ name, mimeType?, size? }) | 代理人写给文件目录的文件,随答复一起送交。 工具代码调用 attachFile 换句话说. |
attachFile(input)
将文件写入代理文件目录( T)AGENT_FILES_DIR并附上答复。 网络聊天显示为下载芯片,Slack将其上传到线程中. 在任何框架适配器中,代理处理消息时从工具中调用它 。 投出一门外.
import { attachFile } from "@astropods/adapter-core";
await attachFile({ name: "account-plan.csv", data: csv, mimeType: "text/csv" });
name 是一个路径段。 奥米 data 以附加文件目录中已经包含的文件。 它返回文件的名称 。 每个用户的文件都共享目录,所以 data 名称已经得到一个数字 : summary.md 变成 summary-2.md中返回文件 attachFile 而不是写进 AGENT_FILES_DIR 直接,因为直接写入可以取代另一个线程的文件. 超过部署文件大小限制的文件( N)FILES_MAX_MB,100米B当未设定, 0 因此,在答复之前,代理人知道情况.
@astropods/adapter-core/files
用于读取用户附加的文件的框架中立函数 。 他们拿走了 path 从 StreamOptions.attachments。每个线索和用户文件共享 AGENT_FILES_DIR,因此,函数只打开当前作为附件收到或与 attachFile他们向外抛出一圈 桥会保存该列表,每次谈话最多100个文件, in AGENT_FILES_DIR/.conversations,所以会持续到重启。 在同一路径上删除并替换的文件不在列表中 。 Mastra 和 AI SDK 适配器将它们包装为工具 fileTools()。 。 。 .
| 函数 | 回返 |
|---|---|
inspectFile(path) | 文件的类型( E)pdf, (中文(简体) ), docx, (中文(简体) ), xlsx, (中文(简体) ), zip, (中文(简体) ), text, (中文(简体) ), binary),其大小,文本长度,对于一个表格,每个工作表的列和精确行数。 该类型从字节中被嗅出,因为舞台上上传没有扩展. 一个没有文本层的PDF, 如扫描, 有 scanned: true。 。 。 . |
readFilePage(path, offset?) | 一个 PAGE_CHARS (20,000-字符) PDF、DOCX 或文本文件的页面,带有 nextOffset (倒在最后一页)和 totalChars。它为没有文本层的PDF扔出,这需要OCR. |
readTable(path, { sheet?, offset?, limit? }) | CSV 或 XLSX 表的一页:页眉为 columns,则 limit 数据行PAGE_ROWS, 100, 默认情况下) offset,与 nextOffset (倒在最后一页). CSV细胞是字符串,而XLSX细胞保持其类型. CSV被流出,因此一个大文件后期的一页不会加载整个文件. |
createFile(name, content, mimeType?) | 以 attachFile 返回时 { attached, path }:用户看到的名称和以后打开的已读函数的路径. |
attachmentNote(attachments, images?) | 适配器的行附加在转弯的文字上,该文字将每个附加的文件及其路径命名. |
PDF, DOCX, XLSX, 和 CSV 解析器在首次使用时加载, 所以一个从未调用这些函数的代理不会加载它们.
分析表格
这些函数传递一个文件的内容而不进行分析. 要计数、 总数、 组合、 或加入大表格上的行, 给代理服务器一个工具, 运行附件上的查询引擎 path,例如 DuckDB (read_csv_auto(path))或密码解释器中的熊猫. 通过路径 resolveAgentFile,它拒绝对话没有收到或创建的任何文件。 如果模型写出查询,限制引擎能读到的内容,因为DuckDB和熊猫可以打开机器上的任何路径.
createTraceparent(input)
将原生的痕量/ span ID对格式化为 W3C traceparent 手给的字符串 onTraceContext. 回归 "" 对于无效的或全零的ID,所以可以安全地通过原始的OpenTeleometry上下文. traceFlags 接受数字或十六进制字符串和默认值 01 (样本).
import { createTraceparent } from "@astropods/adapter-core";
const { traceId, spanId, traceFlags } = span.spanContext();
hooks.onTraceContext?.({ traceparent: createTraceparent({ traceId, spanId, traceFlags }) });
StreamOptions
按请求转至 stream()数字 :
| 外地 | 说明 |
|---|---|
conversationId | 对话线索的稳定 ID |
userId | 发送消息的用户身份 |
userName? | string | undefined:发件人在源平台上的名字,如他们在Slack的全名. undefined 当平台没有发送. |
platformContext? | PlatformContext | undefined ——平台专用字段(频道,线程,工作空间,事件类型). undefined 用于非平台来源(游戏场、直接GRPC)的信息. |
history? | HistoryInput | undefined:此消息之前的转折, 仅在与代理上次回答的内容不同时设定 。 见 已编辑信件。 。 。 . |
已编辑信件
在网络聊天中,用户可以编辑他们发送的信息,也可以切换到另一个对话版本. 下一个信息随即携带 history:在用户的版本上它之前的转弯,最古老的第一. 也经过转弯 代理没有完成回答。 转弯仅为文本;只带文件的用户转弯读取为取名的行. 替换您存储的 conversationId 与 history.messages,然后处理提示。 一个空的 messages 这意味着没有更早的转弯. isComplete 实值 false 当更古老的转折被抛出 以束缚大小.
宣布你这样做与 supportsHistory: true 内 getConfig()。聊天只为设置它的代理编辑。 被包装的适配器设置了它,并为您重新设置了框架的内存.
getConfig() {
return { systemPrompt: "", tools: [], supportsHistory: true };
}
使用 platformContext
PlatformContext 曝光源活动字段适配器经常需要分行——频道和线程回放,工作空间,机器人自己的用户ID,以及一个 eventKind 用于区分一个DM和一个@-mention和线程回复而无需检查消息内容的enum.
import type { AgentAdapter, PlatformContext } from "@astropods/adapter-core";
const adapter: AgentAdapter = {
name: "My Agent",
async stream(prompt, hooks, { platformContext }) {
if (platformContext?.eventKind === "EVENT_KIND_APP_MENTION") {
hooks.onChunk(`You @-mentioned me in ${platformContext.channelName ?? platformContext.channelId}.`);
} else {
hooks.onChunk("Hello!");
}
hooks.onFinish();
},
getConfig() {
return { systemPrompt: "", tools: [] };
},
};
总是先取消检查—— platformContext 实值 undefined 从游乐场或直接的gRPC客户端获取消息。 见 PlatformContext 用于完整字段列表.
serve(adapter, options?)
连接适配器到消息服务并屏蔽到关闭.
import { serve } from "@astropods/adapter-core";
// Override the gRPC address (default: GRPC_SERVER_ADDR env var or localhost:9090)
serve(adapter, { serverAddress: "astro-messaging:9090" });
MessagingBridge
serve() 是薄薄的包装 MessagingBridge。如果需要生命周期控制,则直接使用:
import { MessagingBridge } from "@astropods/adapter-core";
const bridge = new MessagingBridge(adapter);
await bridge.start();
HTTP 出界仪器
@astropods/adapter-core/instrument 补丁 globalThis.fetch 因此,每个出站的HTTP请求都成为了OpenTeleometter CLIENT的跨度. Spans被发送到 ${OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces。当 env var 未被设定时, 输入是不可操作的 .
导入 一次,在发布代码之前 - 通常您切入点的第一行:
import "@astropods/adapter-core/instrument";
// ...the rest of your imports
或明称:
import { instrumentHttp } from "@astropods/adapter-core";
instrumentHttp();
这两种形式都具有同位素,并与其他Astropods适配器在同一过程中共享一个追踪提供者.
连接
一个连接是聊天用户GitHub等第三方账户
让代理使用他们。 经纪人声明 connections 内
astropods.yml,用户在聊天时允许它,代理器每
转.
import { ConnectionClient, ConnectionError } from "@astropods/adapter-core/connections";
const connections = new ConnectionClient();
const { accessToken } = await connections.getToken("github", options.userId);
new ConnectionClient() 读取 ASTRO_AUTHZ_TOKEN 环境状况
从该符号取取服务器 URL。 转弯 userId: 服务器
只返回允许此代理并已在其中发送信息的用户的符号
过去15分钟的网络聊天.
过期的标志在过期前一分钟重新使用。 一个标志 每一次调试,都不得再取回任何物品.
拒绝掷出 ConnectionError 带有 code数字 :
code | 告诉用户 |
|---|---|
not_consented | 允许聊天中的连接 |
not_active | 在网络聊天中发送消息 |
not_connected | 用个人账户连接提供者 |
needs_reauthorization | 重新连接提供者 |
unavailable | 以后再试 |
沙盒
沙盒是一种孤立的机器 代理机用来运行命令和持有 用于一个对话的文件。 谈话安静下来会睡着 计算用的账单.
import { SandboxClient } from "@astropods/adapter-core/sandbox";
const sandboxes = new SandboxClient();
const result = await sandboxes.exec(conversationId, {
command: ["/bin/sh", "-c", "npm test"],
});
console.log(result.exitCode, result.stdout);
new SandboxClient() 读取 ASTRO_AUTHZ_TOKEN 从环境并带走
服务器的 URL , 因此不需要配置 .
打电话 exec 在每一个转弯。 它首先呼吁命名和再利用
后面的沙盒,服务器将两个同时先拨到一个
沙盒而不是两个。 按对话或线索 ID 键: 两个对话
共享一个沙盒 共享文件 .
| 方法 | 对 |
|---|---|
exec(name, request) | 需要附件,然后运行命令 |
attach(name, class?) | 返回不运行任何东西的控点 |
get(name) 编号 : list() | 记录,无全权证书 |
stop(name) | 早点停止计算 可选; 闲置的沙盒独自入睡 |
delete(name) | 丢弃沙盒及其文件 |
非零退出代码和超时命令都是结果,不是抛出
错误: 检查 exitCode 财务报告和审定财务报表 timedOut。丢出错误意味着请求本身
失败 . SandboxNotEnabledError 表示账户没有变成沙盒
在账户或组织设置中.
终点和两个证书 一个沙盒需要不是这个的一部分 表面。 客户端刷新它们, 当沙盒有一次重新附着 被替换了,所以一个特工也从不处理.
限制
输出为缓冲,直到命令退出,并封顶为每流1米B,以及
没有办法流出它, 投票一个背景过程或信号一个。 A 类
沙盒最多活8小时;之后是 exec 得到一个新鲜的与
一个空的工作空间。 文件无法幸存.