@pouchy_ai/companion-sdk 0.21.0 → 0.23.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 +45 -0
- package/README.md +13 -2
- package/dist/client.d.ts +13 -7
- package/dist/client.js +21 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +5 -1
- package/dist/protocol.d.ts +12 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,51 @@ a protocol bump is always called out explicitly here.
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [0.23.0] - 2026-07-11
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`onToolCall` hands you pre-parsed arguments.** The callback now receives a
|
|
20
|
+
`ToolCallEvent` — the `companion.tool_call` wire payload plus `argsJson`:
|
|
21
|
+
`args` pre-parsed as JSON (`undefined` when empty or malformed). Every tool
|
|
22
|
+
handler was re-implementing the same `try { JSON.parse(args) } catch {}`
|
|
23
|
+
boilerplate; now `const { item } = call.argsJson as {...}` just works, and the
|
|
24
|
+
raw `args` string is still there when you need the exact model output.
|
|
25
|
+
`ToolCallEvent` is exported. Backwards-compatible (the type extends
|
|
26
|
+
`ToolCallPayload`).
|
|
27
|
+
|
|
28
|
+
### Docs
|
|
29
|
+
|
|
30
|
+
- The `control.error` stream-plane code vocabulary (`agent_error`,
|
|
31
|
+
`stream_unauthorized`) is now documented in the protocol/API references, the
|
|
32
|
+
README event tables, and pouchy.ai/sdk — previously the codes were emitted
|
|
33
|
+
but listed nowhere.
|
|
34
|
+
- The pouchy.ai/sdk CDN snippet now uses the canonical self-hosted bundle URL
|
|
35
|
+
(`https://pouchy.ai/sdk/companion-sdk.js`) and includes the
|
|
36
|
+
`@elevenlabs/client` import-map entry voice needs.
|
|
37
|
+
- `openCompanionCall` / `VoiceToolBridge` (the advanced voice primitive
|
|
38
|
+
`connectCall`/`startCall` wrap) get a pointer in the package README.
|
|
39
|
+
|
|
40
|
+
No wire-protocol change (`PROTOCOL_VERSION` stays `1`).
|
|
41
|
+
|
|
42
|
+
## [0.22.0] - 2026-07-11
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **Runtime protocol constants are now exported.** `PROTOCOL_VERSION`,
|
|
47
|
+
`INBOUND_TYPES`, and `OUTBOUND_TYPES` are re-exported from the package entry —
|
|
48
|
+
previously only their *types* were reachable. A host can now assert the
|
|
49
|
+
protocol version or enumerate/validate the event vocabulary at runtime without
|
|
50
|
+
hard-coding the strings.
|
|
51
|
+
- **`ToolCallPayload` type.** The `companion.tool_call` payload
|
|
52
|
+
(`{ id, name, args }`) now has a named, exported interface, so a consumer using
|
|
53
|
+
the generic `on('companion.tool_call', …)` gets a typed payload — parity with
|
|
54
|
+
`RenderInterfacePayload`, `ConfirmRequestPayload`, and the other payload types.
|
|
55
|
+
`onToolCall`'s callback is typed against it.
|
|
56
|
+
|
|
57
|
+
No wire-protocol change (`PROTOCOL_VERSION` stays `1`); this is a purely additive
|
|
58
|
+
type/export surface, hence the minor bump.
|
|
59
|
+
|
|
15
60
|
## [0.21.0] - 2026-07-11
|
|
16
61
|
|
|
17
62
|
### Added
|
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ Subscribe with `on(type, fn)` (or `'*'`), or these typed convenience helpers:
|
|
|
67
67
|
| --- | --- | --- |
|
|
68
68
|
| `onMessage(fn)` | `companion.message` | the assistant reply (fires exactly once per turn, streaming or not) |
|
|
69
69
|
| `onDelta(fn)` | *(POST-response SSE)* | **token streaming** — registering makes `sendText` stream the reply as it is generated: `fn(chunk, {reset?})` fires per text chunk (`reset` = clear the partial — that text was tool-call deliberation); `onMessage` then fires once with the authoritative final text (replay-deduplicated). Force per call with `sendText(text, { stream: true \| false })` |
|
|
70
|
-
| `onToolCall(fn)` | `companion.tool_call` | the companion asks your app to run a declared tool → `sendToolResult` |
|
|
70
|
+
| `onToolCall(fn)` | `companion.tool_call` | the companion asks your app to run a declared tool → `sendToolResult`. The call carries `argsJson` — `args` pre-parsed as JSON (undefined on empty/malformed args) |
|
|
71
71
|
| `onRender(fn)` | `companion.ui_action` | **Instant UI** — draw `payload.interface` (platform-neutral genui schema) with your own renderer (web / iOS / Android / CLI). Needs `ui.render` |
|
|
72
72
|
| `onInterfaceUpdate(fn)` | `companion.ui_update` | live `{key,value}` update to an already-rendered panel (no rebuild) |
|
|
73
73
|
| `onSocialMessage(fn)` | `companion.social_message` | inbound A2A friend message, delivered cross-app. Needs `social.message` |
|
|
@@ -77,7 +77,7 @@ Subscribe with `on(type, fn)` (or `'*'`), or these typed convenience helpers:
|
|
|
77
77
|
| `onVoiceInject(fn)` | `companion.voice_inject` | `fn({text, speak})` — a `voiceRelevant` world-state line to say aloud during a live call; route `text` to your voice session when `speak` |
|
|
78
78
|
| `onTyping(fn)` | `companion.typing` | activity indicator — `fn({active})` fires `true` when a turn starts working and `false` when it finishes / pauses, spanning the tool-loop / thinking phase before the first text delta. Drive a "typing…" state |
|
|
79
79
|
| `onUsage(fn)` | `control.usage` | per-token metering echo. _(reserved — not emitted yet)_ |
|
|
80
|
-
| `onError(fn)` | `control.error` | agent / stream errors |
|
|
80
|
+
| `onError(fn)` | `control.error` | agent / stream errors — `agent_error` (server-side turn failed after accept; safe to re-send) or the SDK-synthesized `stream_unauthorized` (stream 401 exhausted reconnects — refresh the token, `start()` again) |
|
|
81
81
|
|
|
82
82
|
### Instant UI
|
|
83
83
|
|
|
@@ -140,6 +140,17 @@ exported: `COMPANION_MODALITIES`, `REPRESENT_SCOPES`, `DEFAULT_MODALITIES`,
|
|
|
140
140
|
`isRepresentScope()`. The list mirrors the server vocabulary and is guarded by
|
|
141
141
|
the SDK's drift test.
|
|
142
142
|
|
|
143
|
+
The wire-protocol runtime constants are exported too — `PROTOCOL_VERSION`,
|
|
144
|
+
`INBOUND_TYPES`, and `OUTBOUND_TYPES` — so you can assert the version or
|
|
145
|
+
enumerate/validate the event vocabulary without hard-coding strings. Every
|
|
146
|
+
outbound payload has a named type; `ToolCallPayload` (`{ id, name, args }`) types
|
|
147
|
+
the `companion.tool_call` event, and `onToolCall`'s callback receives
|
|
148
|
+
`ToolCallEvent` — the payload plus `argsJson` (pre-parsed args).
|
|
149
|
+
|
|
150
|
+
For advanced voice hosts, the lower-level `openCompanionCall(client, options)`
|
|
151
|
+
primitive that `connectCall`/`startCall` wrap is exported too (bring-your-own
|
|
152
|
+
call lifecycle; see `docs/companion-integration-faq.md`).
|
|
153
|
+
|
|
143
154
|
## Representative mode (代聊)
|
|
144
155
|
|
|
145
156
|
Pass a `visitor` and the session flips from **owner-facing** to **representative**:
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AudioClipPayload, CompanionEnvelope, ConfirmRequestPayload, ExpressionPayload, InterfaceUpdatePayload, OutboundType, PendingConfirm, RenderInterfacePayload, SocialMessagePayload, TypingPayload, UsagePayload, VoiceInjectPayload, WorldStateEvent } from './protocol.js';
|
|
1
|
+
import type { AudioClipPayload, CompanionEnvelope, ConfirmRequestPayload, ExpressionPayload, InterfaceUpdatePayload, OutboundType, PendingConfirm, RenderInterfacePayload, SocialMessagePayload, ToolCallPayload, TypingPayload, UsagePayload, VoiceInjectPayload, WorldStateEvent } from './protocol.js';
|
|
2
2
|
/** Ergonomic world-state input: a WorldStateEvent with the CloudEvents plumbing
|
|
3
3
|
* (specversion / id / source) optional — sendWorldState fills them. */
|
|
4
4
|
export type WorldStateInput<D = unknown> = Omit<WorldStateEvent<D>, 'specversion' | 'id' | 'source'> & Partial<Pick<WorldStateEvent<D>, 'specversion' | 'id' | 'source'>>;
|
|
@@ -75,6 +75,13 @@ export interface CompanionToolDecl {
|
|
|
75
75
|
description?: string;
|
|
76
76
|
parameters?: Record<string, unknown>;
|
|
77
77
|
}
|
|
78
|
+
/** What `onToolCall` hands your handler: the `companion.tool_call` wire payload
|
|
79
|
+
* plus `argsJson` — `args` pre-parsed as JSON. `undefined` when `args` is
|
|
80
|
+
* empty or not valid JSON; keep reading the raw `args` string when you need
|
|
81
|
+
* the exact model output. */
|
|
82
|
+
export interface ToolCallEvent extends ToolCallPayload {
|
|
83
|
+
argsJson?: unknown;
|
|
84
|
+
}
|
|
78
85
|
/** Voice-plane credentials, discriminated by provider (see startCall). */
|
|
79
86
|
export type CallCredentials = {
|
|
80
87
|
provider: 'elevenlabs-convai';
|
|
@@ -332,12 +339,11 @@ export declare class CompanionClient {
|
|
|
332
339
|
* string fed back to the voice model. Times out so a missing result can't
|
|
333
340
|
* hang the call. */
|
|
334
341
|
private invokeVoiceTool;
|
|
335
|
-
/** Convenience: subscribe to tool-call requests from the companion.
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}, envelope: CompanionEnvelope) => void): () => void;
|
|
342
|
+
/** Convenience: subscribe to tool-call requests from the companion. The call
|
|
343
|
+
* carries the wire payload plus `argsJson` — `args` pre-parsed as JSON
|
|
344
|
+
* (undefined when empty or malformed), so handlers don't each re-implement
|
|
345
|
+
* the same try/catch around `JSON.parse(args)`. */
|
|
346
|
+
onToolCall(handler: (call: ToolCallEvent, envelope: CompanionEnvelope) => void): () => void;
|
|
341
347
|
/** Convenience: subscribe to errors the companion surfaces — server-side agent
|
|
342
348
|
* errors and stream failures (e.g. a permanent `stream_unauthorized`) both
|
|
343
349
|
* arrive as `control.error`. Returns an unsubscribe fn. */
|
package/dist/client.js
CHANGED
|
@@ -8,11 +8,24 @@
|
|
|
8
8
|
// await c.sendText('how am I doing?');
|
|
9
9
|
//
|
|
10
10
|
// Pure, dependency-free, isomorphic (browser + Node 18+ fetch). The transport is
|
|
11
|
-
// an internal detail
|
|
12
|
-
//
|
|
11
|
+
// an internal detail: the default REST/SSE plane, or an opt-in WebSocket plane
|
|
12
|
+
// (ws-transport.ts) that degrades back to SSE on failure — both sit behind this
|
|
13
|
+
// same API. Protocol types are a self-contained copy of the server's contract,
|
|
14
|
+
// kept in lockstep by protocol.drift.test.ts.
|
|
13
15
|
import { PROTOCOL_VERSION } from './protocol.js';
|
|
14
16
|
import { parseSse } from './sse.js';
|
|
15
17
|
import { openCompanionCall, HOST_CONTROL_TOOLS, HOST_CONTROL_TOOL_NAMES, AVATAR_VISUAL_TOOLS, AVATAR_VISUAL_TOOL_NAMES } from './call.js';
|
|
18
|
+
/** Model tool arguments are model output — tolerate junk without throwing. */
|
|
19
|
+
function parseArgsJson(args) {
|
|
20
|
+
if (!args.trim())
|
|
21
|
+
return undefined;
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(args);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
16
29
|
/** Canonical URL of the official Pouchy brand icon at `size` px, derived from a
|
|
17
30
|
* deployment origin. Standalone (no client/token needed) so a surface can show
|
|
18
31
|
* the Pouchy mark before/without connecting. */
|
|
@@ -499,12 +512,16 @@ export class CompanionClient {
|
|
|
499
512
|
});
|
|
500
513
|
});
|
|
501
514
|
}
|
|
502
|
-
/** Convenience: subscribe to tool-call requests from the companion.
|
|
515
|
+
/** Convenience: subscribe to tool-call requests from the companion. The call
|
|
516
|
+
* carries the wire payload plus `argsJson` — `args` pre-parsed as JSON
|
|
517
|
+
* (undefined when empty or malformed), so handlers don't each re-implement
|
|
518
|
+
* the same try/catch around `JSON.parse(args)`. */
|
|
503
519
|
onToolCall(handler) {
|
|
504
520
|
return this.on('companion.tool_call', (env) => {
|
|
505
521
|
const p = env.payload;
|
|
506
522
|
if (typeof p?.id === 'string' && typeof p?.name === 'string') {
|
|
507
|
-
|
|
523
|
+
const args = typeof p.args === 'string' ? p.args : '';
|
|
524
|
+
handler({ id: p.id, name: p.name, args, argsJson: parseArgsJson(args) }, env);
|
|
508
525
|
}
|
|
509
526
|
});
|
|
510
527
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { CompanionClient, type CompanionClientOptions } from './client.js';
|
|
2
2
|
export { CompanionClient, CompanionError, pouchyBrandIconUrl } from './client.js';
|
|
3
|
-
export type { CompanionClientOptions, HelloAck, RecalledMemory, CompanionTurn, CallCredentials, CompanionToolDecl, WorldStateInput, CompanionAvatar, CompanionWallet, WalletBalance, BrandIconSize, EndSessionResult } from './client.js';
|
|
3
|
+
export type { CompanionClientOptions, HelloAck, RecalledMemory, CompanionTurn, CallCredentials, CompanionToolDecl, ToolCallEvent, WorldStateInput, CompanionAvatar, CompanionWallet, WalletBalance, BrandIconSize, EndSessionResult } from './client.js';
|
|
4
4
|
export { openCompanionCall, HOST_CONTROL_TOOLS, HOST_CONTROL_TOOL_NAMES, AVATAR_VISUAL_TOOLS, AVATAR_VISUAL_TOOL_NAMES } from './call.js';
|
|
5
5
|
export type { CompanionCall, CompanionCallOptions, VoiceToolBridge } from './call.js';
|
|
6
6
|
export { COMPANION_SCOPES, COMPANION_MODALITIES, SENSITIVE_SCOPES, REPRESENT_SCOPES, DEFAULT_SCOPES, DEFAULT_MODALITIES, isSensitiveScope, isRepresentScope, hasScope } from './scopes.js';
|
|
7
7
|
export type { CompanionScope, CompanionModality } from './scopes.js';
|
|
8
|
-
export type { CompanionEnvelope, OutboundType, InboundType, WorldStateEvent, RenderInterfacePayload, InterfaceUpdatePayload, SocialMessagePayload, ConfirmRequestPayload, PendingConfirm, AudioClipPayload, ExpressionPayload, TypingPayload, VoiceInjectPayload, UsagePayload } from './protocol.js';
|
|
8
|
+
export type { CompanionEnvelope, OutboundType, InboundType, WorldStateEvent, RenderInterfacePayload, InterfaceUpdatePayload, SocialMessagePayload, ConfirmRequestPayload, PendingConfirm, ToolCallPayload, AudioClipPayload, ExpressionPayload, TypingPayload, VoiceInjectPayload, UsagePayload } from './protocol.js';
|
|
9
|
+
export { PROTOCOL_VERSION, INBOUND_TYPES, OUTBOUND_TYPES } from './protocol.js';
|
|
9
10
|
/** Create a companion client. */
|
|
10
11
|
export declare function createCompanion(opts: CompanionClientOptions): CompanionClient;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Companion SDK — public entry. Embed the Pouchy companion in a third-party
|
|
2
|
-
// surface (web / app / game / hardware) over the REST/SSE plane
|
|
2
|
+
// surface (web / app / game / hardware) over the REST/SSE plane (with an
|
|
3
|
+
// optional WebSocket transport that degrades to SSE).
|
|
3
4
|
//
|
|
4
5
|
// import { createCompanion } from '$lib/companion-sdk';
|
|
5
6
|
// const c = createCompanion({ baseUrl: 'https://pouchy.ai', token: PAT });
|
|
@@ -12,6 +13,9 @@ import { CompanionClient } from './client.js';
|
|
|
12
13
|
export { CompanionClient, CompanionError, pouchyBrandIconUrl } from './client.js';
|
|
13
14
|
export { openCompanionCall, HOST_CONTROL_TOOLS, HOST_CONTROL_TOOL_NAMES, AVATAR_VISUAL_TOOLS, AVATAR_VISUAL_TOOL_NAMES } from './call.js';
|
|
14
15
|
export { COMPANION_SCOPES, COMPANION_MODALITIES, SENSITIVE_SCOPES, REPRESENT_SCOPES, DEFAULT_SCOPES, DEFAULT_MODALITIES, isSensitiveScope, isRepresentScope, hasScope } from './scopes.js';
|
|
16
|
+
// Runtime protocol constants — so a host can assert PROTOCOL_VERSION or
|
|
17
|
+
// enumerate/validate the event vocabulary without hard-coding the strings.
|
|
18
|
+
export { PROTOCOL_VERSION, INBOUND_TYPES, OUTBOUND_TYPES } from './protocol.js';
|
|
15
19
|
/** Create a companion client. */
|
|
16
20
|
export function createCompanion(opts) {
|
|
17
21
|
return new CompanionClient(opts);
|
package/dist/protocol.d.ts
CHANGED
|
@@ -76,6 +76,18 @@ export interface PendingConfirm {
|
|
|
76
76
|
/** Epoch ms when the companion asked. */
|
|
77
77
|
createdAt: number;
|
|
78
78
|
}
|
|
79
|
+
/** Payload of a `companion.tool_call` event — the companion is asking the host
|
|
80
|
+
* to run one of the app-declared tools it was given at `hello`. `args` is the
|
|
81
|
+
* raw JSON string the model produced (parse it yourself); reply by posting the
|
|
82
|
+
* result back with `client.sendToolResult(id, …)`. */
|
|
83
|
+
export interface ToolCallPayload {
|
|
84
|
+
/** Correlation id — echo it back on the tool result. */
|
|
85
|
+
id: string;
|
|
86
|
+
/** The declared tool name the model chose. */
|
|
87
|
+
name: string;
|
|
88
|
+
/** The model's arguments as a raw JSON string. */
|
|
89
|
+
args: string;
|
|
90
|
+
}
|
|
79
91
|
/** Payload of a `companion.ui_update` event — a live change to an
|
|
80
92
|
* already-rendered Instant UI panel: write each `{ key, value }` into the
|
|
81
93
|
* panel's state bag (re-evaluating templates / progress / `when`), without
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pouchy_ai/companion-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Embed the Pouchy companion
|
|
3
|
+
"version": "0.23.0",
|
|
4
|
+
"description": "Embed the Pouchy companion \u2014 chat, voice, tools, memory, live world-state, instant UI, and agent-to-agent messaging \u2014 in any app, game, or site.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"homepage": "https://pouchy.ai",
|