@pouchy_ai/companion-sdk 0.25.0 → 0.26.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/CHANGELOG.md +20 -0
- package/README.md +7 -1
- package/dist/call.js +7 -6
- package/dist/client.d.ts +4 -7
- package/dist/client.js +5 -12
- package/dist/errors.d.ts +9 -0
- package/dist/errors.js +20 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,26 @@ a protocol bump is always called out explicitly here.
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [0.26.0] - 2026-07-11
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **Voice-call connect failures now honor the typed-error contract.** The
|
|
20
|
+
call helpers (`connectCall` / `startCall` / `openCompanionCall`) used to
|
|
21
|
+
reject with plain `Error`s for the connect-step failures, so they carried
|
|
22
|
+
no `.code` and couldn't be `switch`ed like every other SDK rejection.
|
|
23
|
+
They now reject with `CompanionError` and three new client-synthesized
|
|
24
|
+
codes: `call_unsupported` (non-browser environment — no WebRTC/mic),
|
|
25
|
+
`call_connect_failed` (mic-permission timeout, SDP exchange failed or
|
|
26
|
+
timed out; `status` carries the HTTP status when the exchange answered
|
|
27
|
+
non-2xx), and `call_dependency_missing` (the optional
|
|
28
|
+
`@elevenlabs/client` peer dependency isn't installed). Like
|
|
29
|
+
`reply_timeout`/`stream_unauthorized` these are SDK-synthesized and
|
|
30
|
+
deliberately NOT part of the server-mirrored `COMPANION_ERROR_CODES`
|
|
31
|
+
HTTP vocabulary. Browser-native `getUserMedia` rejections (e.g.
|
|
32
|
+
`NotAllowedError` on permission denial) still propagate untouched.
|
|
33
|
+
`CompanionError` itself is unchanged and keeps its import path.
|
|
34
|
+
|
|
15
35
|
## [0.25.0] - 2026-07-11
|
|
16
36
|
|
|
17
37
|
### Added
|
package/README.md
CHANGED
|
@@ -147,7 +147,13 @@ HTTP `code` vocabulary behind `CompanionError.code`, e.g. `missing_scope` /
|
|
|
147
147
|
`session_not_found` / `turn_pending`) — so you can assert the version, validate
|
|
148
148
|
the event vocabulary, or switch on error codes without hard-coding strings.
|
|
149
149
|
Every helper populates `CompanionError.code` when the server names a cause
|
|
150
|
-
(0.24.0 — previously only the POST-backed calls did).
|
|
150
|
+
(0.24.0 — previously only the POST-backed calls did). The SDK also synthesizes
|
|
151
|
+
a few client-side codes outside that HTTP vocabulary: `reply_timeout`
|
|
152
|
+
(awaitReply fallback gave up), `stream_unauthorized` (event-stream 401
|
|
153
|
+
exhausted reconnects), and — 0.26.0 — the voice connect-step codes
|
|
154
|
+
`call_unsupported` (no WebRTC/mic in this environment), `call_connect_failed`
|
|
155
|
+
(mic timeout / SDP exchange failed) and `call_dependency_missing`
|
|
156
|
+
(`@elevenlabs/client` not installed). Every
|
|
151
157
|
outbound payload has a named type; `ToolCallPayload` (`{ id, name, args }`) types
|
|
152
158
|
the `companion.tool_call` event, and `onToolCall`'s callback receives
|
|
153
159
|
`ToolCallEvent` — the payload plus `argsJson` (pre-parsed args).
|
package/dist/call.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
//
|
|
11
11
|
// Browser-only (needs WebRTC + getUserMedia). Returns a handle to hang up and to
|
|
12
12
|
// inject live context mid-call (the bridge the server uses for voiceRelevant).
|
|
13
|
+
import { CompanionError } from './errors.js';
|
|
13
14
|
/** Universal "host control" verbs the companion can call on ANY surface (web /
|
|
14
15
|
* game / app / hardware), regardless of provider. They're generic on purpose —
|
|
15
16
|
* the SPECIFIC intent rides in the string params, which YOUR surface interprets
|
|
@@ -147,7 +148,7 @@ const OPENAI_REALTIME_CALLS = 'https://api.openai.com/v1/realtime/calls';
|
|
|
147
148
|
/** Open a live call from pre-minted credentials. */
|
|
148
149
|
export async function openCompanionCall(creds, opts = {}, bridge) {
|
|
149
150
|
if (typeof navigator === 'undefined' || !navigator.mediaDevices) {
|
|
150
|
-
throw new
|
|
151
|
+
throw new CompanionError('connectCall is browser-only (needs WebRTC + microphone access)', 0, 'call_unsupported');
|
|
151
152
|
}
|
|
152
153
|
return creds.provider === 'openai-realtime'
|
|
153
154
|
? openOpenAICall(creds, opts, bridge)
|
|
@@ -176,7 +177,7 @@ async function getMicWithTimeout() {
|
|
|
176
177
|
.catch(() => { });
|
|
177
178
|
const timeout = new Promise((_, reject) => setTimeout(() => {
|
|
178
179
|
timedOut = true;
|
|
179
|
-
reject(new
|
|
180
|
+
reject(new CompanionError('microphone request timed out', 0, 'call_connect_failed'));
|
|
180
181
|
}, GUM_TIMEOUT_MS));
|
|
181
182
|
return Promise.race([micPromise, timeout]);
|
|
182
183
|
}
|
|
@@ -343,14 +344,14 @@ async function openOpenAICall(creds, opts, bridge) {
|
|
|
343
344
|
catch {
|
|
344
345
|
clearTimeout(sdpTimer);
|
|
345
346
|
cleanupPartial();
|
|
346
|
-
throw new
|
|
347
|
+
throw new CompanionError(sdpAbort.signal.aborted
|
|
347
348
|
? 'OpenAI Realtime SDP exchange timed out'
|
|
348
|
-
: 'OpenAI Realtime SDP exchange failed');
|
|
349
|
+
: 'OpenAI Realtime SDP exchange failed', 0, 'call_connect_failed');
|
|
349
350
|
}
|
|
350
351
|
clearTimeout(sdpTimer);
|
|
351
352
|
if (!res.ok) {
|
|
352
353
|
cleanupPartial();
|
|
353
|
-
throw new
|
|
354
|
+
throw new CompanionError(`OpenAI Realtime SDP exchange failed (${res.status})`, res.status, 'call_connect_failed');
|
|
354
355
|
}
|
|
355
356
|
await pc.setRemoteDescription({ type: 'answer', sdp: await res.text() });
|
|
356
357
|
let closed = false;
|
|
@@ -458,7 +459,7 @@ async function openConvaiCall(creds, opts, bridge) {
|
|
|
458
459
|
mod = await import('@elevenlabs/client');
|
|
459
460
|
}
|
|
460
461
|
catch {
|
|
461
|
-
throw new
|
|
462
|
+
throw new CompanionError("elevenlabs-convai call needs the optional peer dependency '@elevenlabs/client' — install it (npm i @elevenlabs/client)", 0, 'call_dependency_missing');
|
|
462
463
|
}
|
|
463
464
|
// App tools → EL client tools. NOTE: ElevenLabs only CALLS a client tool the
|
|
464
465
|
// agent already knows (declared on the agent config); a shared Convai agent
|
package/dist/client.d.ts
CHANGED
|
@@ -166,12 +166,10 @@ export declare function pouchyBrandIconUrl(baseUrl: string, size?: BrandIconSize
|
|
|
166
166
|
* a method before `connect()`). `code` is a stable machine-readable tag you can
|
|
167
167
|
* switch on, shared with the `control.error` stream event vocabulary:
|
|
168
168
|
* `'not_connected'`, `'missing_option'`, `'not_representative'`, or the server's
|
|
169
|
-
* own error code for an HTTP failure (when it sends one).
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
constructor(message: string, status: number, code?: string);
|
|
174
|
-
}
|
|
169
|
+
* own error code for an HTTP failure (when it sends one). Defined in errors.ts
|
|
170
|
+
* (so call.ts shares it cycle-free); re-exported here so the public import
|
|
171
|
+
* path is unchanged. */
|
|
172
|
+
export { CompanionError } from './errors.js';
|
|
175
173
|
/** The server's memory-consolidation diagnostic from `endSession()` / `close()`.
|
|
176
174
|
* `ok` is whether consolidation ran; `facts` is how many memories it wrote;
|
|
177
175
|
* `skipped` (when present) says why nothing was written
|
|
@@ -581,4 +579,3 @@ export declare class CompanionClient {
|
|
|
581
579
|
private consume;
|
|
582
580
|
private sleep;
|
|
583
581
|
}
|
|
584
|
-
export {};
|
package/dist/client.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// kept in lockstep by protocol.drift.test.ts.
|
|
15
15
|
import { PROTOCOL_VERSION } from './protocol.js';
|
|
16
16
|
import { parseSse } from './sse.js';
|
|
17
|
+
import { CompanionError } from './errors.js';
|
|
17
18
|
import { openCompanionCall, HOST_CONTROL_TOOLS, HOST_CONTROL_TOOL_NAMES, AVATAR_VISUAL_TOOLS, AVATAR_VISUAL_TOOL_NAMES } from './call.js';
|
|
18
19
|
/** Model tool arguments are model output — tolerate junk without throwing. */
|
|
19
20
|
function parseArgsJson(args) {
|
|
@@ -37,18 +38,10 @@ export function pouchyBrandIconUrl(baseUrl, size = 512) {
|
|
|
37
38
|
* a method before `connect()`). `code` is a stable machine-readable tag you can
|
|
38
39
|
* switch on, shared with the `control.error` stream event vocabulary:
|
|
39
40
|
* `'not_connected'`, `'missing_option'`, `'not_representative'`, or the server's
|
|
40
|
-
* own error code for an HTTP failure (when it sends one).
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
constructor(message, status, code) {
|
|
45
|
-
super(message);
|
|
46
|
-
this.name = 'CompanionError';
|
|
47
|
-
this.status = status;
|
|
48
|
-
if (code)
|
|
49
|
-
this.code = code;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
41
|
+
* own error code for an HTTP failure (when it sends one). Defined in errors.ts
|
|
42
|
+
* (so call.ts shares it cycle-free); re-exported here so the public import
|
|
43
|
+
* path is unchanged. */
|
|
44
|
+
export { CompanionError } from './errors.js';
|
|
52
45
|
const SEEN_CAP = 512;
|
|
53
46
|
export class CompanionClient {
|
|
54
47
|
opts;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Thrown by every helper on an HTTP or client-side failure. `status` is the
|
|
2
|
+
* HTTP status (0 for client-synthesized failures — timeouts, unsupported
|
|
3
|
+
* environments, missing optional deps); `code` is machine-switchable when
|
|
4
|
+
* the server (or the SDK itself) names a cause. */
|
|
5
|
+
export declare class CompanionError extends Error {
|
|
6
|
+
status: number;
|
|
7
|
+
code?: string;
|
|
8
|
+
constructor(message: string, status: number, code?: string);
|
|
9
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// CompanionError — the one error type every SDK helper rejects with (README
|
|
2
|
+
// contract: consumers `switch` on `.code` instead of string-matching prose).
|
|
3
|
+
// Lives in its own module so call.ts can use it without a runtime cycle
|
|
4
|
+
// through client.ts (client.ts re-exports it, keeping the public import path
|
|
5
|
+
// `@pouchy_ai/companion-sdk` → `CompanionError` unchanged).
|
|
6
|
+
/** Thrown by every helper on an HTTP or client-side failure. `status` is the
|
|
7
|
+
* HTTP status (0 for client-synthesized failures — timeouts, unsupported
|
|
8
|
+
* environments, missing optional deps); `code` is machine-switchable when
|
|
9
|
+
* the server (or the SDK itself) names a cause. */
|
|
10
|
+
export class CompanionError extends Error {
|
|
11
|
+
status;
|
|
12
|
+
code;
|
|
13
|
+
constructor(message, status, code) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'CompanionError';
|
|
16
|
+
this.status = status;
|
|
17
|
+
if (code)
|
|
18
|
+
this.code = code;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pouchy_ai/companion-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Embed the Pouchy companion — chat, voice, tools, memory, live world-state, instant UI, and agent-to-agent messaging — in any app, game, or site.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|