@byokit/实时
在一个儿童过程中带有注入音频和提供者适配器的实时语音会话. 第一位消费者:muxr.
import { realtimeClient, type AudioPorts, type RealtimeHostFrame, type RealtimeStream } from '@byokit/realtime';
import { realtimeEngine, toolBridge } from '@byokit/realtime/node';
// The app supplies its sign-in, carrier, audio implementation and authorized planner.
declare const accounts: { access(member: number, signal?: AbortSignal): Promise<{ access: string; accountId: string }> };
declare const emit: (frame: RealtimeHostFrame) => void;
declare const runPlanner: (request: string, signal: AbortSignal) => Promise<string>;
declare const openVoiceStream: () => Promise<RealtimeStream>;
declare const audio: AudioPorts;
const member = 1;
const tools = [{ name: 'delegate', description: 'Handle a spoken request', parameters: { type: 'object', properties: { request: { type: 'string' } } } }];
const bridge = toolBridge({
tools, handlers: { delegate: async (args, { signal }) => runPlanner(String(args.request), signal) },
emit, failure: () => 'That request could not be completed.',
});
const engine = realtimeEngine({
engine: 'chatgpt', auth: { kind: 'plan', access: signal => accounts.access(member, signal) },
tools, bridge, instructions: 'Answer briefly.', emit,
});
// Forward device frames to engine.receive(frame); engine.close() ends the child.
const client = realtimeClient({
open: openVoiceStream, audio,
onStatus: status => console.log(status),
onTurn: (role, text) => console.log(role, text),
});
对于 ChatGPT 语音寄存器 a delegate 工具处理器接收 { request } 并且提供应用程序的策划器。 API 路线使用 auth: { kind: 'key', key }按用途计费。 订阅路由使用 CHATGPT 的签名 @byokit/accounts;它从不读取 Codex 证书或开始 Codex CLI 。 后端拒绝报告为 not-included。 。 。 .
结构化授权和指定目标
delegationHandler 发送表格中的 JSON 请求 { name, arguments }
直接通过应用程序提供 toolBridge对于普通的口头请求
使用可选的应用程序规划器。 无效的结构化请求从未输入规划器 .
保持动作桥与外立面隔开 delegate 桥:
import { delegationHandler, toolBridge } from '@byokit/realtime/node';
import type { ToolHandler } from '@byokit/realtime/node';
import type { RealtimeHostFrame } from '@byokit/realtime';
declare const emit: (frame: RealtimeHostFrame) => void;
declare const sendAuthorizedMessage: ToolHandler;
declare const plan: (request: string, context: Parameters<ToolHandler>[1]) => Promise<string>;
const actionTools = [{ name: 'message', description: 'Message a named agent', parameters: {
type: 'object', properties: { agent: { type: 'string' }, text: { type: 'string' } },
required: ['agent', 'text'], additionalProperties: false,
} }];
const actions = toolBridge({ tools: actionTools, handlers: { message: sendAuthorizedMessage },
emit, failure: () => 'The message could not be confirmed.', timeoutFor: () => 75000 });
const delegate = delegationHandler({ bridge: actions, plan });
const tools = [{ name: 'delegate', description: 'Delegate a spoken request', parameters: { type: 'object' } }];
const bridge = toolBridge({ tools, handlers: { delegate }, emit,
timeoutFor: () => 340000, failure: () => 'The request could not be confirmed.' });
// Pass the outer bridge and its delegate tool to realtimeEngine.
// A structured request can be:
// {"name":"message","arguments":{"agent":"Avery","text":"Please report progress"}}
// Close actions as well as the outer bridge when the session ends.
工具包保存参数和操作代号;使用相同的调用代号重试
共享结果。 命名目标,目标搜索,模糊检查,授权,
参数验证和突变收据属于应用程序的处理者。 工具
JSON计划描述了供应商目录;它们不是运行时间授权.
应用规划师拥有其模型,对话记忆,工具预算和最后期限;
工具箱不添加计划模型或任何代理运行时间依赖。 已中止
电话也必须在应用中停止;完成的副作用永远不会回滚.
主机桥拥有每个工具监视器和故障信息;孩子没有
第二个最后期限。 因此,一个340秒的计程器或290秒的表可以使用
应用软件的宣布预算。 普通的 ChatGPT 用户转回保存未完成
代表团及其转发缓存。 明确 interrupt 或关闭终止
; 一个新的转动 id 仍然可以识别新的请求.
咨询认证检查
通过只读保存的签名搜索 authCheck 在发动机上。 开始了
独立地,从不等待启动,也不能结束会议。 这个
不调用 auth.access或启动登录.
应用程序 peek 召回还必须永远不要刷新、迅速或开始登录.
import { realtimeEngine, toolBridge } from '@byokit/realtime/node';
import type { RealtimeAuth, RealtimeHostFrame, RealtimeTool, RealtimeAuthPeekResult, RealtimeAuthResult } from '@byokit/realtime';
declare const auth: Extract<RealtimeAuth, { kind: 'plan' }>;
declare const tools: RealtimeTool[];
declare const bridge: ReturnType<typeof toolBridge>;
declare const emit: (frame: RealtimeHostFrame) => void;
declare const peekSavedSignIn: (signal: AbortSignal) => Promise<RealtimeAuthPeekResult>;
declare const updateSettingsBadge: (status: 'ready' | 'signed-out' | 'unknown') => void;
declare const showSignInMessage: (result: RealtimeAuthResult) => void;
const engine = realtimeEngine({
engine: 'chatgpt', auth,
tools, bridge, emit,
authCheck: { peek: peekSavedSignIn, onStatus: status => updateSettingsBadge(status), onResult: showSignInMessage },
});
ready 表示应用程序报告一个已保存的登录,而不是提供者权限.
signed-out 表示查找返回错误或发现无法使用保存的登录 .
未识别错误或超时生成 unknown;默认超时为一秒,封顶为十秒. 关闭
取消待核对,并取消逾期通知。 正常会话
认证仍然需要来自 auth.access。 。 。 .
对于一个独立的设置搜索, realtimeAuthCheck({ peek }) 也导出
从可移动条目和返回 { result, details, close }。 。 。 . result 还是
确定状态字符串; details 决定: { state, reason?, message? }, (中文(简体) ),
和发动机 onResult 得到同样的诊断对象。 布尔或
{ state } 偷看保留了先前的行为而不添加理由 .
要报告已过期的已保存的登录, 只读的浏览可以返回
{ state: 'signed-out', reason: 'login-expired' }。内在原因有:
credential-permissions, (中文(简体) ), login-expired, (中文(简体) ), missing 财务报告和审定财务报表 unknown; 应用程序可以
提供额外的原因字符串。 信件使用固定的纯文字, 绝不
复制例外文本或证书路径。 缺少文件错误映射到 missing, (中文(简体) ),
允许错误到 credential-permissions,并过期错误
login-expired; 未识别错误和超时报告 unknown。不要等待此检查
在打开语音会话之前,或从结果中显示登录提示.
生命周期通知和语义应用工具
Feed App确认的生命周期报告进入了现有的语音路径. 装备 不监视代理人或推断其结果:
import type { realtimeClient } from '@byokit/realtime';
import type { realtimeEngine } from '@byokit/realtime/node';
declare const client: ReturnType<typeof realtimeClient>;
declare const engine: ReturnType<typeof realtimeEngine>;
// Called by the app's lifecycle subscription; use bounded, sanitized app wording.
client.speak('Avery has finished the task.');
// A host can inject the same report directly:
engine.receive({ type: 'realtime.say', text: 'Avery has finished the task.' });
speak 最多16个报告排队,直到呼叫准备好,等待本地
播放回放排出且不重放重联时发送的语音 . onTurn 观察
记录和记录 onStatus 观察回放状态;单凭笔录即可
无法证明报告是可信的。 应用程序拥有推送, 减速,
唤起一通入睡电话,并在接到报告后停止.
何时 player.finish(callback) 返回虚假,客户端报告已连接
马上 真正的意味着玩家在排水后会回电. 清除
音频还重新检查已排队的语音,包括麦克风哑音时.
编曲 appBridge 与 toolBridge 至来回语义电话请求:
import { appBridge, toolBridge } from '@byokit/realtime/node';
import type { RealtimeHostFrame } from '@byokit/realtime';
declare const emit: (frame: RealtimeHostFrame) => void;
const app = appBridge(emit);
const navigation = [{ name: 'navigate', description: 'Open an app destination',
parameters: { type: 'object', properties: { target: { type: 'string' } }, required: ['target'] } }];
const bridge = toolBridge({ tools: navigation, app, emit,
handlers: { navigate: (args, { signal }) => app.run('navigate', String(args.target), signal) },
failure: () => 'The app could not complete that request.',
});
// client.onAppRequest handles view/navigate/activate; forward all client frames
// to engine.receive, which routes app results back to this app bridge.
// Closing the engine also cancels pending app requests.
主要条目为可移植的网络和回放原生并加载无原生代码. ./webrtc 用品 webRtcPeer 并选择其本地执行 react-native 条件; 安装可选 react-native-webrtc 124.0.8 RN应用程序中的同位素。 所有媒体API都可以被注入测试. ./node 需要22.18+节点,并为证书寄存器。 它从自己的适配器孩子开始时,环境是空的;证书在私人stdin上行走. 没有向设备发送提供者密钥或计划令牌.
AudioPorts 需要麦克风获取/放行,PCM捕获,回放录入/排水和音频路由. 该应用程序拥有权限及其麦克风服务. 只有在完成这项服务后,才能获得解决。 客户在抓捕之前等着呢 每个客户端拥有其端口;应用程序必须仲裁共享的麦克风.
没有麦克风的连接
设定 capture: 'lazy' 用于浏览器或反应原生WebRTC会话。 启动
谈判一个 sendrecv 没有发件人音轨的音频收发器: 它调用
也没有 audio.microphone.acquire() 也没有 getUserMedia所以应用的麦克风
前景服务停止。 回放路线仍然可用.
import { realtimeClient, type AudioPorts, type RealtimeStream } from '@byokit/realtime';
import { webRtcPeer } from '@byokit/realtime/webrtc';
declare const audio: AudioPorts;
declare const openVoiceStream: () => Promise<RealtimeStream>;
const client = realtimeClient({
open: openVoiceStream, audio, webrtc: webRtcPeer, capture: 'lazy',
onStatus() {}, onTurn() {},
});
// Once WebRTC setup has started, await this before accepting speech:
async function beginTalking() { await client.attachMic(); }
// When idle, release hardware capture while keeping the call connected:
async function becomeIdle() { await client.releaseMic(); }
// End the call and release all media:
function endCall() { client.stop(); }
attachMic() 等待应用程序的麦克风许可/服务租赁,抓取
音频音轨和使用 sender.replaceTrack(track) 在启用发件人之前
编码 懒同辈谈判 sendrecv 使用不活动编码:Android's
音频设备不能仅仅因为一个答案被应用而开始录音.
releaseMic() 禁用之前的编码 replaceTrack(null),停止捕捉轨道,并释放租赁 所以应用程序
可以停止它的麦克风服务,并清除OS指示器. 没有操作
重新谈判。 重复通话是安全的;在等待抓获期间释放或停止
抓住它就清理干净 重新连接开始另一个懒惰的对等点;
应用程序在需要输入时再次明确附加.
内置 webRtcPeer 手柄还暴露了两种直接使用的方法.
自定义同行工厂可执行这些可选方法;客户端附件
如果当前对等方不支持它们或设置尚未启动,则拒绝 .
默认为急切抓取,PCM抓取不变. setMuted() 还是
只切换轨道交付; 使用 releaseMic() 放弃捕捉。 静音
状态在附加新音轨时持续。 每个客户拥有自己的 AudioPorts· ;
microphone.release() 必须停止应用程序的前沿服务.
呼叫结束时关闭客户端和引擎. client.interrupt() 清除回放并中止未完成的工具;旧的响应输出被栅栏。 瞬间提供商和运输故障重试了两次,经过了500和1000ms后,在30个健康秒后有了新的预算. 发送的音频,语音和工具呼叫从不重复播放. 该应用程序可以用 retryableClose。明确的 ChatGPT 中断打开一个新呼叫;明确的双子中断旋转其提供者会话。 本地语音中断仍然由提供者驱动。 没有导出 STT/ LLM/ TTS 链 。 见 空运合同 用于界限、事件和用途.
重新连接和主机政策
设定 preserveMediaOnReconnect: true 客户端保留一个准备的PCM
录音机、麦克风租赁、音频线路和穿越载体的回放尾巴
重新连接。 载体下降时捕获的音频被丢弃. 待决
麦克风获取在重试前仍然会释放; WebRTC 总是创建
新鲜的对等点 新鲜的呼叫 已更改的 PCM 格式释放了旧的记录器
在获得另一个之前。 停止发布即使在后退期间也保留了媒体.
默认仍为释放/ 清除/ 重新获取 .
引擎接受app短语政策和证书-error措辞:
import { realtimeEngine, toolBridge } from '@byokit/realtime/node';
import type { RealtimeAuth, RealtimeHostFrame, RealtimeTool } from '@byokit/realtime';
declare const auth: Extract<RealtimeAuth, { kind: 'plan' }>;
declare const tools: RealtimeTool[];
declare const bridge: ReturnType<typeof toolBridge>;
declare const emit: (frame: RealtimeHostFrame) => void;
const engine = realtimeEngine({ engine: 'chatgpt',
auth, tools, bridge, emit,
hangup: text => /^goodbye[.!]?$/i.test(text.trim()),
authFailure: () => 'Sign in again from Settings.',
signalingIdentity: { originator: 'voice-app', userAgent: 'voice-app/1' },
});
挂断在下一个完成的代理记录后结束,以便提供者 告别吧 这是笔录级的政策 而不是回放的证据 排尽了 核证错误作为关闭部分进行消毒、定界和释放 理由; 工具包未启动登录或即时。 记录保存到 4,000 UTF-8 字节, 状态细节可达500字节, 以及近似原因可达 2,048字节. 空 ChatGPT 记录被忽略 .
ChatGPT 发射 realtime.webrtc.start 当被隔离的孩子开始
进入问题正在得到解决。 设备框架始终被限制和排队直至
证书/配置行已发送 。 这与本地设置重叠而不发送
在提供全权证书之前发出请求. signalingIdentity
让应用程序指定自己的发端人/用户代理;对两者的默认是
byokit,而身份值必须是最多160个字符的可打印ASCII.
证书、终点限制和拒绝更改方向不变.
身份选项允许消费者比较信号延迟; 离线
测试证明启动命令, 而不是减少远程提供者的 POST 时间 .
对于明确直播的麦克风和订阅提供者证明,运行 边框语音演示它通过账户来签名, 将签名保存在这个电脑的机器商店, 记录连接的事实和转帐。 离线测试不能建立现场通行证.