@streamcore/js-sdk
v0.1.8
Published
Framework-agnostic SDK for connecting to a Pion Voice Agent server via WebRTC + WHIP
Maintainers
Readme
@streamcore/js-sdk
English | 简体中文
框架无关的 TypeScript SDK,通过 WebRTC + WHIP 连接 StreamCoreAI 服务端。
安装
npm install @streamcore/js-sdk快速开始
import { StreamCoreAIClient } from "@streamcore/js-sdk";
const agent = new StreamCoreAIClient(
{ whipUrl: "http://localhost:8080/whip" },
{
onStatusChange: (status) => console.log("Status:", status),
onTranscript: (entry, all) => console.log("Transcript:", entry),
onAudioLevel: (level) => console.log("Audio level:", level),
onAgentStateChange: (state) => console.log("Agent:", state),
onError: (err) => console.error("Error:", err),
}
);
// Connect (requests microphone permission, establishes WebRTC session)
await agent.connect();
// Mute / unmute
agent.toggleMute();
console.log("Muted:", agent.isMuted);
// Disconnect
agent.disconnect();API
new StreamCoreAIClient(config?, events?)
创建一个新的客户端实例。
StreamCoreAIConfig
| 属性 | 类型 | 默认值 | 说明 |
| ------------------ | ---------------------- | ------------------------------------ | ------------------------------------ |
| whipUrl | string | "http://localhost:8080/whip" | WHIP 信令端点 URL |
| token | string | — | 预先获取的 JWT,在 WHIP 请求中以 Authorization: Bearer 发送 |
| tokenUrl | string | — | connect() 期间 SDK POST 获取短时效 token 的端点 |
| apiKey | string | — | 调用 tokenUrl 时以 Authorization: Bearer 发送 |
| iceServers | RTCIceServer[] | [{ urls: "stun:stun.l.google.com:19302" }] | ICE 服务器配置 |
| audioConstraints | MediaTrackConstraints| { echoCancellation: true, noiseSuppression: true, autoGainControl: true, voiceIsolation: true, channelCount: 1 } | 麦克风约束 |
StreamCoreAIEvents
| 事件 | 签名 | 说明 |
| -------------------- | ------------------------------------------------------ | ---------------------------------- |
| onStatusChange | (status: ConnectionStatus) => void | 连接状态变化时触发 |
| onTranscript | (entry: TranscriptEntry, all: TranscriptEntry[]) => void | 有新的或更新的转写时触发 |
| onAudioLevel | (level: number) => void | 每一帧动画触发一次,携带麦克风电平(0–1) |
| onAgentStateChange | (state: AgentState) => void | 智能体开始聆听、思考或说话时触发 |
| onError | (error: Error) => void | 连接或服务端错误时触发 |
| onTiming | (event: TimingEvent) => void | 携带服务端流水线耗时信息 |
| onDataChannelMessage | (message: DataChannelMessage) => void | 每条原始 DataChannel 消息都会触发,早于各类型化回调 |
| onData | (topic: string, payload: Uint8Array) => void | 服务端下发的单向数据包,payload 已完成 base64 解码(car.command 承载传动指令) |
实例方法
| 方法 | 返回值 | 说明 |
| --------------- | --------------- | ------------------------------------------------- |
| connect() | Promise<void> | 请求麦克风权限,建立 WebRTC + WHIP 会话 |
| disconnect() | void | 拆除连接、停止麦克风、释放资源 |
| toggleMute() | void | 切换麦克风静音 |
| on(event, fn) | void | 在构造之后注册事件监听器 |
实例属性(只读)
| 属性 | 类型 | 说明 |
| ------------ | -------------------- | ------------------------------------ |
| status | ConnectionStatus | "idle" \| "connecting" \| "connected" \| "error" \| "disconnected" |
| transcript | TranscriptEntry[] | 完整对话历史 |
| audioLevel | number | 当前麦克风音频电平(0–1) |
| isMuted | boolean | 麦克风是否静音 |
| localStream| MediaStream \| null | 本地麦克风流(connect 之后) |
| remoteStream| MediaStream \| null| 远端智能体音频流(connect 之后) |
类型
type ConnectionStatus = "idle" | "connecting" | "connected" | "error" | "disconnected";
type AgentState = "listening" | "thinking" | "speaking";
interface TranscriptEntry {
role: "user" | "assistant";
text: string;
partial?: boolean;
}
interface TimingEvent {
stage: string;
ms: number;
}
type DataChannelMessage =
| { type: "transcript"; text: string; final: boolean }
| { type: "response"; text: string }
| { type: "error"; message: string }
| { type: "timing"; stage: string; ms: number }
| { type: "state"; state: AgentState };底层辅助函数
包中也导出了原始的 WHIP 调用,便于构建自定义客户端:
import { whipOffer, whipDelete } from "@streamcore/js-sdk";
const { answerSDP, sessionURL } = await whipOffer(whipUrl, offerSDP, token?);
await whipDelete(sessionURL, token?);大多数应用应改用 StreamCoreAIClient —— 它会处理 peer 建立、ICE 收集、events DataChannel、音频电平计量和拆除。
鉴权
当服务端设置了 jwt_secret 时,/whip 需要 bearer token。不要把服务商 API key 放进浏览器 —— 它们属于服务端的 config.toml。正确做法是让客户端去取一个短时效 token:
const agent = new StreamCoreAIClient({
whipUrl: "https://agent.example.com/whip",
tokenUrl: "https://api.example.com/agent-token",
apiKey: process.env.NEXT_PUBLIC_APP_KEY,
});在 connect() 期间,SDK 会 POST 到 tokenUrl(若提供了 apiKey 则作为 bearer token 发送),并期望返回 { "token": "..." }。如果同时设置了 token 和 tokenUrl,以 tokenUrl 为准。token 会被缓存,以便 disconnect() 能对 WHIP DELETE 完成鉴权。
通话方身份
如果你使用外部 agent,并希望它跨多次通话记住同一个用户,它就需要知道来的是谁。本 SDK 没有 resourceId 选项,这是刻意的——浏览器自报身份,等于任何人在 devtools 里改一行就能冒充别人。
请改为在支撑 tokenUrl 的服务端设置。那个端点本来就知道当前登录的是哪个用户,而且它持有 StreamCore /token 所需的 API key:
// 你的后端,POST /agent-token
const res = await fetch("https://agent.example.com/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.STREAMCORE_API_KEY}`,
},
body: JSON.stringify({ resource_id: session.user.id }),
});
return Response.json(await res.json()); // { token } —— 再交给浏览器StreamCore 会把该身份签进 token,之后在每一轮对话中以 resource_id 转发给你的 agent。参见协议 → 通话方身份与自带 agent。
从源码构建
cd typescript-sdk
npm install
npm run build编译产物输出到 dist/。
配合打包工具使用
SDK 以 ES module 形式发布并附带 TypeScript 声明文件。它在 Vite、webpack、Next.js、esbuild 及其他现代打包工具中开箱即用。
许可证
Apache 2.0
