Appearance
微信小程序 SDK
@hxsyai/aiadp-miniprogram 是 AI 应用开发平台 OpenAPI 的微信小程序 SDK。它提供与 TypeScript SDK 一致的业务命名空间,并使用 wx.request、wx.uploadFile、wx.downloadFile 和 wx.connectSocket 适配小程序运行环境。
SDK 负责请求封装、字段转换、分块 SSE、WebSocket、类型和错误处理;微信登录、令牌刷新、凭据保存、录音、播放和页面渲染由接入方负责。
环境要求
接入前需要准备:
- OpenAPI 地址:
https://runtime-api.invalid/v1/openapi - 平台签发的 API Key 或业务侧短期访问令牌
- 支持
enableChunked、RequestTask.onChunkReceived和SocketTask的微信小程序基础库
凭据安全
不要把 AppSecret、管理员令牌、长期高权限 API Key 或 Nexus 发布凭据写入小程序代码。小程序包可以被下载和分析,应由业务登录流程换取受限、短期的访问凭据。
安装
SDK 发布在公司 Nexus npm 仓库。在小程序项目的 .npmrc 中配置只读仓库:
ini
@hxsyai:registry=https://repo.i.huaxisy.com/repository/npm-releases/安装最新版本:
bash
npm install @hxsyai/aiadp-miniprogram安装后,在微信开发者工具中执行“工具 → 构建 npm”。业务代码只需从包入口导入,不要直接引用包内 dist 文件:
ts
import { Client } from "@hxsyai/aiadp-miniprogram";创建客户端
ts
import { Client } from "@hxsyai/aiadp-miniprogram";
const client = new Client({
baseUrl: "https://runtime-api.invalid/v1/openapi",
auth: async () => ({
Authorization: `Bearer ${await getAccessToken()}`,
}),
timeout: 30_000,
streamConnectTimeout: 10_000,
streamRequestTimeout: 30 * 60 * 1000,
webSocketConnectTimeout: 10_000,
});auth(context) 会在每次 HTTP、SSE 或 WebSocket 请求前执行,可以接入业务侧已有的登录态和令牌刷新流程。它可返回普通对象或 Promise,context 包含 method、path、operation 和重试次数 attempt。
固定请求头也可以通过 headers 配置,但不适合需要刷新的令牌:
ts
const client = new Client({
baseUrl: "https://runtime-api.invalid/v1/openapi",
headers: {
Authorization: `Bearer ${accessToken}`,
},
});普通 API
apps、chat、knowledge、workflow 和 thirdparty 与 TypeScript SDK 使用相同的方法、请求类型和响应类型。例如查询应用:
ts
const result = await client.apps.list({
appType: 2,
keyword: "助手",
page: 1,
pageSize: 10,
});
for (const app of result.items) {
console.log(app.id, app.name, app.appType);
}SDK 对外统一使用 camelCase,发送给 OpenAPI 时自动转换为接口字段。
Agent / AgentLite 流式对话
先绑定应用类型、应用 ID 和业务用户 ID:
ts
const agent = client.chat.bind({
appType: "agent", // AgentLite 使用 "agentLite"
appId: "<your-app-id>",
userId: "user-1",
});原始事件
sendMessagesStream() 默认返回 raw 原始事件:
ts
const stream = await agent.sendMessagesStream(
{ query: "你好" },
{ outputMode: "raw", idleTimeout: 30_000 },
);
try {
for await (const event of stream) {
if (event.type === "chunk") {
console.log(event.data.content);
}
if (event.type === "interrupt") {
console.log("等待用户操作", event.data);
}
}
} finally {
await stream.close();
}不传 outputMode 时同样默认为 raw。原始流包含正文、思考、工具调用、子 Agent、沙箱、Token 用量、打断、完成和失败等强类型事件。
聚合消息
页面希望直接获得可渲染消息时,使用 aggregate:
ts
const stream = await agent.sendMessagesStream(
{ query: "你好" },
{ outputMode: "aggregate", idleTimeout: 30_000 },
);
try {
for await (const { event, message } of stream) {
renderMessage(message);
// event 仍保留,可用于 TTS、HITL 等需要原始事件的场景
}
} finally {
await stream.close();
}message 会持续累积 content、thinking、items、toolCalls、subAgents 和 usage。它与 client.chat.history() 返回的消息结构一致。
页面更新
SSE 事件可能到达得很频繁。不要每收到一个 token 就调用一次 setData,应在页面层按时间窗口或字符数量节流,避免频繁渲染影响真机性能。
停止、恢复与断流重连
停止当前任务:
ts
await client.chat.stop(taskId);收到 interrupt 事件后,由页面收集用户输入,再显式恢复:
ts
const resumed = await agent.resumeStream({
conversationId: interruptEvent.conversationId,
checkpointId: interruptEvent.data.checkpointId,
responses: {
[interruptEvent.data.interrupts[0].interruptId]: {
type: "confirm",
confirm: true,
},
},
});SDK 不会自动重连。业务方应保存 taskId 和 stream.lastEventId,确认需要恢复后调用:
ts
const reconnected = await agent.reconnectStream({
taskId,
lastEventId: stream.lastEventId,
});resumeStream() 和 reconnectStream() 同样支持 raw 与 aggregate。聚合模式需要延续上一段消息时,传入 initialMessage: stream.message。
文本生成
文本生成应用支持阻塞与流式调用:
ts
const text = client.chat.bind({
appType: "textCompletion",
appId: "<your-app-id>",
userId: "user-1",
});
const result = await text.sendMessages({
input: {
title: "季度报告",
tone: "正式",
},
});
console.log(result.output.content);ts
const stream = await text.sendMessagesStream(
{ input: { title: "季度报告", tone: "正式" } },
{ outputMode: "raw" },
);
try {
for await (const event of stream) {
if (event.type === "chunk") console.log(event.data.content);
}
} finally {
await stream.close();
}文本生成流也可以使用 { outputMode: "aggregate" },并支持 records() 和 recordDetail() 查询生成记录。
工作流
阻塞执行:
ts
const result = await client.workflow.invoke({
workflowId: "<workflow-id>",
input: { question: "总结检查结果" },
});
console.log(result.finalOutput);流式执行:
ts
const stream = await client.workflow.invokeStream(
{
workflowId: "<workflow-id>",
input: { question: "总结检查结果" },
},
{ idleTimeout: 30_000 },
);
try {
for await (const event of stream) {
console.log(event.type, event.data);
}
} finally {
await stream.close();
}文件上传与下载
小程序不能使用浏览器 Blob 或 FormData 上传本地文件。先通过微信 API 获得本地临时路径,再传给 SDK:
ts
const chooseResult = await wx.chooseMessageFile({
count: 1,
type: "file",
});
const selected = chooseResult.tempFiles[0];
const file = await client.files.upload({
userId: "user-1",
filePath: selected.path,
fileName: selected.name,
path: `/reports/${selected.name}`,
});
console.log(file.path);wx.uploadFile 不能像浏览器 FormData 一样单独指定 multipart 文件名,因此 SDK 会额外发送 file_name 表单字段。
下载返回微信临时文件路径:
ts
const download = await client.files.download({
userId: "user-1",
path: "/reports/report.pdf",
});
console.log(download.tempFilePath);
wx.openDocument({ filePath: download.tempFilePath });tempFilePath 由微信管理,需要长期保存时,请使用微信文件系统 API 复制到业务目录。
分片上传
ts
const initialized = await client.files.multipart.init({
userId: "user-1",
path: "/reports/archive.zip",
totalChunks: chunkFilePaths.length,
});
const parts = [];
for (let index = 0; index < chunkFilePaths.length; index += 1) {
parts.push(await client.files.multipart.part({
userId: "user-1",
path: "/reports/archive.zip",
uploadId: initialized.uploadId,
partNumber: index + 1,
filePath: chunkFilePaths[index],
}));
}
await client.files.multipart.complete({
userId: "user-1",
path: "/reports/archive.zip",
uploadId: initialized.uploadId,
parts,
});SDK 负责分片接口通信,不负责把一个大文件切成多个本地临时文件;切片过程由接入方结合微信文件系统 API 完成。
语音
非流式 TTS/STT 与 TypeScript SDK 参数一致:
ts
const synthesized = await client.voice.synthesize({
provider: "provider-id",
text: "检查结果正常",
voiceCode: "voice-code",
format: "mp3",
});
const recognized = await client.voice.recognize({
provider: "provider-id",
audioData: base64Audio,
sampleRate: 16_000,
});流式语音使用 wx.connectSocket()。SDK 负责鉴权、连接、音频帧和错误处理;麦克风授权、录音采样和播放由接入方负责。
ts
const session = await client.voice.recognizeStream(
{
provider: "provider-id",
sampleRate: 16_000,
},
{ connectTimeout: 10_000 },
);
session.sendAudio(frameArrayBuffer);
for await (const result of session) {
console.log(result.text, result.isFinal);
}页面卸载或不再使用时应关闭会话:
ts
await session.close();超时、取消与重试
普通 HTTP 方法支持请求级超时、取消、请求头覆盖和重试选项:
ts
const controller = new AbortController();
const request = client.apps.list(
{ page: 1, pageSize: 10 },
{
signal: controller.signal,
timeout: 15_000,
retry: { maxRetries: 2, baseDelay: 500 },
},
);
controller.abort();
await request;只读、可重试请求默认在网络错误或 502、503、504 时重试;发送消息、上传等非幂等请求不会自动重试。
流式请求还支持:
connectTimeout:等待响应头或首个分块的时间,默认 10 秒;idleTimeout:连接建立后等待下一条完整 SSE 事件的时间,默认关闭;streamRequestTimeout:单次微信分块请求的总生命周期,客户端默认 30 分钟;signal:取消后调用对应微信任务的abort()。
如果目标基础库没有原生 AbortController,可以传入符合 SDK AbortSignalLike 接口的实现。
错误处理
ts
import {
AiAdpError,
AbortError,
TimeoutError,
} from "@hxsyai/aiadp-miniprogram";
try {
await client.apps.list();
} catch (error) {
if (error instanceof TimeoutError) {
console.error("请求超时");
} else if (error instanceof AbortError) {
console.error("请求已取消");
} else if (error instanceof AiAdpError) {
console.error({
kind: error.kind,
operation: error.operation,
httpStatus: error.httpStatus,
code: error.code,
traceId: error.traceId,
});
} else {
throw error;
}
}kind 可能为 configuration、api、http、transport、timeout、abort、decode、stream 或 unsupported_runtime。
小程序后台配置
在微信公众平台分别配置实际使用的合法域名:
| 微信网络能力 | SDK 用途 |
|---|---|
| request 合法域名 | 普通 API、Chat SSE、Workflow SSE |
| uploadFile 合法域名 | 普通上传、分片上传 |
| downloadFile 合法域名 | 文件和目录下载 |
| socket 合法域名 | 流式 TTS/STT |
正式环境必须使用 HTTPS 和 WSS。流式接口所在网关需要关闭响应缓冲,否则客户端可能在请求结束后一次性收到全部事件。
Chat 和 Workflow 流默认关闭 HTTP/2,以减少不同真机的分块兼容差异。确认目标基础库和网关兼容后,可以在客户端设置 streamEnableHttp2: true。
小程序进入后台后,网络任务可能被暂停或断开。建议:
- 页面卸载时关闭 Chat、Workflow 和语音流;
- 保存业务需要的
taskId、lastEventId和聚合消息; - 页面恢复后根据任务状态显式调用
reconnectStream(),不要无限自动重试; - 将网络错误与主动取消分别提示。
与 TypeScript SDK 的差异
业务命名空间、普通接口、Chat 事件和 Workflow 事件保持一致,平台相关能力使用小程序语义:
| 能力 | TypeScript SDK | 微信小程序 SDK |
|---|---|---|
| 包名 | @hxsyai/aiadp | @hxsyai/aiadp-miniprogram |
| HTTP | fetch | wx.request |
| SSE | Web Stream | enableChunked + onChunkReceived |
| 上传输入 | Blob / ArrayBuffer | filePath |
| 下载输出 | 二进制响应 | tempFilePath |
| WebSocket | 原生 WebSocket / ws | wx.connectSocket |
完整的请求字段和响应含义以对应的 OpenAPI 接口文档 为准。
