Skip to content

TypeScript SDK

@hxsyai/aiadp 是 AI 应用开发平台 OpenAPI 的 TypeScript SDK。它负责请求封装、字段转换、SSE / WebSocket 通信、类型和错误处理;登录、令牌刷新与凭据保存由调用方负责。

  • 当前版本:0.3.0
  • 浏览器:现代浏览器
  • Node.js:18+
  • OpenAPI 地址:https://runtime-api.invalid/v1/openapi

选择引入方式

方式适用场景Tree Shaking页面全局变量
npm / pnpm / yarnVue、React、Node.js、TypeScript 等工程化项目,推荐支持
CDN 全局脚本无构建工具的传统 HTML 页面不支持AIADP
CDN 异步加载希望按需加载 SDK 的页面不支持全量 global 包裁剪AIADP 或 ESM 模块

三种方式提供相同的 Client 和业务能力,区别只在加载与打包方式。

方式一:包管理器安装(推荐)

SDK 发布在公司 Nexus npm 仓库。首次使用时,为 @hxsyai scope 配置仓库地址:

bash
npm config set @hxsyai:registry https://repo.i.huaxisy.com/repository/npm-releases/

安装 SDK:

bash
npm install @hxsyai/aiadp

也可使用 pnpm 或 yarn:

bash
pnpm add @hxsyai/aiadp
# 或
yarn add @hxsyai/aiadp

导入完整客户端:

ts
import { Client } from "@hxsyai/aiadp";

const client = new Client({
  baseUrl: "https://runtime-api.invalid/v1/openapi",
  auth: async () => ({
    Authorization: `Bearer ${await getApiKey()}`,
  }),
});

如果只使用某一类能力,可以从子入口导入,减少应用最终打包体积:

ts
import { ChatClient } from "@hxsyai/aiadp/chat";

const chat = new ChatClient({
  baseUrl: "https://runtime-api.invalid/v1/openapi",
  auth: getAuthHeaders,
});

支持的子入口包括:appschatfilesknowledgeworkflowthirdpartyvoicenode

方式二:CDN 全局脚本

通过普通 script 标签加载:

html
<script src="https://runtime-docs.invalid/sdk/aiadp/aiadp.global.min.js"></script>
<script>
  const client = new AIADP.Client({
    baseUrl: "https://runtime-api.invalid/v1/openapi",
    auth: () => ({
      Authorization: `Bearer ${getApiKey()}`,
    }),
  });
</script>

加载完成后,SDK 暴露在 globalThis.AIADP。该文件是浏览器全量包,不支持 Tree Shaking。

方式三:CDN 异步加载

动态导入 ESM

现代浏览器可以直接动态导入 aiadp.esm.min.js

html
<script type="module">
  const { Client } = await import(
    "https://runtime-docs.invalid/sdk/aiadp/aiadp.esm.min.js"
  );

  const client = new Client({
    baseUrl: "https://runtime-api.invalid/v1/openapi",
    auth: () => ({
      Authorization: `Bearer ${getApiKey()}`,
    }),
  });
</script>

使用异步 Loader

传统页面也可以先加载体积较小的 Loader,再由 Loader 加载 global 包:

html
<script src="https://runtime-docs.invalid/sdk/aiadp/aiadp-loader.min.js"></script>
<script>
  AIADPLoader.load({
    src: "https://runtime-docs.invalid/sdk/aiadp/aiadp.global.min.js",
    expectedVersion: "0.3.0",
    timeout: 15000,
  }).then(({ Client }) => {
    const client = new Client({
      baseUrl: "https://runtime-api.invalid/v1/openapi",
      auth: () => ({
        Authorization: `Bearer ${getApiKey()}`,
      }),
    });
  });
</script>

Loader 会复用同一地址正在进行的加载,并支持超时、CSP nonce、SRI、跨域模式和版本校验。Loader 只负责异步加载,不包含 SDK 业务代码。

本地 HTML 测试

浏览器不能通过 file:// 动态加载 ESM 文件。请将测试页面与 SDK 文件放在静态资源目录中,通过任意 HTTP 静态服务器访问,并确保服务器为 .js 文件返回正确的 JavaScript MIME 类型。

CDN 文件说明

文件完整访问地址用途
aiadp.global.min.jshttps://runtime-docs.invalid/sdk/aiadp/aiadp.global.min.js普通 script 标签使用的全量包,暴露 globalThis.AIADP
aiadp.esm.min.jshttps://runtime-docs.invalid/sdk/aiadp/aiadp.esm.min.js供现代浏览器 import / import() 使用的 ESM 全量包
aiadp-loader.min.jshttps://runtime-docs.invalid/sdk/aiadp/aiadp-loader.min.js异步加载 aiadp.global.min.js 的小型加载器
manifest.jsonhttps://runtime-docs.invalid/sdk/aiadp/manifest.json当前版本与 CDN 文件清单

ESM 跨域加载

业务页面与文档站不同源时,浏览器动态导入 aiadp.esm.min.js 还要求文档站响应允许 CORS。如果部署环境未开启 CORS,请使用 aiadp.global.min.js 或 Loader 方式。

鉴权

SDK 不接管登录、令牌刷新或凭据保存。调用方通过 auth(context) 返回当前请求需要的请求头:

ts
const client = new Client({
  baseUrl: "https://runtime-api.invalid/v1/openapi",
  auth: async (context) => {
    const apiKey = await credentialStore.getApiKey();

    return {
      Authorization: apiKey.startsWith("Bearer ") ? apiKey : `Bearer ${apiKey}`,
    };
  },
});

auth() 会在每次请求时调用,并且可以返回 Promise,因此可接入调用方已有的令牌刷新逻辑。context 包含 methodpathoperation 和当前重试次数 attempt

固定请求头也可以通过 headers 传入,但不适合需要刷新的凭据:

ts
const client = new Client({
  baseUrl: "https://runtime-api.invalid/v1/openapi",
  headers: {
    Authorization: `Bearer ${apiKey}`,
  },
});

浏览器凭据安全

写入网页 JavaScript、HTML、Local Storage 或请求头的 API Key 都可以被浏览器用户查看。auth() 用于统一管理和动态获取凭据,并不能在浏览器中隐藏凭据。不要把长期有效或高权限密钥提交到前端源码;生产环境应根据安全要求使用受限密钥、短期凭据或由自己的服务端代理请求。

应用列表

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);
}

JavaScript SDK 对外统一使用 camelCase,例如请求中的 pageSize 和响应中的 appType;发送给 OpenAPI 时会自动转换为接口字段。

应用详情会把 app_schema 解码为有类型的 appSchema。脚手架可以直接使用变量、模型、工具和技能信息生成运行界面:

ts
const app = await client.apps.detail({ appId: "<your-app-id>" });

for (const variable of app.appSchema?.prompt?.variables ?? []) {
  renderInput({
    key: variable.key,
    label: variable.name,
    required: variable.required,
    dataType: variable.dataType,
    options: variable.options,
  });
}

console.log(app.appSchema?.freeModels);
console.log(app.appSchema?.toolList);
console.log(app.appSchema?.skillList);
console.log(app.appSchema?.versionMeta?.version);

appSchema.versionMeta 提供版本号、版本名称、版本说明、是否最新/草稿/自动版本及发布时间;顶层 app.version 同步取自该元数据中的版本号。

Agent / AgentLite 流式对话

先绑定应用类型、应用 ID 和业务用户 ID,再发送消息:

ts
const agent = client.chat.bind({
  appType: "agent", // AgentLite 使用 'agentLite'
  appId: "<your-app-id>",
  userId: "user-1",
});

const stream = await agent.sendMessagesStream({ query: "你好" });

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: 'aggregate'

ts
const stream = await agent.sendMessagesStream(
  { query: "你好" },
  { outputMode: "aggregate" },
);

for await (const { event, message } of stream) {
  renderMessage(message);
  // message.content、thinking、items、toolCalls、subAgents 会持续更新
  // message.usage 保留 promptTokens、completionTokens、totalTokens 及耗时
  // event 仍保留,便于处理 TTS、HITL 等特殊事件
}

outputMode 只控制 SDK 的返回形式,不会发送给后端。默认值为 raw,因此旧代码无需修改。

实时聚合结果与历史消息都使用 ChatMessage 结构。同一个消息组件可以直接渲染历史数据:

ts
const messages = await client.chat.history({
  appId: "<your-app-id>",
  conversationId,
  pageSize: 100,
});

messages.forEach(renderMessage);

message.items 按后端 sort_order 排序,包含思考、正文、工具和子 Agent 等过程项。

SDK 不会在断流后自动重连。业务方应保存流中的 taskIdstream.lastEventId,需要恢复时显式调用:

ts
const stream = await agent.reconnectStream({
  taskId,
  lastEventId,
});

收到 interrupt 事件后,由业务界面收集用户输入并恢复执行:

ts
const resumed = await agent.resumeStream({
  conversationId: interruptEvent.conversationId,
  checkpointId: interruptEvent.data.checkpointId,
  responses: {
    [interruptEvent.data.interrupts[0].interruptId]: {
      type: "confirm",
      confirm: true,
    },
  },
});

聚合模式恢复或重连时,把上一段消息作为 initialMessage 传入即可继续累积,不需要业务层重新拼接:

ts
const resumed = await agent.resumeStream(
  {
    conversationId: interruptEvent.conversationId,
    checkpointId: interruptEvent.data.checkpointId,
    responses,
  },
  {
    outputMode: "aggregate",
    initialMessage: stream.message,
  },
);

停止生成:

ts
await client.chat.stop(taskId);

文本生成

文本生成应用使用 textCompletion 类型。阻塞调用直接返回最终结果:

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);

也可以使用 SSE 流式生成:

ts
const stream = await text.sendMessagesStream({
  input: { title: "季度报告", tone: "正式" },
});

try {
  for await (const event of stream) {
    if (event.type === "chunk") console.log(event.data.content);
  }
} finally {
  await stream.close();
}

文本生成流同样支持 { outputMode: 'aggregate' }。它返回统一的 ChatMessage,但仍不提供多轮会话和 HITL 恢复。

查询当前应用的生成记录和单条详情:

ts
const records = await text.records({
  page: 1,
  pageSize: 10,
});

for (const record of records.items) {
  console.log(record.id, record.status, record.totalTokens, record.duration);
}

const detail = await text.recordDetail({
  completionId: records.items[0].id,
});

console.log(detail.input, detail.content);
for (const item of detail.items) {
  console.log(item.sortOrder, item.itemType, item.content.text);
}

records() 对应文本生成记录列表,状态为 0 执行中、1 成功、2 失败、3 取消;recordDetail() 返回提交时的 input、完整 content 和已按 sortOrder 升序排列的过程片段。

文本生成不支持会话、HITL 恢复或断流重连。

取消、超时与重试

HTTP 和 SSE 方法的最后一个参数可以传入请求选项:

ts
const controller = new AbortController();

const request = client.apps.list(
  { page: 1, pageSize: 10 },
  {
    signal: controller.signal,
    timeout: 15000,
    retry: { maxRetries: 2, baseDelay: 500 },
  },
);

controller.abort();
await request;

只读、可重试请求默认会在网络错误或 502503504 时重试;发送消息等非幂等请求不会自动重试。

SSE 将建立连接和读取事件分开控制:

ts
const controller = new AbortController();
const stream = await agent.sendMessagesStream(
  { query: "你好" },
  {
    signal: controller.signal,
    connectTimeout: 10000,
    idleTimeout: 30000,
  },
);
  • connectTimeout:等待 SSE 响应建立的最长毫秒数;未传时依次使用请求 timeout、客户端 streamConnectTimeout,最后默认 10 秒。
  • idleTimeout:连接建立后等待下一条完整 SSE 事件的最长毫秒数;默认不启用,传 0 也表示不启用。服务端 ping 事件即使未通过迭代器输出,也会刷新空闲计时。
  • signal:建立连接或读取过程中取消请求。超时抛出 TimeoutError,主动取消抛出 AbortError,并保留对应的 operation

语音 WebSocket 流式接口也支持连接超时和取消:

ts
const controller = new AbortController();
const session = await client.voice.recognizeStream(
  { provider: "provider-id" },
  { signal: controller.signal, connectTimeout: 5000 },
);

单次 connectTimeout 优先于客户端 webSocketConnectTimeout,两者均未设置时默认 10 秒。连接超时或取消会关闭尚未打开的 WebSocket。自定义 webSocketFactory 的第三个参数包含 headersoperationsignal 和最终生效的 connectTimeout。浏览器原生 WebSocket 无法添加 upgrade 请求头,需要自定义 factory 或按网关约定接入。

错误处理

建议使用稳定的 kindoperationhttpStatuscode 判断错误:

ts
import { AiAdpError } from "@hxsyai/aiadp";

try {
  await client.apps.list();
} catch (error) {
  if (error instanceof AiAdpError) {
    console.error({
      kind: error.kind,
      operation: error.operation,
      httpStatus: error.httpStatus,
      code: error.code,
      traceId: error.traceId,
    });
  } else {
    throw error;
  }
}

使用 CDN 全局脚本时,错误基类位于 AIADP

js
if (error instanceof AIADP.AiAdpError) {
  console.error(error.kind, error.operation, error.httpStatus);
}

kind 可能为:configurationapihttptransporttimeoutabortdecodestreamunsupported_runtimemissing_dependency

其他能力

完整客户端还提供以下命名空间:

命名空间能力
client.apps应用列表、详情、运行参数
client.chatAgent、AgentLite、文本生成、生成记录、会话和消息历史
client.filesAgent 工作空间文件操作
client.knowledge知识库列表、详情和检索
client.workflow工作流阻塞与流式执行
client.thirdparty三方服务、工具列表和调用
client.voice语音合成、识别、音色及 WebSocket 流式能力

接口请求字段和响应含义以对应的 OpenAPI 接口文档 为准。

AI 应用开发平台 - 面向医疗场景的 AI 应用创新引擎