Qoni SDK
本页说明当前公开的 Qoni SDK、安装要求、能力范围、最小调用方式、任务句柄与错误处理,并明确其他语言 SDK 的公开状态。
当前可用版本
Qoni 当前公开的统一 SDK 是 Node.js / TypeScript 包 @qoniai/qoni,源代码位于 QoniAI/qoni-sdk-node。
| 项目 | 当前状态 |
|---|---|
| npm 包 | @qoniai/qoni |
| GitHub 仓库 | QoniAI/qoni-sdk-node |
| 当前公开版本 | 0.4.0 |
| 运行环境 | Node.js 18 或更高版本,服务端运行时需要提供 fetch |
| 模块格式 | ESM、CommonJS 和 TypeScript 类型声明 |
| License | MIT |
服务端凭证
Qoni accessKey 和 secretKey 只能保存在可信服务端。不要把它们打包进浏览器、移动应用、公开 CLI 配置或不受信任的 Agent 运行时。
SDK 覆盖范围
统一 SDK 从 Qoni 提供以下能力:
| Namespace | 用途 |
|---|---|
genauth | 获取当前用户信息,以及管理 GenAuth 用户 |
gumem | 创建 Session、写入消息、召回 Memory、上传资源和记录 Action |
doAnything | 启动或重新连接通用 Web Agent 任务 |
webSearch | 执行公开网页搜索并读取结果 |
deepResearch | 执行长时间研究任务并下载产物 |
track | 创建、查询、暂停、恢复和执行监控任务 |
运行时产品调用使用短期委托令牌。SDK 会负责运行时发现和下游产品令牌兑换,应用代码不应自行拼接内部 /api/v3/eak/* 路径或内部 claim。
安装
npm install @qoniai/qoni也可以使用 pnpm 或 Yarn:
pnpm add @qoniai/qoni
# 或
yarn add @qoniai/qoni初始化客户端
import { Qoni, QoniScopes } from "@qoniai/qoni";
const qoni = new Qoni({
accessKey: process.env.QONI_ACCESS_KEY!,
secretKey: process.env.QONI_SECRET_KEY!,
});私有部署或本地部署可以传入 host,它应指向 Qoni Console / SDK gateway,而不是单独的 GenAuth、Web Agent 或 GUMem 地址。使用 Qoni 托管服务时不需要设置 host。
Qoni 支持以下选项:
| 选项 | 必填 | 说明 |
|---|---|---|
accessKey | 是 | Qoni Console 中创建的 access key |
secretKey | 是 | Qoni Console 中创建的 secret key |
host | 否 | 私有部署的 Qoni 网关地址,覆盖默认的服务运行时发现 |
fetch | 否 | 自定义 fetch 实现,用于代理或测试环境 |
timeoutMs | 否 | 单次请求超时时间,默认 30000;事件流等待不受此限制 |
sseMaxRetries | 否 | 事件流断线自动重连次数上限,默认 5,设为 0 关闭 |
获取委托令牌
Web Agent 和 GUMem 产品代表终端用户执行操作。静默委托必须传入与当前 Qoni 凭证绑定的 GenAuth 用户 ID:
const { token } = (
await qoni.delegateToken({
user: { id: process.env.QONI_USER_ID! },
agent: "research-assistant",
products: ["webSearch"],
scopes: [QoniScopes.GUMEM_MEMORY_READ, QoniScopes.GUMEM_MEMORY_WRITE],
})
).data;对于站点登录、浏览器接管、长期监控或敏感产物等高风险操作,优先使用 mode: "interactive",让用户在 Qoni Console 中确认授权。交互式授权在服务端通过 completeDelegateToken({ grantId, code, state }) 完成,委托令牌不会暴露给浏览器。
细粒度权限通过 scopes 声明,格式为 <namespace>.<resource>:<verb>,例如 webagent.web_search:read。Web Agent 每个产品只有 read 和 manage 两个动词;也可以用 products: ["webSearch"] 简写一次申请整个产品。SDK 导出 QoniScopes 常量与 QoniScopeBundles 预置组合(如 GUMEM_SESSION_RECALL),避免手拼 scope 字符串;格式错误的 scope 会在本地抛出 QoniValidationError。响应中的 grantedScopes、grantId 和 auditId 可用于应用的审计记录。
调用 Web Search
const search = await qoni.webSearch.run({
token,
prompt: "Qoni SDK documentation",
maxResultsPerQuery: 5,
});
const result = await search.wait();
console.log(result.output);run() 返回可重新连接的 handle。长任务可以保存 run.id,之后使用 qoni.webSearch.attach(run.id, { token }) 重新连接。
调用 GUMem
申请 GUMem 所需权限后,可以创建 Session、写入已确认的用户信息并召回相关上下文:
await qoni.gumem.createSession({
token,
userId: process.env.QONI_USER_ID!,
sessionId: "daily-assistant",
title: "Daily assistant memory",
});
await qoni.gumem.addMessages({
token,
sessionId: "daily-assistant",
messages: [
{ role: "user", content: "Keep planning suggestions concise." },
],
});
const { data: context } = await qoni.gumem.recall({
token,
sessionId: "daily-assistant",
query: "What preferences should the assistant follow?",
details: true,
});任务句柄与事件流
doAnything、webSearch 和 deepResearch 的 run() 都返回可重连的任务句柄 RunHandle:
| 成员 | 用途 |
|---|---|
wait({ onScreenshot, onInteraction, timeoutMs }) | 等待任务完成,可在回调中消费步骤截图和交互请求 |
events() | 异步迭代类型化事件流,收到终端 done 事件后结束 |
status() | 查询当前运行状态 |
cancel(reason) | 取消任务 |
sessionRef | 传给下一次 run({ session }) 以复用会话 |
run.id 与 attach() | 保存运行 ID 后随时重连长任务 |
事件流断线时 SDK 使用 Last-Event-ID 自动重连续传。常见事件类型包括 progress、message、screenshot、interaction 和 done,常量见 QoniEventTypes;需要原始 wire 事件时可读取 event.raw。
for await (const event of run.events()) {
if (event.type === "progress") appendTrace(event.data);
if (event.type === "screenshot") renderScreenshot(event.image);
if (event.type === "interaction") handleInteraction(event.data);
if (event.type === "done") return event.data.output;
}人机协同交互
Web Agent 任务可能需要用户参与。SDK 把这类步骤统一建模为 interaction,类型包括 site_login、clarification、confirmation、take_control 和 wait(常量 InteractionTypes)。在 wait({ onInteraction }) 或事件流中拿到 interaction 后,先用 can(kind) 检查可用动作,再调用对应方法,例如 answer()、confirm()、reject()、openLogin() 或 confirmSignedIn()。调用未声明的动作会抛错,避免对用户会话误操作。
错误处理
所有 SDK 错误继承 QoniError,携带 code、status、requestId、traceId、auditId 和 retryable 标志。普通 HTTP 请求不会自动重试,retryable 为 true 的错误由应用决定重试策略;events() 的 SSE 事件流会按照 sseMaxRetries 自动重连。
| 错误类 | 触发场景 |
|---|---|
QoniValidationError | 本地输入校验失败,例如 scope 格式错误或静默委托缺少 user |
QoniAuthError | accessKey / secretKey 签名被拒绝 |
QoniPermissionDeniedError | 委托令牌缺少所需 scope(HTTP 403) |
QoniTokenExpiredError | 委托令牌已过期 |
QoniDelegationRequiredError | 产品调用缺少 token,或令牌未被网关接受 |
QoniRateLimitError | 触发限流(HTTP 429) |
QoniTimeoutError | 请求或 wait() 超时;任务在服务端继续执行,可 attach() 重连 |
QoniUpstreamError | 下游产品服务错误 |
从 0.4.0 之前的版本迁移
0.4.0(2026-08-18)是一次破坏性重命名版本,服务端 wire 契约保持不变:
- 包名从
@eazo/anima改为@qoniai/qoni,推荐的主构造器统一为Qoni,环境变量统一为QONI_*前缀。公开的0.4.0仍保留旧的长名称构造器导出作为兼容别名;新代码应只使用Qoni。 delegateAgent/completeDelegateAgent已弃用,改用delegateToken/completeDelegateToken;交互式回调必须携带grantId,旧的{ code, state }形式不再支持。delegateToken的顶层userId已弃用,改用user: { id };构造器选项accessKeyId改为accessKey。- 网关路由仍位于
/api/v3/eak/*,token claim 与eak.*错误码保持原样,应用不应自行构造这些内部值。
其他 SDK 的公开状态
截至 2026 年 8 月 19 日,QoniAI GitHub 组织只有 qoni-sdk-node 一个公开 SDK 仓库。当前没有在该组织下发现 Qoni Python、Java、Go、PHP 或 C# 统一 SDK。
文档中独立出现的 GUMem SDK、Web Agent SDK 或 GenAuth SDK 属于对应产品的接入资料或历史 SDK,不等同于已经在 QoniAI 组织公开的 Qoni 统一 SDK。选择生产依赖前,应同时确认包注册表、源代码仓库和发布版本;不要根据文档中的示例包名推断它已经公开发布。
检查结果
完成安装后,可以检查 npm 是否能解析当前版本:
npm view @qoniai/qoni version然后确认应用只从服务端读取 QONI_ACCESS_KEY、QONI_SECRET_KEY,并使用真实的 GenAuth 用户 ID 发起静默委托。
下一步
- 阅读 Quickstart 了解身份、Memory 和 Web Agent 的组合流程。
- 查看
qoni-sdk-nodeREADME 获取完整 API surface、错误类型和事件模型。