跳到内容
BeeuniBeeuni
中文
Esc
↑↓导航↵打开⌘J预览
本页内容

SDK 参考

完整的 @beeuni/sdk API — 客户端方法、模块、轮次和分发。

此页面介绍完整的 @beeuni/sdk API 表面:每个客户端方法、无框架模块、回合辅助工具,以及软件包的发布方式。使用 SDK 开始,并参阅 Sessions 深入了解会话生命周期。

客户端

createBeeuni(config) 返回一个客户端。每个方法都是对平台 API 的类型化调用。project(id) 和 session(pid, sid) 句柄会绑定 ID,因此无需重复传入。

const beeuni = createBeeuni({ backendUrl, getToken });

beeuni.accounts; // account / team operations
beeuni.accountInvites; // invite accept/decline by token alone
beeuni.projects; // top-level project operations
beeuni.connectors; // Connector calls scoped by an agent-minted token
beeuni.connector(slug); // one connector in the token's scope → see p.connector(slug)
beeuni.project(id); // id-bound project handle
beeuni.session(pid, sid); // id-bound session handle → see Sessions
beeuni.github; // GitHub App install + repo linking (account-scoped)
beeuni.gitBackend; // the instance git backend ("Beeuni managed")
beeuni.billing; // credits, subscription, tier, transactions
beeuni.sandboxShares; // public share links for a sandbox port
beeuni.connectStatus; // easy-connect status
beeuni.marketplace; // public marketplace catalog
beeuni.validateToken; // pasted-API-key check
beeuni.config; // platform config in effect
beeuni.runtime(); // 运行环境 REST compatibility client

账户 — beeuni.accounts

方法 说明
list() · get(accountId) 所属账户 · 单个账户
create({ name }) · updateName(accountId, name) 创建 · 重命名账户
branding.get(accountId) · branding.update(accountId, { app_name }) · branding.uploadAsset(accountId, kind, file) · branding.removeAsset(accountId, kind) · branding.reset(accountId) 组织品牌设置(Enterprise):自定义徽标、图标、favicon 和产品名称;kind 为 logo · icon · favicon,或深色方案变体的 logo_dark · icon_dark · favicon_dark
members(accountId) · invite(accountId, input) 列出成员 · 邀请成员
updateMemberRole(accountId, userId, role) · removeMember(accountId, userId) 分配账户角色 · 移除成员
invites(accountId) 待处理邀请
cancelInvite(accountId, inviteId) · resendInvite(accountId, inviteId) 取消 · 重新发送待处理邀请
leave(accountId) 离开账户

accounts.tokens 会签发账户范围的 API 密钥(beeuni_pat_...)。完整令牌模型请参阅 SDK 身份验证。

方法 说明
tokens.list(accountId?, options?) 列出 API 密钥——整个账户的密钥,或使用 { mine: true } 仅列出你自己的密钥
tokens.create(input) 签发一个密钥——{ accountId?, name, expiresAt?, projectId? }
tokens.revoke(tokenId, accountId?) 撤销一个密钥

accounts.audit 是企业重建日志。它将经过身份验证的 API 请求与语义会话、连接器、审批和计算机事件结合起来。

方法 说明
audit.log(accountId, filters?) 按项目、会话、执行者、来源、结果、请求、关联、资源、操作或时间列出事件
audit.export(accountId, filters?) 将相同的筛选事件流导出为 CSV 或 JSONL
audit.webhooks.list/create/update/remove(...) 管理用于集中式事件流的已签名 SIEM webhook

每个事件都包含 project_id、session_id、actor_type、source、outcome、request_id、trace_id 和 correlation_id(如果操作提供了这些信息)。API 不会在集中式事件中存储请求正文、提示词、机密、凭据或原始连接器参数。连接器事件可以包含有界的参数预览,其中会对凭据形式的字段和不透明数据进行编辑。

访问分配

Beeuni 只有一种授权记录:分配。它将一个主体(user、group、service_account 或 pending)绑定到一个角色和一个范围(account 或一个 project),也可以进一步限定到一个对象(agent、skill、secret、app 或 trigger),并可选择携带一个 expires_at。群组访问、按资源访问和自定义角色绑定都属于分配。模型详见 账户与访问。

规范的 REST 表面如下:

方法 + 路径 功能
GET /v1/accounts/{accountId}/iam/assignments 列出分配,可按主体、范围、对象或角色筛选
POST /v1/accounts/{accountId}/iam/assignments 创建一个分配
DELETE /v1/accounts/{accountId}/iam/assignments/{assignmentId} 撤销一个分配
GET /v1/accounts/{accountId}/iam/permissions 以数据形式提供权限目录
GET /v1/accounts/{accountId}/iam/roles · …/roles/{roleId}/permissions 角色 · 单个角色的权限

SDK 将它们公开为 listAssignments、createAssignment、revokeAssignment 和 listPermissions。目录行包含 action、scope_type、resource_type、delegable、description、area、level 和 implies——请读取这些字段,而不是硬编码操作字符串。

分配自定义角色需要账户的 rbac 权限;没有该权限时,路由会返回带有 code: "entitlement_required" 的 402。

账户邀请 — beeuni.accountInvites

仅凭邀请令牌即可访问——受邀者可能尚未成为成员。

方法 说明
listMine() 列出发送到你邮箱的所有待处理、未过期邀请,并包含工作区及其授予的任何项目
describe(inviteId) · accept(inviteId) · decline(inviteId) 预览 · 接受 · 拒绝邀请

项目 — beeuni.projects

方法 说明
list() · listForAccount(accountId) 你的项目 · 账户中的项目
get(id) · detail(id) 摘要 · 完整详情
create(input) · createRepo(input) 从现有 repo_url · 新建空 GitHub 仓库
provision(input) 在新的 Beeuni 管理仓库上创建项目,并使用入门模板初始化——{ name, account_id?, seed_starter?, starter_template?, marketplace_items?, source_item_id?, idempotency_key? }
update(id, input) · archive(id) 更新设置 · 归档
llmCatalog(id) · modelPicker(id) 完整 · 紧凑模型目录,用于选择器
sandboxTemplates(id) · sandboxHealth(id) 沙盒构建模板 · 构建健康状况
sessions(id) · createSession(id, input?) 列出可见会话 · 创建会话

provision 会创建新项目;它不会启动现有项目的沙盒。请改为启动会话——参阅 Sessions。

可以重试时发送 idempotency_key——例如重新加载、打开第二个标签页或重试超时请求。provision 每次调用都会创建一个全新的托管仓库,因此没有密钥时,这些调用都会创建实际的重复项目。对同一次逻辑创建的每次尝试都重复使用同一个密钥,后续重复请求会返回第一次尝试创建的项目(201、相同的 project_id、push_token: null)。密钥标识的是尝试,而不是负载——使用同一个密钥提交不同的 name 时,会返回第一个项目并忽略新值,因此每次不同的创建都应签发新密钥。使用相同的名称且不带密钥创建第二个项目仍然有效。

如果重复请求到达时第一次调用仍在配置中,它会返回带有 code: 'provision_in_flight' 的 409,而不是 project_id;第一次调用仍可能回滚。请使用相同密钥重试。

project(id).sessions.list({ scope: 'project' }) 是面向具有项目管理权限的调用者的生命周期清单。它会增加可访问但不可用、预热中和软删除的会话,并附带所有权和运行时状态元数据。两种列表范围都会省略调用者无法打开的所有会话。

sessions.list 和 sessions.listPage 也接受层级和归因筛选条件。不提供这些条件时,列表保持扁平且不变。

选项 说明
parent: 'root' 仅顶层会话。每行都包含 child_count。
parent: '<sessionId>' 该会话的子会话,按最新优先排序。
startedBy: 'me' | 'others' | 'automated' 按相对于调用者的 initiator 筛选。
q 在调用者可以打开的每个会话中,对标题、启动器标签、触发器 slug 和会话 ID 前缀执行不区分大小写的搜索。使用 parent: 'root' 时,通过子会话匹配的根会话具有 search_match: 'child'。

每个会话行都有 parent_session_id 和 initiator({ type: 'member' | 'trigger' | 'channel' | 'api' | 'system', id, label })。initiator 标识启动整个运行的人员;子会话会复制其父会话的值。sessionParentId(session) 会读取 parent_session_id,然后读取旧版 metadata.spawned_by_session。游标仅对签发它的筛选条件集有效。

GitHub — beeuni.github

账户范围的 GitHub App 安装和仓库链接,而非项目范围的操作。

方法 说明
getInstallation(accountId) · listInstallations(accountId) 此账户的安装 · 用户可访问的安装
saveInstallation(input) · deleteInstallation(accountId, installationId?) 记录 · 解除安装关联
listLinkableInstallations(input) 已授权的 GitHub 用户可关联的安装;每个条目包含 linked_to_other_accounts,表示持有该安装的其他 Beeuni 账户数量,绝不包含其名称
listRepositories(accountId, installationId?) · listRepositoryBranches(...) 安装可访问的仓库 · 分支和 GitHub 默认分支
linkRepository(input) 使用已授权的 GitHub 安装将仓库导入为项目。
replaceProjectRepository({ project_id, repo_url, expected_repo_url, github_token }) 替换现有项目的 GitHub 仓库。使用具有 Contents 读写权限的 github_token,或使用 installation_id 加上临时的 github_user_token 来验证组织管理员权限,并通过 GitHub App 仅授权此仓库。copy_shared_secrets_from_project_id 加上 copy_shared_secret_identifiers 会在同一事务中复制选定的共享运行时密钥。过期的 expected_repo_url 返回 409。旧仓库仍保留在 GitHub 上。新会话使用替换后的仓库;现有会话保留其检出内容。

此列表仅包含真实的账户连接。“Beeuni managed”不在其中——它是下文的实例后端。

实例 git 后端 — beeuni.gitBackend

整个部署共用一个所有者及其凭据,用于 Beeuni 托管的仓库。它绝不是账户连接,也绝不会出现在 beeuni.github.listInstallations 中。

方法 说明
get() { configured, kind: 'app' | 'pat' | null, owner } — 任何已认证用户均可读取;它仅公开每个托管的 repo_url 已包含的所有者登录名

计费 — beeuni.billing

读取额度、订阅、套餐等级和交易历史。通过 Beeuni 结账和账单管理处理付款及额度购买。

方法 说明
accountState(accountId?) · accountStateMinimal(accountId?) 完整 · 最简计费状态
transactions(params?) · transactionsSummary(params?) 历史记录 · 汇总总额
creditBreakdown(accountId?) · usageHistory(params?) 按来源划分的额度余额 · 随时间变化的用量
sessionCosts.list(options?) · sessionCosts.get(sessionId, options?) 分页会话费用记录 · 单个会话的详细账目
tierConfigurations() 可用套餐等级
checkout.createSession(input) · checkout.confirmSession(sessionId, accountId?) 已弃用。 以 ENDPOINT_RETIRED 拒绝。将在下一个主要版本中移除。
subscription.createPortalSession(...) · subscription.cancel(...) · subscription.reactivate(...) 打开客户门户 · 取消 · 重新启用
subscription.cancelScheduledChange(...) · prorationPreview(...) 取消 · 预览套餐变更
subscription.scheduleDowngrade(...) 已弃用。 以 ENDPOINT_RETIRED 拒绝。请在客户门户中更改套餐。将在下一个主要版本中移除。
credits.purchase(input) · credits.autoTopupSettings(...) · credits.configureAutoTopup(...) 一次性购买 · 读取 · 配置自动充值

sessionCosts.list() 接受 accountId、projectId、limit 和 offset。 每行合并已结算的 LLM 费用和已计费的沙盒计算费用。 sessionCosts.get() 额外提供模型用量及区分 LLM/计算费用的账目。 列表包含无关联会话费用的对账总额。

沙盒共享 — beeuni.sandboxShares

针对一个对外开放的沙盒端口的公开共享链接。作用范围是沙盒,而非项目。

方法 说明
list(sandboxId) 有效共享链接
create(input) 创建一个 — { sandboxId, port, ttl?, label? }
revoke(sandboxId, token) 撤销一个

市场目录 — beeuni.marketplace

公开目录浏览,只读——不同于将条目安装到项目上的 project(id).marketplace。

方法 说明
items(options?) · item(id) · itemFile(id, path) 浏览 · 单个条目 · 条目中的文件
marketplaces() · featured() 所有 · 精选市场
sources.list() · sources.add(input) · sources.remove(id) 列出 · 添加 · 移除来源

通知 — beeuni.notifications

调用者在所有账户和项目中的通知。每位已登录用户都有一个收件箱、一条偏好设置记录,以及其浏览器的 Web Push 订阅。每个方法都需要个人凭据:服务账户会收到 403。

const page = await beeuni.notifications.list({ limit: 20 });
await beeuni.notifications.markRead({ ids: [page.notifications[0].id] });
await beeuni.notifications.updatePreferences({ kinds: { turn_done: { push: false } } });
方法 说明
list({ limit?, before? }, { signal? }) 最新一页:{ notifications, unread_count, next_before }。limit 为 1 到 50(默认 20)。将 next_before 作为 before 传入以获取下一页。调用者不再可见的记录会被排除。失败时不会调用宿主错误处理程序。
markRead({ ids }) · markRead({ all: true }) · markRead({ sessionId }) 将 1 到 100 条记录、所有记录或某个会话的所有记录标为已读。仅更改调用者的记录。返回 { updated, unread_count }。
preferences() · updatePreferences({ kinds }) 读取 · 更改每种类型的推送和电子邮件选项。返回 { kinds, email_available }。补丁仅更改其中指定的类型和渠道。
webPushPublicKey() { public_key }:用于 pushManager.subscribe 的 applicationServerKey
registerWebPushSubscription({ endpoint, keys }) 向此浏览器发送推送。需要浏览器登录:个人令牌会收到 403。未知推送服务上的端点会收到 400。
unregisterWebPushSubscription(endpoint, { signal? }) 停止向此浏览器推送。返回 { deleted }。
registerDeviceToken(input) · unregisterDeviceToken(token, { signal? }) 注册 · 移除原生应用的 Expo 推送令牌

类型(InboxNotificationKind,列于 INBOX_NOTIFICATION_KINDS):

类型 发送时机 推送 电子邮件(默认)
turn_done 你发起或关注的轮次结束 开启 关闭
turn_error 该轮次因错误而结束 开启 开启,汇总发送
question 智能体提出问题 开启 开启,汇总发送
permission 智能体请求权限 开启 关闭
shared 有人与你共享了会话 开启 开启,汇总发送
automation_failed 你关注的自动化开始失败 开启 开启,立即发送
automation_recovered 该自动化恢复正常 开启 关闭

DEFAULT_NOTIFICATION_PREFERENCES 保存这些默认值。收件箱记录始终会写入;偏好设置仅决定推送和电子邮件。汇总邮件列出收到 15 分钟后仍未读的记录,每小时最多发送一封。当 email_available 为 false 时,隐藏电子邮件列。

每条记录的 url 会打开其主题。其 ?notification=<id> 查询参数让页面将该记录标为已读。

会话句柄包含调用者对单个会话的关注状态:

方法 说明
session(pid, sid).watch() { watching }:调用者是否会收到此会话的通知
session(pid, sid).setWatch(watching) false 为调用者静音此会话,true 重新关注它。向会话发送提示会关注该会话,但绝不会取消静音。
session(pid, sid).presence({ tab_id, active, alerts? }, { keepalive? }) 此标签页的在线状态租约。alerts: true 表示标签页会自行显示通知:启用 notification_center 时,服务器仅在显示提醒的标签页正被使用时跳过手机和 Web Push 推送。关闭时,alerts 被忽略,任何在线标签页都会阻止手机推送。keepalive 允许请求在页面关闭后继续。默认值:报告离线时开启,报告在线时关闭。useSession 仅在带有 presencePageExit 时发送 keepalive。

项目句柄 — beeuni.project(id)

绑定项目 ID;所有子资源都依附于它。

const p = beeuni.project(projectId);
await p.detail();
await p.update({ name });
await p.llmCatalog();
方法 用途
get · detail · update · archive 读取 · 完整详情 · 更新 · 归档
llmCatalog · modelPicker · sandboxHealth 读取模型和沙箱构建
onboardingComplete 将项目入门引导标记为已完成
validateManifest(raw) 在服务端验证 beeuni.yaml(或旧版 beeuni.toml)清单
gitToken() 生成新的限定作用域的 git 推送令牌(自带仓库使用 409)
setAgentScope(agentName, scope) 在清单中设置智能体允许使用的密钥和连接器——这是第二重绑定,不是角色

p.tokens — 项目作用域的 API 密钥

创建会话时自动生成,作为 BEEUNI_TOKEN;也可手动生成。

方法 用途
list() 项目 API 密钥
create(input?) 生成新密钥
revoke(tokenId) 撤销密钥

用户打开此链接即可输入密钥或连接应用,无需拥有完整的 项目访问权限。

方法 用途
requestSecret(input) · requestConnector(input) 用于收集密钥的链接 · 连接应用

p.apps — Apps(发布、机器、卷)

由项目功能 apps 控制。指南:SDK → Apps。

方法 用途
list() · get(appId) · create(input) · update(appId, input) · remove(appId) 资源清单和生命周期;create 接受 uses,update 还接受 labels
deployments.* · artifacts.* · access.* · rollback · start · stop 部署、构件、访问策略、流量和运行时
machines.list/start/stop/restart/destroy · scale(appId, count) · exec(appId, input) 每个进程组的机器;exec 需要 project.app.admin
volumes.list/create/update/destroy/snapshots/snapshot/restore/fork 持久卷、每日快照、恢复、分叉
token(appId) 有效期为 15 分钟的登录令牌;不带 member_tokens 的 409 app_capability_unsupported

p.secrets — 项目密钥

方法 用途
list() · upsert(input) 列出元数据 · 创建或更新只写值和交付策略
setStrategy(identifier, strategy, options?) 更改暴露方式及其主机列表
broker(identifier, request) 执行经会话授权、受策略约束的 HTTPS 请求
remove(identifier) 删除密钥
setPersonal(name, value) · removePersonal(name) 设置 · 移除用户级覆盖值
setGitCredential(input) 设置 git 身份验证凭据

使用消费方 sandbox 的 runtime 属于环境暴露——这是默认方式, 也是唯一会将明文值放入会话的策略。使用 消费方 network 的 egress 属于出口强制执行暴露:会话持有句柄, Beeuni 在沙箱外替换为真实值,仅针对策略列出的确切 HTTPS 主机。出口强制执行暴露是实验性功能;它需要 secrets_egress 功能开关(Settings → Feature flags)。关闭此开关时, 带有出口策略的 setStrategy(identifier, 'egress', …) 和 upsert(...) 返回 403 feature_disabled。所有 broker 消费方都完全不会出现在会话中。 参见 密钥。broker(...) 方法需要 会话作用域的令牌和有效的会话句柄。

p.access — 项目分配、邀请、请求

这里的每个方法都读取或写入此项目作用域内的分配。项目 角色为 manager 和 member。

方法 用途
list() · invite(email, role) 拥有访问权限的主体 · 邀请用户
update(userId, role) · revoke(userId) 分配项目角色 · 撤销分配
pendingInvites() · requests() 未完成的邀请 · 待处理的访问请求
resendInvite(inviteId) · revokeInvite(inviteId) · approveRequest(id) · rejectRequest(id) 重新发送/撤销邀请 · 批准/拒绝请求
groupGrants() · attachGroupGrant(...) · updateGroupGrant(...) · detachGroupGrant(...) 相同的分配,但主体为 group

p.access.resourceGrants 是对象分配视图:它将 主体的范围限定为项目中的一个对象,而不是整个项目。Beeuni 目前对智能体和技能强制执行对象分配。智能体默认不开放 ——只有分配中指定了成员本人或其所属的某个 组,该成员才能访问它。对象分配本身不赋予任何权限,对 项目管理员和成员施加同样的限制。

方法 用途
resourceGrants.list() 此项目中的对象分配
resourceGrants.create(input) 将一个对象分配给用户或组
resourceGrants.remove(grantId) 撤销一项对象分配

p.connector(slug) — 单个连接器

方法 用途
run(action, args, options?) 操作的输出;抛出 ConnectorCallError 或 ConnectorApprovalPendingError——参见错误
call(action, args, options?) 原始调用结果;202 以 ok: false 完成解析
describe() · describe(action) 带输入和输出模式的连接器 · 单个操作
accounts() 此调用者可用来运行它的账户,默认账户排在首位
paginate(action, args, { next, maxPages? }) 遍历每页输出的异步迭代器;页数超过 maxPages(默认 100)时抛出带有 nextArgs 的 ConnectorPageLimitError——参见分页
uploadAttachment(content, input) 将 connector 设为此 slug 的 p.connectors.uploadAttachment

options:account、approvalContext、timeoutMs(默认 90 000)、signal。使用来自 beeuni connectors types 的文件后,参数和输出都具有类型。

p.connectors — 工具连接器

方法 用途
catalog() · tools() 可调用的 Connector 目录 · 扁平化的 <connector>.<action> 工具
search(query, options?) · describe(tool) 查找 · 检查单个可调用工具
call(tool, args?, options?) 通过服务端网关调用一个 <connector>.<action> 工具。options.account 指定以哪个账户运行——见下文。
accounts(slug) 此调用者可用来调用 slug 的账户,默认账户排在首位——即 options.account 的匹配对象
uploadAttachment(content, input) 为 input.connector 暂存字节;返回 ref({ $beeuni_attachment }),供放入后续调用的参数中——参见附加文件
list() · config(connectorId) 已配置的连接器 · 单个连接器的配置
create(input) 添加连接器
auth.discover(input) 从 OpenAPI 规范、Postman 集合或端点预览身份验证
remove(connectorId) · sync() 删除连接器 · 重新同步连接器
setName(connectorId, name) · setSensitive(connectorId, sensitive) 重命名 · 标记为敏感(额外的审批控制)
setAuthorizationStrategy(slug, strategy) @deprecated。仍会调用路由;该路由不执行任何操作,仅返回 {ok:true, deprecated:true},不做任何更改。现在,每个连接上的 owner_type 就是完整的访问规则。
setCredentialMode(connectorId, mode) · setCredential(connectorId, input) 切换来源 · 设置凭据值
policies.get(connectorId) · policies.set(connectorId, policies) 读取 · 替换其工具策略
connections.list() · connections.reconcile(input) 列出 · 创建/更新已连接的账户
connections.updateCredential(connectionId, input) 轮换连接凭据
connections.revoke(connectionId) · connections.activate(connectionId) 禁用 · 恢复连接
connections.setDefault(connectionId) 将其设为所属所有者作用域的默认连接
connections.rename(connectionId, label) 仅更改标签;账户仍保持授权。每个连接都携带 connected_as,即其获得授权时所用的身份。

p.connectors.discover 用于浏览直接连接器目录。它是实验性功能,默认关闭——可在每个项目的 Settings → Feature flags → “Connectors API Discover” 下启用。Easy Connect 仍是默认连接器市场。

方法 用途
discover.list(query?, cursor?) · discover.detail(id) 搜索 OpenAPI/MCP/GraphQL/CLI 条目 · 单个条目的详情

p.connectors.pipedream 是旧版托管 OAuth 兼容路径;listApps 仅返回 OAuth 应用。新的托管集成请使用 Easy Connect。API 密钥应用请直接连接。

方法 说明
pipedream.listApps(params?) · pipedream.connect(input) · pipedream.finalize(input) 浏览应用目录 · 开始连接流程 · 完成连接

连接器定义工具、提供商应用和策略。connections 存储其已连接的账户——一个连接器可以并列持有多个账户。 会话可以通过 connector_bindings: { alias: { connection_id } } 为每次调用固定一个账户, 也可以通过 call(tool, args, { account }) 为单次调用指定一个账户。凭据始终加密存储, 并按请求解析。

connections 是唯一有效的授权门面。已废弃的 authorizations 和 profiles 名称不属于当前 SDK 接口。

账户与调用时检查

每个连接都有一个 owner_type:project(共享——连接器授予的任何人都可访问, 包括用户或服务账户)或 member(私有——只有其所有者可访问,且只能在私有会话中访问;服务账户永远无法访问)。共享账户可以进一步限制到群组和人员: connections.list() 在 shared_with 中返回其授权范围,而 connectionSharedWithEveryone(connection) 会回答项目中的所有人是否都可以使用它。受限账户对其指定的人员遵循私有规则,而 usable: false 会标记一个账户,使调用者只能看到并管理它。使用 createAssignment / revokeAssignment 授予或撤销权限 (object: { type: 'connection', id })——参见 选择谁可以使用共享账户。 p.connectors.accounts(slug) 列出调用者可以访问的所有账户, 默认账户排在首位:

const accounts = await beeuni.project(projectId).connectors.accounts('stripe-read');
// [{ connection_id, label, owner_type, is_default }, ...]

await beeuni.project(projectId).connectors.call(
  'stripe-read.get_balance',
  {},
  { account: 'My Stripe' }, // a connection id, a label, or the words `me` / `project`
);

未指定账户的调用会先解析为调用者自己的默认私有账户,然后解析为项目的默认共享账户。无法解析的指定账户会通过 connector_not_connected 被拒绝——绝不会静默替换,并且拒绝信息会列出 requested_account 和 available_accounts。每次成功调用都会返回其使用的账户: result.account = { connection_id, label, owner_type }。

现在已不再有创建会话时的连接器检查。过去,当所需连接器没有可用连接时,会话会被 409 CONNECTOR_CONNECTION_REQUIRED 拒绝;该拒绝已取消(require_connectors 不再生效——参见 p.sessions)。检查已移至调用阶段:被拒绝的 connector_not_connected 会在可以为调用者生成授权链接时携带 connect_url,即托管授权链接——整个补救过程只需点击一次,并通过记录中的连接按钮提供。

p.policies — 项目策略

方法 说明
list() · set(policies) 项目策略 · 替换整个策略集

p.triggers — cron、Webhook、监控和事件自动化

触发器会按计划、通过入站 Webhook、受监控的命令或连接器上的应用事件启动代理操作。参见 触发器,了解会话策略和负载模板化。

方法 说明
list() 所有触发器
eventTypes({ connector }) 连接器可以触发的应用事件({ provider, app, event_types });未知连接器返回 404;其提供商没有事件源时返回 409 event_source_unavailable
create(input) 创建一个触发器
update(triggerId, input) 编辑触发器
remove(triggerId) 删除触发器
fire(triggerId) 立即运行
setActivation(paused) 暂停或恢复项目中的所有触发器

create(input) 接受 { name, type: 'cron' | 'webhook' | 'monitor' | 'event', prompt_template, slug?, agent?, model?, enabled?, session_mode?, session_id?, cron?, run_at?, timezone?, secret_env?, connector?, event?, event_source?, event_account?, event_config?, session_access? }. name and prompt_template,其中 name 和 prompt_template 为必填项。 cron/run_at 互斥(type: 'cron');secret_env(Webhook HMAC 密钥)适用于 type: 'webhook'。

event 触发器需要 connector(连接器 slug)和 event(来自 eventTypes 的类型 ID)。event_account 为可选项:该连接器的一个共享账户的标签;null 或省略时使用连接器的默认共享账户。 event_source 为可选项:事件源适配器 ID,例如 composio。null 或省略时使用连接器的提供商。类型 ID 属于该适配器。event_config 的结构由该类型的 config_schema 决定。 eventTypes 和 eventApps 会将适配器报告为 source;provider 是已弃用的别名。 每个列出的触发器都包含 event: { connector, account, connected_as, type, config, source, provider, app, status: 'active' | 'needs_connection' | 'error' | 'pending', error, last_event_at } | null。提示模板会读取事件的 {{ event.data.<field> }},以及 event.id、event.type、event.app、 event.connector 和 event.occurred_at。

session_access 控制谁可以打开触发器创建的会话。它是 { mode: 'private' | 'members' | 'project', memberIds: string[], groupIds: string[] } and defaults to private。此策略是账户本地的运行时状态,不会写入可移植的 beeuni.yaml 清单。仅更新 session_access 不会创建 Git 提交。固定的会话会保留自己的共享设置。项目管理员始终可以打开触发器创建的会话,包括使用 private 或选定成员访问权限的会话。

session_access 是基于每个资源的可见性设置,叠加在角色模型之上,而不是一种角色。它决定谁可以打开某个触发器的会话。它不会授予角色判定所拒绝的任何权限。参见 账户与访问权限。

p.marketplace / p.registry — 已安装项目

将目录项目的文件安装到项目的默认分支。 registry.* 是 marketplace.* 的完全相同别名。

方法 说明
marketplace.list() · marketplace.install(id) 已安装项目 · 安装目录项目
marketplace.updates() · marketplace.update(name) · marketplace.updateAll() 可用更新 · 更新一个 · 全部更新
marketplace.remove(name) 卸载项目

p.files — 仓库文件(读取)

只读访问项目的 Git 树。要在运行中的会话内读取和写入文件,请使用会话的文件操作——参见下方模块中的 文件。

方法 说明
listDirectory({ ref?, path? }) 一层文件夹:{ entries: [{ path, type, size? }], truncated }。用于构建目录树;每个文件夹最多完整返回 5,000 个条目。
list(options?) · read(path, ref?) 路径下的所有文件(递归),达到 1,000 个时截断(截断时响应会携带 X-Beeuni-Truncated: 1)· Git 引用处某个文件的内容
search(query, { content?, ref?, limit? }) 在整个仓库中搜索文件名,或使用 content: true 搜索内容
archive(options?) · history(path) 下载 tarball · 某个文件的 Git 历史

p.git — 历史记录

方法 说明
commits() 提交日志
commit(sha) · commitDiff(sha) 某次提交 · 其差异
branches() · versionDiff(from, to) 分支 · 两个引用之间的差异

p.changeRequests — 生命周期与合并

变更请求(CR)用于将会话的工作合并到默认分支。

方法 说明
list() · get(crId) 未关闭的 CR · 某个 CR
diff(crId) · mergePreview(crId) 其差异 · 预览合并结果
open(input) · merge(crId, input?) 打开 · 合并 CR
close(crId, input?) · reopen(crId, input?) 不合并直接关闭 · 重新打开已关闭的 CR
requestChanges(crId, input) 记录反馈,可选择将其传回发起会话

p.sessions — 以及会话句柄

方法 用途
list() 项目的会话
create(input?) 创建会话
session(sid) 会话句柄(与 beeuni.session(id, sid) 相同)

会话句柄是运行时的核心 — 参见 会话。

create(input) 接受以连接器连接 slug 为键的 connector_bindings。 每个值指定一个 connection_id。它还接受 secrets,用于 缩小后端来源密钥的范围。require_connectors 已弃用且 不生效:仍接受该字段(不会因旧客户端发送该字段而拒绝请求), 但没有任何逻辑读取它 — 创建会话时,绝不会因某个连接器 没有可用账户而拒绝会话。参见账户与调用时 门控。

p.approvals — 连接器审批收件箱

受连接器门控、等待决策的待处理操作 — 为 权限审批体验提供支持(APPROVE / ASK / BLOCK)。

方法 用途
list(options?) · sessionsNeedingInput(options?) 待处理审批 · 因等待决策而阻塞的会话
resolve(executionId, decision, scope?) 批准或拒绝一项 — decision: 'approve' | 'deny'、scope: 'once' | 'session' | 'session_all'

p.gateway — LLM 可观测性

此项目模型流量的请求日志、成本/延迟汇总、预算和网关 API 密钥。

方法 用途
logs(opts?) · log(logId) 请求日志条目 · 单个日志条目
overview(days?) · series(days?) · breakdown(days?) · sessions(days?) · errors(days?) 时间窗口内的汇总、每会话成本和错误
budgets() · setBudget(input) · deleteBudget(budgetId) 读取 · 创建/编辑 · 移除预算
keys() · createKey(name) · revokeKey(keyId) 列出 · 生成 · 撤销网关 API 密钥
playground(prompt, models) 在最多 6 个模型上运行同一条提示词
routing.get() · routing.set(policy) · routing.reset() 读取 · 替换 · 继承路由策略
routing.preview(input) 解析路由,不调用模型

路由策略包含默认模型、视觉模型和有序的 回退链,每个模型最多尝试一次;fallbackOn 为 transient 或 any-error。

只有当前模型在返回任何输出之前失败,网关才会 转到下一个回退模型:

  • transient:网络错误、超时、任何 5xx,或 402、403、429。
  • any-error:所有失败,包括 400。

开始输出后的失败仍由该模型承担。使用你自己的 提供商密钥(BYOK)的请求绝不会回退到由 Beeuni 计费的模型。每个回退 模型都有各自的生成默认设置。

p.channels — Slack / 电子邮件 / 语音

连接器接口,让智能体能够充当 Slack 应用、电子邮件地址, 或加入实时语音通话。

方法 用途
slack.installation() · slack.mode() · slack.manifest() 当前安装 · 模式 · 应用清单
slack.connect(input) · slack.disconnect() 连接 · 断开连接
slack.getFile(url) · slack.uploadFile(input) 通过服务器代理下载 · 上传文件
email.installation(connectorSlug?) · email.mode() 当前安装 · 模式
email.connect(input) · email.disconnect(...) · email.updatePolicy(input) 连接 · 断开连接 · 更新发送/回复策略
voice.setBotName(name) 在进行中的通话中重命名机器人

p.modelDefaults — 默认模型偏好设置

账户、智能体和项目范围的模型默认设置,由网关解析。

方法 用途
get() · set(input) · clear(params) 读取 · 设置默认值 · 清除覆盖设置

p.setDefaultAgent — 项目默认智能体

p.setDefaultAgent(agentName) 检查智能体是否已声明并启用, 然后将其设为项目 beeuni.yaml 中的 default_agent。新会话 优先使用该智能体,除非用户选择其他智能体。

p.updateFeatureFlag — 功能标志

p.updateFeatureFlag(feature, enabled) 为项目开启或关闭一个功能标志。 传入 enabled: null 可清除覆盖设置并回退到 平台默认值。它调用规范的 PATCH /v1/projects/:id/features。

feature 是 FEATURE_FLAG_KEYS 中的一个(从 @beeuni/sdk 导出,类型为 FeatureFlagKey)。调用者需要项目的 project.settings.write 权限;否则路由返回 403。

标志关闭时,所有受该标志门控的路由都以相同方式拒绝请求:HTTP 403, 附带 { error, code: "feature_disabled", feature }。使用 isFeatureDisabledError(error) 据此执行分支逻辑,使用 featureDisabledKey(error) 读取标志键 — 切勿 匹配消息文本。

p.updateExperimentalFeature(feature, enabled) 是已弃用的别名。它 仍调用已弃用的路由别名 PATCH /v1/projects/:id/experimental, 以便固定使用较旧已部署 API 的调用方继续正常运行。新代码中请使用 p.updateFeatureFlag。

p.sandbox — 模板与快照构建

项目句柄上 sandboxHealth/sandboxTemplates 之外的沙箱构建配置: Dockerfile/镜像/预热池模板及其快照构建。

方法 用途
list() · snapshots() 此项目的沙箱 · 已构建的快照
rebuildSnapshot(slug?) · fixWithAgent() 重建快照 · 请求智能体修复失败的构建
createTemplate(input) · updateTemplate(...) · removeTemplate(...) · buildTemplate(...) 添加 · 编辑 · 删除 · 构建模板
setProvider(provider) 请求切换提供商。null(或平台默认提供商 / 已在使用的提供商)立即生效;切换到另一个已启用的提供商会启动持久化的准备→验证→激活转换 — 在构建和验证目标预热镜像期间,当前提供商继续提供服务,之后激活目标。返回值为带标签的联合类型:kind:'project'(立即生效)或 kind:'preparation'(轮询 getProjectSandboxProviderTransition(),直到 activated/failed)

平台管理员 hooks(@beeuni/sdk/react)

这些 hooks 为管理控制台提供服务。API 仅响应平台 管理员的这些请求。每次变更都会使 ['admin', 'accounts'] 查询失效。

Hook 功能
useAdminRole(userId, options?) 从 GET /user-roles → { isAdmin, role } 读取调用者角色。userId 用作缓存键。缺少 userId 时禁用查询。在挂载和获得焦点时重新获取,因此角色被撤销后,最多一次导航便不再据此放行。
useAdminGrantCredits() 变更 { accountId, amount, description, isExpiring }:增加钱包余额。POST /admin/api/accounts/:id/credits。涉及资金变动:请先在 UI 中确认。
useAdminDebitCredits() 变更 { accountId, amount, description }:扣减钱包余额。POST /admin/api/accounts/:id/credits/debit。涉及资金变动:请先在 UI 中确认。
useAdminSetTier() 变更 { accountId, tier }:设置套餐档位。
useAdminGrantTrial() 变更 { accountId, tierKey, seats, durationDays, creditGrant?, note? }:授予或替换试用。在试用期结束前,账户按 tierKey 运行。creditGrant 还会增加钱包余额。
useAdminRevokeTrial() 变更 { accountId }:立即结束当前试用。没有进行中的试用时返回 400。

备用访问方式

beeuni.runtime() 返回当前活动沙箱的类型化 运行环境 REST 客户端。 在由 createScopedBeeuni 创建的客户端(@beeuni/sdk/server)上,它会抛出异常 — 在多租户服务器中,进程全局的“活动”运行时是另一个请求的沙箱, 会导致跨租户泄露。请改用会话范围的 beeuni.session(pid, sid).runtime(先调用 ensureReady()),它会 解析该会话自己的沙箱。

模块

客户端 门面和 React hooks 背后不依赖框架的模块。当你需要绕过门面执行单个操作、 使用纯辅助函数或仅适用于 Node 的隔离层时,可以使用这些模块。每个模块都标有 稳定性级别,便于你判断可以基于哪些模块进行构建。

层级 含义
标准入口 从根入口 @beeuni/sdk 导入。所有新代码都应使用此入口。
受支持 专用子路径(@beeuni/sdk/react、@beeuni/sdk/server)。提供一等支持,未弃用。
已弃用别名 仍可使用的旧子路径。它重新导出根入口已导出的代码。请改为从根入口导入。
内部 不受 semver 约束。不要在宿主代码中导入。

根入口是标准入口。下面所有不依赖框架的名称都可以直接从 @beeuni/sdk 导入:

import { files, getSessionHealth, getClient, authenticatedFetch, backendApi } from '@beeuni/sdk';

标准模块

模块 功能
文件 工作区文件操作:列出、读取、搜索、写入
会话运行时 健康探测及预览/代理 URL 构建器
运行环境 客户端 类型化的 运行环境 REST 客户端及其完整类型接口
认证 authenticatedFetch 和令牌访问器
Projects REST 门面封装的原始 REST 函数
API 客户端 backendApi,底层类型化 HTTP 客户端
轮次 将消息分组为轮次,以及费用和状态计算 — 参见轮次
对话记录 formatTranscript,客户端 Markdown 导出
输入编辑器列表 会话输入编辑器的智能体和模型列表:提供哪些选项、运行哪个选项

文件

import { files } from '@beeuni/sdk';

const tree = await files.list('/workspace/src');
const { content } = await files.read('/workspace/README.md');
const hits = await files.findText('TODO');
await files.upload(file, '/workspace/uploads', file.name, {
  onProgress: ({ loadedBytes, totalBytes }) => {
    console.log(`${loadedBytes}/${totalBytes}`);
  },
});

超过 64 KiB 的上传内容会以经过验证的分块跨越沙箱边界。每个分块到达会话文件系统后,都会调用进度回调。

uploadNativeFile({ uri, name, type? }, targetPath, baseUrl) 通过一次请求从 React Native 上传设备文件。运行时从 uri 流式传输字节,因此这些字节不会进入 JS 堆。它使用与 files.upload 相同的认证、截止时间和 401 重放机制。不进行分块。

fetchProjectArchive、fetchCostExportCsv 和沙箱版本调用通过同一传输层发送。失败时会抛出带有 status 的 ApiError。

files.write(path, blob) 替换 path 处的文件;如果 path 是文件夹,则会失败。files.create(path) 创建空文件,且绝不覆盖:当 path 处已存在文件或文件夹时,它会抛出 FileExistsError(status 409、code 'FILE_EXISTS')。

import { FileExistsError, files } from '@beeuni/sdk';

try {
  await files.create('/workspace/notes.md');
} catch (error) {
  if (error instanceof FileExistsError) console.log(`${error.path} already exists`);
  else throw error;
}

files 面向全局当前活动的沙箱。如果宿主同时运行多个会话,请改为在会话句柄上调用 s.files。它始终面向该会话自己的沙箱。参见会话。

会话运行时辅助函数

import { getSessionHealth, isRuntimeReady } from '@beeuni/sdk';

const result = await getSessionHealth();
if (result.ok && isRuntimeReady(result.health)) {
  // the sandbox daemon is ready
}

getSessionHealth 不会因非 2xx 状态而抛出异常。它返回 { status, ok, health, body },由你决定状态的含义。同一模块还导出 URL 辅助函数,用于将智能体的 localhost 输出改写为可访问的代理 URL:detectLocalhostUrls、rewriteLocalhostUrl、proxyLocalhostUrl、parseLocalhostUrl 和 buildWebProxyUrl。

运行环境 客户端

import { getClient } from '@beeuni/sdk';

const client = getClient();
const { data } = await client.session.list({ limit: 100 });

getClient() 返回活动沙箱的类型化 运行环境 v2 兼容客户端,已注入认证信息。当宿主运行多个会话时,应优先使用限定于单个会话的同一客户端 beeuni.session(pid, sid).runtime,而不是全局的 getClient()。

认证辅助函数

import { authenticatedFetch, getAuthToken } from '@beeuni/sdk';

const res = await authenticatedFetch(`${runtimeUrl}/beeuni/health`);
const token = await getAuthToken();

令牌来自你传给 createBeeuni 的 getToken 函数。大多数应用代码不需要此模块 — 文件、会话和门面层已经为你处理认证。

API 客户端

import { backendApi } from '@beeuni/sdk';

const data = await backendApi.get('/some/endpoint');
await backendApi.post('/some/endpoint', { name: 'x' });

backendApi 是所有 REST 函数的基础类型化 HTTP 客户端。仅在端点尚无类型化封装时使用它。

输入编辑器的智能体和模型列表

使用与 Beeuni Web 应用相同的规则,构建会话输入编辑器的智能体选择器和模型选择器。每个函数都是纯函数:先通过客户端获取输入,再将其传入。

import {
  composerSelectableAgents,
  createModelVisibility,
  flattenModels,
  modelInDefaultView,
  pickerProviderList,
  projectConfigAgentsToRuntimeAgents,
  resolveComposerAgent,
  resolveComposerModel,
  resolveModelDefault,
} from '@beeuni/sdk';

// Agents: the roster, the picker list, and the agent the send carries.
const roster = projectConfigAgentsToRuntimeAgents(detail.config);
const pickerAgents = composerSelectableAgents(roster, { enableProjects: false });
const agent = resolveComposerAgent({
  agents: roster,
  boundAgent: session?.agent,
  defaultAgent: detail.config.default_agent,
  selectedAgent: pick,
});
if (agent.disabled) {
  // no accessible agent: refuse the send
}

// Models: gateway projects read /model-picker, native projects merge the
// catalog synthesis with the running sandbox's provider list.
const gatewayEnabled = detail.project.experimental?.llm_gateway === true;
const providers = pickerProviderList({
  gatewayEnabled,
  modelPicker,
  runtimeProviders,
  llmCatalogProviders,
  secretNames,
});
const models = flattenModels(providers, { providerMode: gatewayEnabled ? 'gateway' : 'native' });
const isVisible = createModelVisibility({ catalogModels: models });
const defaultView = models.filter(
  (m) => m.enabled !== false && modelInDefaultView(m, { search: '', isStoreVisible: isVisible, selected }),
);
const { model, explicit } = resolveComposerModel({
  models,
  picks: [sessionPick],
  serverDefault: resolveModelDefault(modelDefaults, agent.selected ?? undefined),
  providers,
});

当输入编辑器使用默认设置时,resolveComposerModel 返回 explicit: undefined。model 是用于显示和发送的键。每个扁平化模型的 id 是选择操作存储的引用;modelRefToKey(ref, gatewayEnabled) 将已存储的引用(会话固定项、频道绑定、触发器的 model)读回为键。

受支持的子路径

子路径 功能
@beeuni/sdk/react React hooks — 参见 React hooks
@beeuni/sdk/server 多租户后端的请求级配置
@beeuni/sdk/wire-message-id 仅包含 运行环境 传输消息 ID 时钟(单个模块,无导入)。根入口导出相同的名称

传输消息 ID

提示的 messageId 是它在对话记录中的位置。运行环境 按 msg_ + 48 位时钟(Date.now() * 0x1000,低 48 位)+ 14 个 base62 字符对消息排序,时钟每 2^36 毫秒(约 2.2 年)回绕一次。切勿手动编码。

import { mintWireMessageId } from '@beeuni/sdk';

// `after`: the ids already in this session's transcript.
const messageId = mintWireMessageId({ after: transcriptIds });

生成时先将时间设为两分钟前,再提升到 after 中最多超前一小时的最新 ID 之上一个时钟刻度。调用方若以时钟而非 ID 保存最新位置,则使用 mintWireMessageIdAbove({ nowMs, newestKnownTime }), which returns { id, time }. newestWireIdClock(ids) 查找该时钟。所有比较都在环上进行,因此回绕两侧的 ID 仍保持真实顺序。

48 位时钟约每 2.2 年回绕一次,因此切勿用 > 或 <= 比较两个时钟:刚回绕后生成的 ID 在数值上小于刚回绕前生成的 ID。请使用 wireIdClockDelta(clock, reference),即环上的有符号距离(当 clock 在前时为正),并使用 maxWireIdClock(clocks) 找出多个值中最新的一个:

import { maxWireIdClock, wireIdClockDelta } from '@beeuni/sdk/wire-message-id';

const floor = maxWireIdClock([transcriptNewest, deliveredNewest]);
const stale = floor !== null && wireIdClockDelta(clientClock, floor) <= 0n;

服务端隔离

createBeeuni 将其配置(包括令牌函数)存储在一个进程级变量中。这适用于浏览器标签页、CLI 或单租户服务器。但对于处理不同用户并发请求的 Node 服务器,这并不安全,因为最后一次 createBeeuni 调用会覆盖所有进行中请求的配置。@beeuni/sdk/server 通过按请求隔离解决此问题:

import { createScopedBeeuni } from '@beeuni/sdk/server';

export async function handler(req: Request) {
  const beeuni = createScopedBeeuni({ backendUrl, getToken: () => tokenFor(req) });
  return beeuni.projects.list();
}

createScopedBeeuni 和 runWithBeeuni 使用 Node 的 AsyncLocalStorage 按请求隔离配置。切勿在浏览器打包代码中导入 @beeuni/sdk/server — 它会静态引入 node:async_hooks。

限定作用域客户端的顶层 runtime() 会抛出异常(它会解析到另一个租户的沙箱)。在 await s.ensureReady() 之后,通过 beeuni.session(pid, sid).runtime 访问特定会话的运行时。

已弃用的别名

约二十个旧子路径仍可使用:/files、/turns、/session、/auth、/projects-client、/api-client、/config、/event-stream、/opencode-client、/platform-client 等。每个子路径都重新导出根入口 @beeuni/sdk 已导出的代码。它们保持可用,以免现有的 import breaks, but new code should import from the root.

内部模块

@beeuni/sdk/internal/* 包含 apps/web 自身运行时在内部使用的 zustand 存储 — 会话同步状态、活动运行时跟踪和重连记录。此子路径明确不受 semver 约束。不要在宿主代码中导入它;React hooks 已经提供了你需要的状态。

轮次

将会话消息分组为轮次并对每个消息部分进行分类的普通函数。用它们构建自定义聊天渲染器,替代 apps/web 中的参考渲染器。不依赖 React 或 DOM — 每个导出项都是普通函数或类型,可从任何宿主安全调用。

import { classifyPart, classifyTurn, toolInfo, toolViewModel } from '@beeuni/sdk';

从根入口 @beeuni/sdk 导入所有函数。@beeuni/sdk/turns 子路径仍可使用,但它是已弃用的别名。新代码必须使用根入口 — 参见分发。

对部分进行分类

classifyPart(part) 将 Beeuni 对话记录格式(beeuni.transcript.v1、BEEUNI_TRANSCRIPT_SCHEMA)的 12 种片段类型之一规范化为 ClassifiedPart——一个以 kind 为键的联合类型。每个变体都已解析出渲染器所需的字段:工具状态、解析后的 JSON 输出、图像检测。

import { classifyPart, type ClassifiedPart } from '@beeuni/sdk';

for (const part of message.parts) {
  const classified: ClassifiedPart = classifyPart(part);
  switch (classified.kind) {
    case 'text':
      render(classified.text);
      break;
    case 'tool':
      render(classified.tool.title, classified.tool.status);
      break;
  }
}
kind 结构
text { id, text, synthetic }——跳过 synthetic 片段;它们标记 shell 模式的合成提示
reasoning { id, text }
tool { id, tool: ToolView }
file { id, filename?, mime, url, isImage, isPdf }
subtask { id, description, agent, prompt, model? }
patch { id, hash, files, fileCount }
snapshot { id, snapshot }
agent { id, name }
retry { id, attempt, message, createdAt }
compaction { id, auto, overflow, tailStartId? }
step { id, phase: 'start' | 'finish', snapshot?, reason?, cost?, tokens? }
unknown { raw }——此 SDK 版本不认识的片段类型

无法识别的传输片段会在运行时降级为 unknown,而不是抛出异常。这让旧版客户端能够与新版服务器通信。

工具片段被分类为 ToolView:

interface ToolView {
  name: string;
  title: string;
  status: 'pending' | 'running' | 'done' | 'error';
  input?: Record<string, unknown>;
  output?: string;
  error?: string;
  outputParsed?: unknown; // JSON.parse(output) when it parses, capped at 256KB
  outputText?: string;    // the raw output text, always present
  kind?: ToolKind;        // toolKind(name): the action, whatever the harness calls the tool
  files?: ToolFile[];     // the files a file tool read, wrote or changed: path, patch, additions/deletions
  diff?: string;          // a unified diff of the change
  diagnostics?: Record<string, unknown[]>; // language-server diagnostics, keyed by file path
  answers?: string[][];   // the answers to a `question`, one list per question
  childSessionId?: string; // the child session a delegating call (`task`) runs
}

toToolView(part) 直接从工具片段构建它。读取这些字段,而不是执行框架自身的 state.metadata:这样,同一张卡片就能渲染 运行环境 的 edit(filePath、filediff)和 pi 的 edit(path、edits,以及统一的 patch)。

某些工具(web_search、image_search、连接器调用)即使 JSON 正文包含 success: false,也会报告 state.status: 'completed'。classifyPart 会检测这种情况,并同样将 ToolView.status 设为 'error'。

classifyTurn(message) 对一条助手消息的每个片段进行分类,并返回一个包含三个字段的 ClassifiedTurn:

  • parts——分类后的各个片段
  • error——来自 message.info.error(如果有)
  • isEmpty——当该轮次没有错误,也没有包含可见内容的片段时为 true

工具元数据

toolKind(name) 是统一的工具分类体系:它将任意执行框架的工具名称(pi 的 write、运行环境 的 oc-apply_patch、插件的 pty_spawn)映射为一个 ToolKind——read、edit、write、bash、web_search、task、question、……或 other。叙述类别、视图模型、toolInfo 类别和上下文工具组都由它派生。inputPath(input) 从 filePath、file_path 或 path 读取文件工具的路径。

toolKind('oc-apply_patch'); // 'apply_patch'
toolKind('pty_spawn');      // 'pty'
inputPath({ path: 'app.py' }); // 'app.py'

还有两个查询函数都用于描述工具。不要混淆它们。

  • toolInfo(name)——不涉及图标,返回 { label, category }。classifyPart 在内部使用它。ToolCategory 为 'shell' | 'files' | 'search' | 'edit' | 'web' | 'task' | 'other'。
  • getToolInfo(name, input)——包含图标信息,为参考工具卡片 UI 返回 { icon, title, subtitle }。副标题来自工具的输入,例如文件路径或搜索查询。
toolInfo('bash'); // { label: 'Shell', category: 'shell' }
getToolInfo('write', { filePath: '/workspace/main.go' });
// { icon: 'file-pen', title: 'Write', subtitle: 'main.go /workspace' }

这两个函数都匹配工具名称前缀,因此 Beeuni 的插件工具系列(agent_*、session_*、task_*、trigger_*、project_*、pty_*)无需更新注册表即可解析。未知工具名称绝不会抛出异常——它会回退为 humanizeToolName(name),类别为 'other'。

工具视图模型

toolViewModel(classifiedTool) 将已分类的工具片段映射为专为某个工具系列构建的结构。UI 随后可以对其进行专门渲染,而不是作为通用 JSON 数据块显示。

const vm = toolViewModel(classifiedTool);
if (vm.kind === 'shell') {
  render(vm.command, vm.stdout, vm.exitCode);
}
kind 结构 工具
web-search { query, results?, answer?, error? } web_search、image_search
shell { command, stdout?, exitCode? } bash
file-read { path, preview? } read
file-write { path, preview? } write
file-edit { path, diff?: DiffLine[] } edit、morph_edit
search { pattern, matches?: SearchMatch[] } grep、glob
task { description, agent? } task
todo { items: TodoItem[] } todowrite
question { questions: QuestionItem[], answers? } question、ask
generic { label, inputPretty?, outputPretty? } 其余所有工具,始终可安全渲染

DiffLine 为 { type: 'added' | 'removed' | 'unchanged', text }。字符串字段设有上限,避免单次大型工具输出破坏渲染:格式化 JSON 限为 4000 个字符,运行差异比较前限为 256KB。

将消息分组为轮次

一个轮次将一条用户消息与回答它的助手消息配对。它是聊天 UI 作为一次交互渲染的单位。

import { groupMessagesIntoTurns, collectTurnParts, type TurnLike } from '@beeuni/sdk';

const turns: TurnLike[] = groupMessagesIntoTurns(messages);
for (const turn of turns) {
  const parts = collectTurnParts(turn);
}

groupMessagesIntoTurns 将每条助手消息关联到其父级用户消息。缺少父级链接时,它会回退到消息顺序。它还会将孤立的助手消息——没有父级且出现在所有用户消息之前的消息——附加到第一个轮次,而不是最后一个。

相关辅助函数:

  • findLastTextPart(parts)——该轮次的最终回复文本
  • turnHasSteps(parts)——如果存在 tool、compaction、snapshot 或 patch 片段,则为 true
  • isShellMode(turn) / getShellModePart(turn)——由一个合成提示驱动一次 bash 调用的轮次

类型守卫

通过 type 收窄片段类型:

import { isTextPart, isToolPart, getPartText } from '@beeuni/sdk';

if (isTextPart(part)) {
  // part.type narrowed to 'text'
}
const text = getPartText(part); // works for 'text' and 'reasoning' parts

还提供:isReasoningPart、isFilePart、isAgentPart、isCompactionPart、isSnapshotPart、isPatchPart、isStepPart(step-start 和 step-finish)。

状态和错误

import { getWorkingState, getTurnStatus, formatDuration } from '@beeuni/sdk';

const status = getTurnStatus(parts, childMessages); // "Running commands..."
formatDuration(4300); // "4s" — durations under 1s return ''

getTurnStatus 扫描一个轮次的片段,查找最后一条状态行。当最后一个片段是正在运行的 task 委派时,传入 childMessages,使状态显示子智能体的实际活动,而不是通用的“正在委派…”状态行。

import { getTurnError, getChildSessionError, unwrapError } from '@beeuni/sdk';

getTurnError(turn);                    // the first assistant error, unwrapped
getChildSessionError(childMessages);   // newest error in a sub-agent's messages
unwrapError(rawError);                 // normalizes double-JSON and mixed error shapes

费用和 token 总数

import { getTurnCost, getSessionCost, formatCost, formatTokens } from '@beeuni/sdk';

const info = getTurnCost(partsWithMessage, modelPricingLookup);
const sessionCost = getSessionCost(messages, modelPricingLookup);

formatCost(0.0032);  // "$0.003"
formatTokens(12345); // "12k"

这两个函数都从 step-finish 片段读取费用和 token 总数。当片段报告为零时,它们会使用 ModelPricingLookup 根据 token 数量估算费用。

ChatGPT/Codex 订阅消息计入 $0.00,包括运行时费用非零的历史消息。token 和上下文用量仍然可见。混合会话保留付费 API 消息的费用。OpenAI API 模型仍会计费,包括名称中含有 codex 的 API 模型。

子会话和待处理请求

项目会话的对话树(根对话及其生成的子智能体对话)来自其 runtime_sessions 列表。这些辅助函数读取该列表,优先使用当前名称,而不是 W4 之前的名称:

import { directSubsessions, projectSessionForRuntimeId, rootRuntimeSession, runtimeSessionsOf } from '@beeuni/sdk';

const root = rootRuntimeSession(projectSession);            // the root conversation id
const children = directSubsessions(projectSession);         // its subagent conversations
const owner = projectSessionForRuntimeId(projectSessions, childId); // the session a conversation belongs to

task 工具调用会委派给子会话。这些辅助函数将父轮次与该子会话自身的消息关联起来。

import { getChildSessionId, getChildSessionToolParts } from '@beeuni/sdk';

const childId = getChildSessionId(taskToolPart);
const steps = getChildSessionToolParts(childMessages);

将待处理的权限或问题请求与其工具调用匹配,并找出在请求处于活动状态时应隐藏哪些工具片段:

import { getPermissionForTool, getHiddenToolParts, isToolPartHidden } from '@beeuni/sdk';

const permission = getPermissionForTool(permissions, callID);
const hidden = getHiddenToolParts(activePermission, activeQuestion);

格式化和列表

import { getFilename, getDirectory, relativizePath, stripAnsi } from '@beeuni/sdk';

getFilename('/workspace/src/main.go');               // "main.go"
getDirectory('/workspace/src/main.go');               // "/workspace/src"
relativizePath('/workspace/src/main.go', '/workspace'); // "src/main.go"

会话列表辅助函数操作相同的会话数据:

import { sortSessions, childMapByParent, allDescendantIds } from '@beeuni/sdk';

sessions.sort(sortSessions(Date.now())); // pins sessions updated in the last 60s
const childMap = childMapByParent(sessions);
const descendants = allDescendantIds(childMap, sessionId);

重试状态:getRetryInfo(sessionStatus) 返回 { attempt, message, next, details? } when status.type === 'retry', with message 限为 60 个字符。details 会在存在结构化 LLM 网关封装时保留它:最终提供商、网关代码、请求 ID、建议、上游状态,以及按顺序排列的候选失败信息。每个候选失败信息包含 attempt、provider、routeModel、resolvedModel、stage、可选的 status、code 和 message。旧版纯文本重试返回 details: undefined。 getRetryMessage(sessionStatus) 返回解除封装后的完整消息。当 运行环境 仅保留该消息时,网关复合信息仍包含请求 ID,以及每个候选的提供商、解析后的模型、HTTP 状态、代码和有长度限制的消息。

结构类型

分组和状态函数接受最小结构类型 — PartLike、MessageInfoLike、TurnLike、ToolStateLike、 SessionStatusLike — 而非具体的会话记录类型。 只要符合必需字段,你自己的消息和片段结构就会原样传递。 classifyPart 和 classifyTurn 是例外。 它们以 Beeuni 的 Part 联合类型(beeuni.transcript.v1)为类型依据,因此其 穷尽性检查会在构建时发现新的片段类型。

分发

npm install @beeuni/sdk

此包以编译后的 ESM 形式发布,并提供完整的 TypeScript 类型声明。 react 和 @tanstack/react-query 是可选的对等依赖。如果 使用 @beeuni/sdk/react,请同时安装两者。

import { createBeeuni } from '@beeuni/sdk'; // framework-free core
import { useSession } from '@beeuni/sdk/react'; // optional React layer
import { createScopedBeeuni } from '@beeuni/sdk/server'; // Node and Bun servers

入口与稳定性

根入口 @beeuni/sdk 是标准入口。它导出完整的 无框架依赖接口,可在浏览器、Node 18+、Bun 和边缘 运行时中运行。

入口 级别 约定
@beeuni/sdk 标准 无框架依赖。绝不导入 React 或 node:*。
@beeuni/sdk/react 受支持 React hooks。唯一导入 React 的入口。
@beeuni/sdk/server 受支持 通过 node:async_hooks 为 Node 和 Bun 服务器提供按请求隔离的配置。切勿将其打包到浏览器中。
旧版子路径(/projects-client、/turns、/files 等) 已弃用 仍可使用。每个子路径都从根入口重新导出。请改为从根入口导入。
@beeuni/sdk/internal/* 内部 仅供 Beeuni Web 应用使用。不是受支持的 API。

CDN 包

此包还提供两个由 tsup 构建的浏览器包:一个 ESM 包 (dist/beeuni.esm.min.js)和一个定义了 window.Beeuni 的 IIFE 全局包(dist/beeuni.global.js)。

<script src="https://unpkg.com/@beeuni/sdk/dist/beeuni.global.js"></script>
<script>
  const beeuni = Beeuni.createBeeuni({
    backendUrl: 'https://api.beeuni.ai/v1',
    getToken: async () => KEY,
  });
</script>

window.Beeuni 暴露的根入口与 npm 导入相同: Beeuni.createBeeuni、Beeuni.classifyTurn、Beeuni.ApiError。

另请参阅

  • SDK — 安装并创建你的第一个会话。
  • 会话 — 生命周期、流式传输和错误处理。
  • React hooks — 基于这些模块构建的响应式层。

智能体仓库访问

智能体配置接受 repository_access?: boolean(默认值为 true)。 设置 false,即可在不访问项目仓库或仓库 API 的情况下运行新会话。 Git、密钥、连接器和工具权限仍独立管理。现有会话保留其已保存的策略。 AgentConfigBlock.workspace 已弃用。SDK 将旧版 branch/runtime 映射到布尔字段。 写入旧版 read 时,必须明确选择 repository_access;这不会启用只读仓库访问。

提供商和模型访问

读取 beeuni.projects.modelAccess(projectId)。使用 beeuni.projects.setModelAccess(projectId, { target: 'provider' | 'model', id, enabled }) 更改一个目标。

对于 Beeuni Managed Models,使用提供商 ID beeuni;对于 BYOK、Codex 和自定义提供商,使用目录中的提供商 ID。对于模型,使用完整的网关传输 ID。禁用提供商会涵盖未来的模型,并保留各模型的偏好设置和已保存的凭据。

禁用当前默认模型及其提供商之前,必须先指定替代项(409 cannot_disable_default)。直接向已禁用目标发送的网关请求会失败,并返回 model_disabled 或 provider_disabled。现有正在处理的上游请求会正常完成。当项目使用原生 运行环境 而非网关时,响应中的 enforced 标志为 false。

React 使用方使用 @beeuni/sdk/react 中的 useModelAccess(projectId)。其 setEnabled(change) 变更操作会刷新管理目录和会话选择器。

这个页面有帮助吗?