@craftedxp/voice-js 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONSUMING.md +6 -2
- package/README.md +31 -4
- package/dist/assistant.d.mts +32 -0
- package/dist/assistant.d.ts +32 -0
- package/dist/assistant.js +1241 -0
- package/dist/assistant.js.map +1 -0
- package/dist/assistant.mjs +23 -0
- package/dist/assistant.mjs.map +1 -0
- package/dist/browser.d.mts +12 -573
- package/dist/browser.d.ts +12 -573
- package/dist/browser.js +222 -183
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +23 -1373
- package/dist/browser.mjs.map +1 -1
- package/dist/chunk-LV7JGPYW.mjs +200 -0
- package/dist/chunk-LV7JGPYW.mjs.map +1 -0
- package/dist/chunk-ZW22Y67M.mjs +1208 -0
- package/dist/chunk-ZW22Y67M.mjs.map +1 -0
- package/dist/config-D2TbvIqT.d.mts +297 -0
- package/dist/config-D2TbvIqT.d.ts +297 -0
- package/dist/embed.iife.js +5 -42
- package/dist/incomingCall-CfRRzj2P.d.mts +103 -0
- package/dist/incomingCall-CfRRzj2P.d.ts +103 -0
- package/dist/node.d.mts +19 -152
- package/dist/node.d.ts +19 -152
- package/dist/node.js +19 -0
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +19 -0
- package/dist/node.mjs.map +1 -1
- package/dist/room.d.mts +156 -0
- package/dist/room.d.ts +156 -0
- package/dist/room.js +236 -0
- package/dist/room.js.map +1 -0
- package/dist/room.mjs +7 -0
- package/dist/room.mjs.map +1 -0
- package/dist/transcribe.d.mts +14 -0
- package/dist/transcribe.d.ts +14 -0
- package/dist/transcribe.js +1213 -0
- package/dist/transcribe.js.map +1 -0
- package/dist/transcribe.mjs +18 -0
- package/dist/transcribe.mjs.map +1 -0
- package/package.json +21 -4
package/CONSUMING.md
CHANGED
|
@@ -9,9 +9,11 @@ Walks through the three install paths (local tarball → fastest, file: dep →
|
|
|
9
9
|
npm install @craftedxp/voice-js
|
|
10
10
|
# Node consumers also need:
|
|
11
11
|
npm install ws
|
|
12
|
+
# Multi-party rooms (joinRoom) also need:
|
|
13
|
+
npm install livekit-client
|
|
12
14
|
|
|
13
|
-
# wire up:
|
|
14
|
-
import { configureVoiceClient } from '@craftedxp/voice-js'
|
|
15
|
+
# wire up (since 0.7.0, import from the subpath for your agent type):
|
|
16
|
+
import { configureVoiceClient } from '@craftedxp/voice-js/assistant'
|
|
15
17
|
const voice = configureVoiceClient({ apiBase, fetchToken })
|
|
16
18
|
const call = await voice.startCall({ agentId, ...callbacks })
|
|
17
19
|
```
|
|
@@ -61,6 +63,8 @@ npm install ws
|
|
|
61
63
|
|
|
62
64
|
`ws` is a peer dependency declared as `peerDependenciesMeta.optional` so npm doesn't force-install it for browser-only consumers. Add it explicitly when running under Node / Electron-main.
|
|
63
65
|
|
|
66
|
+
`livekit-client` is likewise an optional peer (since 0.7.0 — it was a direct dependency in 0.5.x–0.6.x). It's only needed if you import from `@craftedxp/voice-js/room`; assistant / transcribe consumers never download it. `joinRoom` lazy-loads it and throws an actionable error if it's missing.
|
|
67
|
+
|
|
64
68
|
## Backend setup — minting `ct_` tokens
|
|
65
69
|
|
|
66
70
|
Your `fetchToken` callback hits YOUR backend. Your backend uses the `sk_` API key (held server-side only) to mint a short-lived `ct_` for the SDK to use. Pattern:
|
package/README.md
CHANGED
|
@@ -12,9 +12,26 @@ Companion to [`@craftedxp/voice-rn`](https://www.npmjs.com/package/@craftedxp/vo
|
|
|
12
12
|
npm install @craftedxp/voice-js
|
|
13
13
|
# Node consumers also need:
|
|
14
14
|
npm install ws
|
|
15
|
+
# Multi-party rooms only (joinRoom) also need:
|
|
16
|
+
npm install livekit-client
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
`ws`
|
|
19
|
+
`ws` and `livekit-client` are both declared as OPTIONAL peers:
|
|
20
|
+
|
|
21
|
+
- `ws` — only needed in Node / Electron-main. Browsers use the native `WebSocket` and skip it.
|
|
22
|
+
- `livekit-client` — only needed if you import from `@craftedxp/voice-js/room`. Since 0.7.0 it is no longer a direct dependency, so assistant / transcribe consumers never download it (the embed widget dropped from ~854 KB to ~100 KB). `joinRoom` lazy-`import()`s it and throws an actionable error if it's missing.
|
|
23
|
+
|
|
24
|
+
## Entry points (since 0.7.0)
|
|
25
|
+
|
|
26
|
+
Import from the subpath that matches your [agent type](https://www.npmjs.com/package/@craftedxp/sdk-node) so you only pull in the code you use:
|
|
27
|
+
|
|
28
|
+
| Import | Surface | Agent type |
|
|
29
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
|
|
30
|
+
| `@craftedxp/voice-js/assistant` | `configureVoiceClient` → `startCall` (1:1 voice) + `startTextSession` (text chat) + client tools. **No LiveKit in the module graph.** | `assistant` |
|
|
31
|
+
| `@craftedxp/voice-js/room` | `joinRoom` → `RoomSession`. The only entry that touches LiveKit (lazy, optional peer). | `room` |
|
|
32
|
+
| `@craftedxp/voice-js/transcribe` | `configureTranscribeClient` → `startDictation` (STT-only). | `transcribe` |
|
|
33
|
+
| `@craftedxp/voice-js/node` | Raw-PCM assistant client for Node / Electron-main. | `assistant` |
|
|
34
|
+
| `@craftedxp/voice-js` | Deprecated barrel — re-exports everything for back-compat. Prefer a subpath; the barrel still pulls LiveKit lazily but defeats the bundle savings. | — |
|
|
18
35
|
|
|
19
36
|
## How the integration fits together
|
|
20
37
|
|
|
@@ -36,7 +53,7 @@ The `sk_` API key never lives in browser code. **The SDK has no `apiKey` option*
|
|
|
36
53
|
## Quick start (browser)
|
|
37
54
|
|
|
38
55
|
```ts
|
|
39
|
-
import { configureVoiceClient } from '@craftedxp/voice-js'
|
|
56
|
+
import { configureVoiceClient } from '@craftedxp/voice-js/assistant'
|
|
40
57
|
|
|
41
58
|
const voice = configureVoiceClient({
|
|
42
59
|
apiBase: 'https://api.your-server.com',
|
|
@@ -186,9 +203,15 @@ Node consumers get a `NodeCall` extension with one extra method:
|
|
|
186
203
|
```ts
|
|
187
204
|
interface NodeCall extends Call {
|
|
188
205
|
sendAudioChunk: (pcm: ArrayBuffer | ArrayBufferView) => boolean
|
|
206
|
+
sendClientEvent: (text: string) => boolean
|
|
207
|
+
sendText: (text: string) => boolean
|
|
189
208
|
}
|
|
190
209
|
```
|
|
191
210
|
|
|
211
|
+
`sendClientEvent(text)` pushes a short advisory context line to the live call (e.g. a browser action the user just took). The server buffers these and shows them to the LLM ahead of the next turn — they never trigger a response by themselves. Text is trimmed and truncated to 400 chars. Returns `false` if the WS isn't open yet or text is empty.
|
|
212
|
+
|
|
213
|
+
`sendText(text)` sends a typed user turn — `{type:'user_text', text}` — for text/multimodal sessions opened with a `channel:'text'` token. The server accepts `user_text` only on text-channel sessions and rejects it on voice calls (anti-injection), so on a voice call this is a no-op beyond the frame being ignored server-side. Text is trimmed. Returns `false` (and sends nothing) if the WS isn't open or text is empty/whitespace. Never throws.
|
|
214
|
+
|
|
192
215
|
### Stable types
|
|
193
216
|
|
|
194
217
|
```ts
|
|
@@ -272,7 +295,7 @@ surface-only actions (read DOM state, hit a private API, mutate local storage,
|
|
|
272
295
|
control the UI).
|
|
273
296
|
|
|
274
297
|
```ts
|
|
275
|
-
import { configureVoiceClient, type ClientToolMap } from '@craftedxp/voice-js'
|
|
298
|
+
import { configureVoiceClient, type ClientToolMap } from '@craftedxp/voice-js/assistant'
|
|
276
299
|
|
|
277
300
|
const tools: ClientToolMap = {
|
|
278
301
|
addTodoItem: {
|
|
@@ -397,7 +420,11 @@ Renders a floating call button with a Shadow-DOM transcript panel. Pre-mint the
|
|
|
397
420
|
|
|
398
421
|
## Status
|
|
399
422
|
|
|
400
|
-
- **0.
|
|
423
|
+
- **0.9.0** (current) — `sendText(text)` on `NodeCall`: typed user turns for `channel:'text'` WS sessions (`user_text` frame). Server accepts `user_text` only on text-channel sessions and rejects it on voice-channel sessions (anti-injection). Text is trimmed; returns `false` (and sends nothing) if the WS isn't open or text is empty/whitespace, never throws. Additive — drop-in for 0.8.0 consumers.
|
|
424
|
+
- 0.8.0 — `sendClientEvent(text)` on `NodeCall`: advisory context lines for live calls (`client_event` frame). Server buffers these and prepends them to the next turn's context; never triggers a response by itself. Text is trimmed and truncated to 400 chars; returns `false` if the WS isn't open yet or text is empty. Additive — drop-in for 0.7.0 consumers.
|
|
425
|
+
- 0.7.0 — Per-type entry points + LiveKit goes optional. New subpaths `@craftedxp/voice-js/assistant`, `/room`, `/transcribe` (plus the existing `/node`); import the one matching your [agent `type`](https://www.npmjs.com/package/@craftedxp/sdk-node). `livekit-client` moved from `dependencies` to an **optional peerDependency** — assistant / transcribe consumers no longer download it, and the embed widget dropped from ~854 KB to ~100 KB. `joinRoom` lazy-`import()`s LiveKit and throws an actionable error if it isn't installed, so the deprecated barrel keeps working for non-room consumers. **Breaking for room consumers:** add `npm install livekit-client`. Non-room consumers are drop-in (prefer migrating barrel imports to `/assistant`).
|
|
426
|
+
- 0.6.0 — Text chat sessions. `startTextSession({ token, agentId, … })` opens an HTTP+SSE chat against a `channel: 'text'` token — no microphone / audio. Exposed from the assistant entry. Additive; voice consumers see no change.
|
|
427
|
+
- 0.5.4 — Screen sharing. `setScreenShareEnabled(on, { audio })` publishes a `screen_share` video track (and, where the browser allows, a `screen_share_audio` track — Chrome captures tab/system audio; macOS Chrome is tab-audio only; Safari/Firefox don't capture share audio). `RoomTrackEvent` gains a `source` field (`camera` / `microphone` / `screen_share` / `screen_share_audio` / `unknown`) so a screen share can render as its own tile instead of replacing the participant's camera. Adds `isScreenShareEnabled()` and `getLocalScreenTrack()`. No 1:1 call-surface change. Drop-in for 0.5.3 consumers (the new `source` field is additive).
|
|
401
428
|
- 0.5.3 — `session.participantId` (this session's own stable `p_…` id). `active.speakers` includes the local participant, so a focus-tile UI rendered you as a remote when you spoke (no remote track → blank tile with the raw id). Filter `participantId` out of `active.speakers` to focus only remote speakers (self-view when none). No 1:1 call-surface change. Drop-in upgrade for 0.5.2 consumers.
|
|
402
429
|
- 0.5.2 — `getRemoteTracks(): RoomTrackEvent[]`. Returns remote tracks already subscribed at call time. A late joiner misses the live `track.subscribed` events for tracks published before it connected (LiveKit delivers them during `connect`, before consumer listeners attach), so it never rendered participants who already had their camera on (e.g. the host). Call `getRemoteTracks()` right after registering `track.subscribed` to backfill them. No 1:1 call-surface change. Drop-in upgrade for 0.5.1 consumers.
|
|
403
430
|
- 0.5.1 — Room video surface. `RoomSession` gains: `track.subscribed` / `track.unsubscribed` events with payload `{ participantId: string; kind: 'audio' | 'video'; track: RemoteTrack }` (raw livekit-client track — call `track.attach(el)` / `track.detach()`); `active.speakers` event (`string[]` of participantIds currently speaking, drives active-speaker UI); `setMicEnabled(on: boolean): Promise<void>` / `setCameraEnabled(on: boolean): Promise<void>` (mid-call toggles); `isMicEnabled(): boolean` / `isCameraEnabled(): boolean` (read current state for toggle button UI); `getLocalCameraTrack(): LocalVideoTrack | null` (attach to self-view element). No API changes to the 1:1 call surface (`startCall` / `Call`). Drop-in upgrade for 0.5.0 consumers.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { V as VoiceClientConfig, a as VoiceClientFactory } from './config-D2TbvIqT.mjs';
|
|
2
|
+
export { C as Call, b as CallEndEvent, c as CallEndReason, d as CallError, e as CallErrorCode, f as CallState, g as ChatEvent, h as ClientTool, i as ClientToolMap, F as FetchToken, j as FetchTokenArgs, k as FetchTokenResult, P as ProtocolCallbacks, l as ProtocolState, S as ServerMessage, m as StartCallOptions, n as StartTextSessionOpts, T as TextSession, o as TranscriptEntry, p as VolumeEvent, q as buildWsUrl, r as createProtocolState, s as handleServerMessage, t as startTextSession } from './config-D2TbvIqT.mjs';
|
|
3
|
+
export { C as CaptureController, a as CaptureOptions, I as IncomingCallPayload, O as OnAgentSpeakingChange, b as OnChunk, c as OnError, d as OnVolume, P as PlaybackController, e as PlaybackOptions, R as RWSEvent, f as RWSOptions, g as ReconnectingWebSocket, W as WebSocketFactory, h as WebSocketLike, i as createAudioCapture, j as createAudioPlayback, k as createReconnectingWebSocket, p as parseIncomingCall } from './incomingCall-CfRRzj2P.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One-time SDK setup. Returns a factory you call `startCall` on for
|
|
7
|
+
* every voice call.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* const voice = configureVoiceClient({
|
|
11
|
+
* apiBase: 'https://api.your-server.com',
|
|
12
|
+
* fetchToken: async ({ agentId }) => {
|
|
13
|
+
* const r = await fetch('/api/voice-token', {
|
|
14
|
+
* method: 'POST',
|
|
15
|
+
* body: JSON.stringify({ agentId }),
|
|
16
|
+
* })
|
|
17
|
+
* return (await r.json()).token
|
|
18
|
+
* },
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* // Per call (typically inside a click handler):
|
|
22
|
+
* const call = await voice.startCall({
|
|
23
|
+
* agentId: 'agt_xxx',
|
|
24
|
+
* onTranscript: (entries) => render(entries),
|
|
25
|
+
* onEnd: ({ reason }) => log(reason),
|
|
26
|
+
* })
|
|
27
|
+
* call.mute()
|
|
28
|
+
* call.end()
|
|
29
|
+
*/
|
|
30
|
+
declare function configureVoiceClient(config: VoiceClientConfig): VoiceClientFactory;
|
|
31
|
+
|
|
32
|
+
export { VoiceClientConfig, VoiceClientFactory, configureVoiceClient };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { V as VoiceClientConfig, a as VoiceClientFactory } from './config-D2TbvIqT.js';
|
|
2
|
+
export { C as Call, b as CallEndEvent, c as CallEndReason, d as CallError, e as CallErrorCode, f as CallState, g as ChatEvent, h as ClientTool, i as ClientToolMap, F as FetchToken, j as FetchTokenArgs, k as FetchTokenResult, P as ProtocolCallbacks, l as ProtocolState, S as ServerMessage, m as StartCallOptions, n as StartTextSessionOpts, T as TextSession, o as TranscriptEntry, p as VolumeEvent, q as buildWsUrl, r as createProtocolState, s as handleServerMessage, t as startTextSession } from './config-D2TbvIqT.js';
|
|
3
|
+
export { C as CaptureController, a as CaptureOptions, I as IncomingCallPayload, O as OnAgentSpeakingChange, b as OnChunk, c as OnError, d as OnVolume, P as PlaybackController, e as PlaybackOptions, R as RWSEvent, f as RWSOptions, g as ReconnectingWebSocket, W as WebSocketFactory, h as WebSocketLike, i as createAudioCapture, j as createAudioPlayback, k as createReconnectingWebSocket, p as parseIncomingCall } from './incomingCall-CfRRzj2P.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One-time SDK setup. Returns a factory you call `startCall` on for
|
|
7
|
+
* every voice call.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* const voice = configureVoiceClient({
|
|
11
|
+
* apiBase: 'https://api.your-server.com',
|
|
12
|
+
* fetchToken: async ({ agentId }) => {
|
|
13
|
+
* const r = await fetch('/api/voice-token', {
|
|
14
|
+
* method: 'POST',
|
|
15
|
+
* body: JSON.stringify({ agentId }),
|
|
16
|
+
* })
|
|
17
|
+
* return (await r.json()).token
|
|
18
|
+
* },
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* // Per call (typically inside a click handler):
|
|
22
|
+
* const call = await voice.startCall({
|
|
23
|
+
* agentId: 'agt_xxx',
|
|
24
|
+
* onTranscript: (entries) => render(entries),
|
|
25
|
+
* onEnd: ({ reason }) => log(reason),
|
|
26
|
+
* })
|
|
27
|
+
* call.mute()
|
|
28
|
+
* call.end()
|
|
29
|
+
*/
|
|
30
|
+
declare function configureVoiceClient(config: VoiceClientConfig): VoiceClientFactory;
|
|
31
|
+
|
|
32
|
+
export { VoiceClientConfig, VoiceClientFactory, configureVoiceClient };
|