Quickstart 在 Node 服务端使用固定版本 qca-sdk@0.5.0。浏览器的请求信封、SSE 和语音连接仍访问 Quickstart;本地 Express 与 Vercel 入口复用同一个实现。项目的 Node 要求高于 SDK 的 20.12 最低要求。
| 位置 | 职责 |
|---|---|
server/src/qca/clients.ts |
为每次请求、每条连接创建独立 client,显式传递环境与 PAT/SAT |
server/src/qca/dispatch.ts |
将本地请求映射到 SDK 资源方法,保留业务 payload 和原始响应 |
server/src/qca/extensions.ts |
SDK 暂未提供资源方法的显式兼容清单 |
server/src/qca/http.ts |
HTTP 状态、错误、request ID、期限与断开取消 |
server/src/qca/transfers.ts |
multipart、文件元数据和二进制预览 |
server/src/qca/stream.ts |
SSE 原始字节转发、背压与会话结束判断 |
server/src/voiceProxy.ts |
本地 WebSocketServer;用 SDK connect/sendEvent/事件迭代访问 QCA |
例如,Forward Session 创建对应以下 SDK 调用:
import { ForwardClient } from 'qca-sdk';
const client = new ForwardClient({
baseURL: 'https://api.qoder.com.cn/api/v1/forward',
authMode: 'sa',
accessToken: forwardSAT,
timeout: 30_000,
maxRetries: 0,
});
const response = await client.sessions.create(
{ identity_id: identityId, template_id: templateId, incremental_streaming_enabled: true },
{ idempotencyKey, signal },
).asResponse();代码中的 token、资源 ID、幂等键和 signal 来自当前请求。PAT 使用 { authMode: 'pat', pat };CN/Global 地址继续由已有环境配置控制。SDK 自动重试关闭,写操作继续使用浏览器生成的幂等键,避免迁移改变重复发送行为。SDK 的 .asResponse() 保留 HTTP 状态与 wire DTO,包括 204、专用 Realtime 历史页和扩展字段。
SA 登录使用 forward.serviceAccountTokens.create({ saKey, ... }),返回完整 Forward SAT 签发信息。SA Key 只作为签发方法的当次参数;后续请求使用签发得到的 SAT。现有 Identity SAT 签发分支也已映射到 SDK。页面没有新增吊销功能。
SDK ServiceAccountCredential 的平台交换链路与此不同。Realtime 需要 Forward 签发的绑定 SAT,因此本项目继续保留 Forward 登录方式。静态 SAT 过期后需要重新登录。
JSON、上传、预览、SSE 及 proxy.auth 都会传递 authMode;旧页面未传此字段时保留 PAT 兼容默认。SDK client 不跨用户共享;不默认读取进程凭据来执行普通业务请求。历史文件的 Cloud 回退仍由客户端按现有 PAT/404 条件触发。
当前页面需要两类 SDK request() 适配:
GET /resources:保留注册资源列表语义。- Forward/Cloud
GET /files/{id}/content:仅返回签名 URL;files.download()用于需要文件字节的预览,SDK 不会向存储请求附带 API token。
为保持旧导出函数可调用,显式保留 8 个兼容操作:Identity access_tokens 的查询/创建/删除,Resource 注册/删除,Vault 更新/归档,Schedule DELETE。页面没有使用这些功能;保留传输不表示目标服务已经实现它们。未知接口返回明确的 404,不做任意路径转发。
语音 Conversation 创建和历史查询使用 SDK 原生方法。创建时幂等键进入 header;历史页保留 conversation/events/page,多页恢复仍由浏览器负责。
上游语音连接使用 forward.realtime.connect(),仅支持 Node。浏览器负责录音重采样、播放、断线恢复和结束确认。代理只有一个 SDK 事件消费者,转发完整事件及原关闭 request_id;不会再次发起 closeGracefully 或自动重放输入。SDK 在 ready 后才返回连接,初始化阶段的事件随后按顺序送达浏览器。若迭代结束且未收到对应关闭确认,代理请求浏览器恢复连接,覆盖服务端正常关闭 transport 的重启场景。
SDK 校验事件、序号和音频格式;旧的简化 mock 报文不可用。初始化有总计 30 秒期限,浏览器断开会取消上游,部署的 280 秒连接轮换保留。SDK 内部队列有界,下游也保留缓冲限制。SDK 不改变 Vercel 的部署条件,仍需按 README 配置并在目标环境验收。
Skill 使用推荐的 files multipart 字段,名称和描述来自 ZIP 内的 SKILL.md。普通文件保留文件名、MIME、purpose 和对象 metadata。SSE 直接转发原始字节;子线程 idle 不关闭主会话流。
部分 Agent 产物的 Forward 元数据返回 404,但其内容接口允许下载。产物卡片在此情形下继续尝试经过鉴权的内容预览;若存储只返回 application/octet-stream,通过 PNG/JPEG/GIF/WebP/BMP/AVIF 文件头识别图片。未知格式仍显示下载卡片,元数据 401/403 不触发此降级。
Usage 的时间参数改为 Asia/Shanghai 整点 start_at/end_at,左闭右开,最大 744 小时;页面明确显示统计截止时间。时长使用 active_seconds,保留小数和缺失 credits。汇总读取全部分页,账本翻页复用同一时间窗口并使用 created_at[lt] 上界。账本按 Session 创建时间筛选,与跨窗口执行的小时聚合不保证精确对账。
平均每会话使用官方汇总的 credits/session_count;明细是否全部加载使用 Session 分页的 has_more,不以汇总会话数作为明细总数。每日趋势与明细小计来自已加载的会话累计消耗。
在仓库根目录执行:
npm run test --workspace=client
npm run test --workspace=server
npm run build --workspace=client
npm run build --workspace=server
npm run test:deployment测试使用真实 SDK、注入 fetch 和本地 HTTP/WebSocket 上游,不需要真实 token,不访问 QCA。覆盖请求隔离、签发、错误码、上传/预览、SSE、语音生命周期和 Usage。部署测试比较本地构建与真实 Vercel API 导出在本地适配器中的行为,不模拟 Vercel 基础设施。
真实服务的验证范围见下方记录;Global、PAT 和 Vercel 在线部署仍需要单独验收。
- 客户端:214 项测试通过;服务端:32 项通过;本地/Vercel 入口对照:6 项通过,共 252 项。
- client/server 构建通过;Usage/文件相关测试另外在 TZ=UTC 下通过。
git diff --check通过。- 全量前端 lint 仍有 4 个错误、2 个警告,均来自改造前已有的 App/batchPanel 规则问题;已对照远程 main 基线,本次修改未增加 lint 问题。
- npm audit 仍报告已有依赖的漏洞;涉及包版本与 main 一致,新增 qca-sdk 和升级的 ws 未出现在本次审计问题清单中。未在本次迁移中扩大依赖升级范围。
- 中国站 Service Account 已完成主要功能真实联调,包括用户实际说话并听到语音回复。图片预览和用量展示问题已修复并在真实页面复测。
- Schedule 管理与执行接口成功,但两次运行均未按初始消息返回指定文本,根因尚未确定。此项不能标为完整通过。
- 详细范围、证据、保留的测试资源与未测项见 SDK 迁移测试记录。