@pouchy_ai/companion-sdk 0.10.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 ADDED
@@ -0,0 +1,86 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@pouchy_ai/companion-sdk` are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+ This package follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
7
+ with the usual pre-1.0 caveat: while the major version is `0`, a **minor** bump
8
+ (`0.x.0`) may contain breaking changes and a **patch** bump (`0.x.y`) is reserved
9
+ for backwards-compatible fixes and additions. The wire protocol has its own
10
+ version (`PROTOCOL_VERSION`, currently `1`) guarded by `protocol.drift.test.ts`;
11
+ a protocol bump is always called out explicitly here.
12
+
13
+ ## [Unreleased]
14
+
15
+ ## [0.10.0] - 2026-06-28
16
+
17
+ Completes the SDK surface for all six companion capabilities, with Instant UI and
18
+ cross-app A2A added. All changes are **additive** (new event types are ignored by
19
+ older receivers — `PROTOCOL_VERSION` stays `1`).
20
+
21
+ ### Added
22
+
23
+ - **Instant UI.** The companion can render an interactive panel on the host:
24
+ `companion.ui_action` (`onRender`) carries a platform-neutral genui interface
25
+ (`{ title?, nodes, state?, computed?, reportChanges? }`), and
26
+ `companion.ui_update` (`onInterfaceUpdate`) applies live `{key,value}` writes to
27
+ an already-rendered panel. Gated by the new `ui.render` scope. The same payload
28
+ renders on web, native iOS/Android, or a CLI — reference renderers in
29
+ `examples/web-instant-ui`, `examples/native-instant-ui` (SwiftUI + Jetpack
30
+ Compose). New types `RenderInterfacePayload` / `InterfaceUpdatePayload`. See
31
+ `docs/companion-instant-ui.md`.
32
+ - **Cross-app A2A.** `companion.social_message` (`onSocialMessage`) delivers an
33
+ inbound A2A friend message to any embed whose token holds `social.message`, not
34
+ just the first-party app. New type `SocialMessagePayload`.
35
+ - **Confirmation observation + biometric cue.** `onConfirmRequest`
36
+ (`companion.confirm_request`) lets an embed surface a pending sensitive-op
37
+ approval (observe-only; approval stays first-party). The payload now carries an
38
+ advisory `stepUp` flag (true for money ops) so a first-party surface can gate
39
+ approval behind a passkey / Face ID. New type `ConfirmRequestPayload`.
40
+ - **Typed event helpers** for the remaining outbound events: `onAudio`
41
+ (`companion.audio`), `onExpression` (`companion.expression`), `onUsage`
42
+ (`control.usage`). New types `AudioClipPayload` / `ExpressionPayload` /
43
+ `UsagePayload`.
44
+ - **Capabilities map** doc (`docs/companion-capabilities.md`) — the six
45
+ capabilities, their SDK surface, and the beyond-the-sandbox model.
46
+
47
+ ### Protocol
48
+
49
+ - Outbound types added: `companion.ui_action`* / `companion.ui_update` /
50
+ `companion.social_message`. (*`ui_action` was reserved previously; now emitted.)
51
+ Non-breaking — receivers ignore unknown types; `PROTOCOL_VERSION` unchanged (`1`).
52
+
53
+ ## [0.9.0] - 2026-06-23
54
+
55
+ First publicly published release (public npm, `publishConfig.access: "public"`,
56
+ proprietary license — see `LICENSE`). No code changes versus the previously
57
+ self-hosted/CDN build; this entry captures the surface that ships publicly.
58
+
59
+ ### Added
60
+
61
+ - **Public distribution.** Installable from the public npm registry as
62
+ `@pouchy_ai/companion-sdk`; also resolvable via `esm.sh` / `jsDelivr` for
63
+ no-bundler / import-map consumers, and self-hosted at
64
+ `https://www.pouchy.ai/sdk/companion-sdk.js`.
65
+ - **Chat.** Text and multimodal (text + images) messaging.
66
+ - **Voice.** Live WebRTC call (`connectCall`), provider-agnostic across OpenAI
67
+ Realtime (zero extra deps) and ElevenLabs Convai (optional
68
+ `@elevenlabs/client` peer dependency).
69
+ - **Tools.** Bidirectional tool calling — the companion invokes app-declared
70
+ actions and the app reports results back.
71
+ - **Memory.** Scope-gated read/write into the user's recall namespace.
72
+ - **Live world-state.** CloudEvents-shaped "play-along" channel
73
+ (`sendWorldState`) for streaming contextual data to the companion.
74
+ - **Representative mode (代聊).** Visitor-facing sessions answered on the owner's
75
+ behalf using only screened context (`represent` scope + optional
76
+ `expose:*` / `represent:*` scopes).
77
+ - **Avatar.** VRM (3D) and 2D portrait retrieval.
78
+ - **Transports.** REST + Server-Sent Events by default; optional WebSocket
79
+ (`stream: 'websocket'`) with automatic SSE fallback.
80
+ - **Auth.** Personal Access Tokens (`pchy_…`) and "Login with Pouchy" OAuth 2.1
81
+ (Authorization Code + PKCE, rotating refresh tokens).
82
+ - **Versioned wire protocol.** `PROTOCOL_VERSION = 1`, kept in lockstep with the
83
+ server by `protocol.drift.test.ts` (fails CI on divergence).
84
+
85
+ [Unreleased]: https://github.com/oviswang/Pouchy/compare/companion-sdk-v0.9.0...HEAD
86
+ [0.9.0]: https://github.com/oviswang/Pouchy/releases/tag/companion-sdk-v0.9.0
package/LICENSE ADDED
@@ -0,0 +1,41 @@
1
+ Pouchy Companion SDK License
2
+ Copyright (c) 2026 Pouchy.ai. All Rights Reserved.
3
+
4
+ This license governs use of the "@pouchy_ai/companion-sdk" software package (the
5
+ "SDK") as published to the npm registry. The SDK is proprietary software owned
6
+ by Pouchy.ai. By installing, copying, or using the SDK you agree to these terms.
7
+
8
+ 1. GRANT. Subject to these terms, Pouchy.ai grants you a worldwide,
9
+ non-exclusive, non-transferable, royalty-free, revocable license to install
10
+ and use the SDK, as distributed, solely to build and operate applications
11
+ that integrate with Pouchy.ai's official services and APIs.
12
+
13
+ 2. RESTRICTIONS. Except to the extent a restriction below is prohibited by
14
+ applicable law, you may not:
15
+ (a) modify, adapt, or create derivative works of the SDK's source for
16
+ redistribution;
17
+ (b) redistribute, sublicense, sell, rent, or lease the SDK as a standalone
18
+ product, or republish it under a different name;
19
+ (c) reverse engineer, decompile, or disassemble the SDK except to the extent
20
+ necessary for interoperability and expressly permitted by law;
21
+ (d) use the SDK to build or operate a service that competes with Pouchy.ai's
22
+ services, or to access Pouchy.ai's services in violation of their terms;
23
+ (e) remove or alter any copyright, trademark, or other proprietary notices.
24
+
25
+ 3. RESERVATION OF RIGHTS. All rights not expressly granted are reserved by
26
+ Pouchy.ai. No rights are granted in Pouchy.ai's source repositories,
27
+ trademarks, or services beyond what is needed to use the SDK as described.
28
+
29
+ 4. TERMINATION. This license terminates automatically if you breach it. On
30
+ termination you must stop using and delete all copies of the SDK.
31
+
32
+ 5. NO WARRANTY. THE SDK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
35
+
36
+ 6. LIMITATION OF LIABILITY. IN NO EVENT SHALL POUCHY.AI BE LIABLE FOR ANY CLAIM,
37
+ DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR
38
+ OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SDK OR THE USE OR
39
+ OTHER DEALINGS IN THE SDK.
40
+
41
+ For any other use, or for written permission, contact legal@pouchy.ai.
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # @pouchy_ai/companion-sdk
2
+
3
+ Embed the Pouchy companion — chat, voice, tools, memory, live world-state,
4
+ **Instant UI**, and **agent-to-agent messaging** — in any app, game, or site.
5
+
6
+ All six companion capabilities are reachable over the SDK (memory · reasoning ·
7
+ skills · A2A/social · wallet · instant UI), and each rides a **platform-neutral**
8
+ contract — so the same companion runs on web, native iOS/Android, or a CLI. See
9
+ [`docs/companion-capabilities.md`](../../docs/companion-capabilities.md).
10
+
11
+ ## Install
12
+
13
+ ```sh
14
+ npm i @pouchy_ai/companion-sdk
15
+ ```
16
+
17
+ No bundler? Pull it from a CDN via an import map instead — see
18
+ [`docs/companion-integration-faq.md`](../../docs/companion-integration-faq.md).
19
+ Changes per release are tracked in [`CHANGELOG.md`](./CHANGELOG.md).
20
+
21
+ ```ts
22
+ import { createCompanion } from '@pouchy_ai/companion-sdk';
23
+
24
+ const companion = createCompanion({ baseUrl: 'https://www.pouchy.ai', token: PAT });
25
+ await companion.connect();
26
+ companion.onMessage((t) => console.log(t));
27
+ companion.start();
28
+ await companion.sendText('hey');
29
+ await companion.connectCall(); // live voice (browser)
30
+ companion.sendWorldState({ type: 'game.player.hp', data: { hp: 12 }, retained: true });
31
+ ```
32
+
33
+ - **Guide:** [`docs/companion-quickstart.md`](../../docs/companion-quickstart.md)
34
+ - **Spec:** [`docs/companion-sdk-protocol.md`](../../docs/companion-sdk-protocol.md)
35
+ - **API reference:** [`docs/companion-api-reference.md`](../../docs/companion-api-reference.md)
36
+ - **Capabilities map:** [`docs/companion-capabilities.md`](../../docs/companion-capabilities.md)
37
+ - **Instant UI renderer contract:** [`docs/companion-instant-ui.md`](../../docs/companion-instant-ui.md)
38
+
39
+ ## Events
40
+
41
+ Subscribe with `on(type, fn)` (or `'*'`), or these typed convenience helpers:
42
+
43
+ | Helper | Event | Use |
44
+ | --- | --- | --- |
45
+ | `onMessage(fn)` | `companion.message` | streamed assistant text |
46
+ | `onToolCall(fn)` | `companion.tool_call` | the companion asks your app to run a declared tool → `sendToolResult` |
47
+ | `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` |
48
+ | `onInterfaceUpdate(fn)` | `companion.ui_update` | live `{key,value}` update to an already-rendered panel (no rebuild) |
49
+ | `onSocialMessage(fn)` | `companion.social_message` | inbound A2A friend message, delivered cross-app. Needs `social.message` |
50
+ | `onConfirmRequest(fn)` | `companion.confirm_request` | observe a sensitive-op approval (`stepUp:true` ⇒ the first-party surface should gate it with a biometric). Observe-only — approval is first-party |
51
+ | `onAudio(fn)` | `companion.audio` | TTS clip (non-call modality) |
52
+ | `onExpression(fn)` | `companion.expression` | avatar viseme / expression / gesture |
53
+ | `onUsage(fn)` | `control.usage` | per-token metering echo |
54
+ | `onError(fn)` | `control.error` | agent / stream errors |
55
+
56
+ ### Instant UI
57
+
58
+ ```ts
59
+ import { renderInterface } from './instant-ui'; // your renderer (web example in examples/web-instant-ui)
60
+ let panel: ReturnType<typeof renderInterface> | null = null;
61
+ companion.onRender(({ interface: ui }) => { panel = renderInterface(ui, mountEl); });
62
+ companion.onInterfaceUpdate(({ update }) => panel?.applyUpdate(update));
63
+ ```
64
+
65
+ Reference renderers ship in [`examples/`](../../examples): `web-instant-ui` (vanilla),
66
+ `native-instant-ui` (SwiftUI + Jetpack Compose), and `cli-skills` (terminal +
67
+ local/device skills).
68
+
69
+ ## Representative mode (代聊)
70
+
71
+ Pass a `visitor` and the session flips from **owner-facing** to **representative**:
72
+ the companion answers *that visitor* **on the owner's behalf** (代聊 /
73
+ customer-service) using only **screened** owner context — never the owner's private
74
+ memory, system prompt, or PII. Works over text and voice.
75
+
76
+ ```ts
77
+ const c = createCompanion({
78
+ baseUrl: 'https://www.pouchy.ai',
79
+ token: OWNER_PAT, // must hold the `represent` scope
80
+ surface: 'support-widget',
81
+ appContext: { name: 'AcmeShop', description: 'Order support' },
82
+ visitor: { id: stableVisitorId, displayName: 'Sam' } // stable per end-user
83
+ });
84
+ const ack = await c.connect(); // → { representative: true, visitorPaired, … }
85
+ await c.sendText('do you ship to Canada?');
86
+ const call = await c.connectCall(); // same, over voice
87
+ ```
88
+
89
+ Scopes (granted by the owner's **"Let it represent you to visitors"** key toggle):
90
+
91
+ | Scope | Adds |
92
+ | --- | --- |
93
+ | `represent` | **required** — open a visitor-facing session |
94
+ | `expose:knowledge` | answer from the owner's knowledge base ("My materials") |
95
+ | `expose:facts` | share a wider set of screened facts |
96
+ | `represent:remember` | durable per-visitor notes across visits (isolated store) |
97
+ | `represent:pair` | `c.pairVisitor(visitorPAT)` — pair a visitor who's also a Pouchy user → unlock A2A |
98
+
99
+ Without `represent`, supplying a `visitor` is rejected (`403`). First-party tools
100
+ (wallet / skills / social) are withheld; your own declared tools still work. Full
101
+ walkthrough: **[API reference §3.3–3.4](../../docs/companion-api-reference.md)** and
102
+ the [source README](../../src/lib/companion-sdk/README.md#representative-mode-代聊).
103
+
104
+ ## Voice (optional dependency)
105
+
106
+ `connectCall()` for the **ElevenLabs Convai** provider needs the optional peer
107
+ dependency:
108
+
109
+ ```sh
110
+ npm i @elevenlabs/client
111
+ ```
112
+
113
+ OpenAI Realtime needs no extra dependency (self-contained WebRTC).
114
+
115
+ ## Build & publish
116
+
117
+ The source lives in the app repo at `src/lib/companion-sdk` and is decoupled from
118
+ any `$lib` import, so this package builds with plain `tsc`:
119
+
120
+ ```sh
121
+ cd packages/companion-sdk
122
+ npm run build # tsc → dist/ (ESM + .d.ts)
123
+ npm publish # public scope (publishConfig.access: "public"); runs build via prepublishOnly
124
+ ```
125
+
126
+ The wire contract (`protocol.ts`) is a self-contained mirror of the server's;
127
+ `protocol.drift.test.ts` (run by the app's vitest) fails CI if they diverge.
128
+
129
+ Full release steps (version bump, `CHANGELOG.md`, drift test, tag) live in
130
+ [`PUBLISHING.md`](./PUBLISHING.md).
131
+
132
+ ## License
133
+
134
+ Proprietary — © 2026 Pouchy.ai. The published package may be installed and used
135
+ to build integrations with Pouchy's official services; all other rights are
136
+ reserved. See [`LICENSE`](./LICENSE).
package/dist/call.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ import type { CallCredentials } from './client.js';
2
+ /** Lets the live voice call invoke the app's declared tools (pause_game,
3
+ * set_feature, …). The companion's voice LLM calls a tool → invoke() runs the
4
+ * app's onToolCall handler and resolves with a result string fed back to the
5
+ * model. Wired by connectCall from the tools declared at createCompanion(). */
6
+ export interface VoiceToolBridge {
7
+ tools: {
8
+ name: string;
9
+ description?: string;
10
+ parameters?: Record<string, unknown>;
11
+ }[];
12
+ invoke: (name: string, argsJson: string) => Promise<string>;
13
+ }
14
+ /** Universal "host control" verbs the companion can call on ANY surface (web /
15
+ * game / app / hardware), regardless of provider. They're generic on purpose —
16
+ * the SPECIFIC intent rides in the string params, which YOUR surface interprets
17
+ * — so a single fixed schema set serves every embed AND can be pre-registered on
18
+ * the (otherwise static) ElevenLabs Convai agent. `invoke_action` is the
19
+ * catch-all trigger; the SDK unwraps it to the named action so it reaches your
20
+ * onToolCall just like a declared tool. The others pass through by name. */
21
+ export declare const HOST_CONTROL_TOOLS: VoiceToolBridge['tools'];
22
+ /** Names of the host-control verbs (for routing). */
23
+ export declare const HOST_CONTROL_TOOL_NAMES: readonly string[];
24
+ /** Avatar gesture/expression tools the embodied ("形象") companion calls to emote
25
+ * — drive a VRM/3D body's gestures and facial expression. These are offered on
26
+ * EVERY embed (like the host verbs) so the companion can express itself without
27
+ * each third party re-declaring them, and — crucially — so the SDK can register
28
+ * a no-op handler for them on the ElevenLabs Convai path, where the shared agent
29
+ * is pre-configured to call play_gesture / play_expression regardless of what the
30
+ * embed declares. An integrator that actually renders an avatar opts in by
31
+ * declaring (or handling) the same tool name and the SDK routes the call to them;
32
+ * otherwise it answers with a silent no-op success (see invokeVoiceTool / emit),
33
+ * so a pure audio or 2D embed can ignore avatars entirely and the companion's
34
+ * emote calls never error. Enum values mirror the canonical GESTURE_CATEGORIES /
35
+ * EXPRESSION_INTENTS the avatar runtime understands (kept inline so the SDK stays
36
+ * self-contained). */
37
+ export declare const AVATAR_VISUAL_TOOLS: VoiceToolBridge['tools'];
38
+ /** Names of the avatar visual tools (for routing + the no-op fallback). */
39
+ export declare const AVATAR_VISUAL_TOOL_NAMES: readonly string[];
40
+ export interface CompanionCallOptions {
41
+ /** Element to route remote audio to. One is created if omitted. */
42
+ audioElement?: HTMLAudioElement;
43
+ onTranscript?: (e: {
44
+ role: 'user' | 'assistant';
45
+ text: string;
46
+ }) => void;
47
+ onSpeakingChange?: (speaking: boolean) => void;
48
+ onError?: (err: Error) => void;
49
+ }
50
+ export interface CompanionCall {
51
+ /** Hang up. Idempotent. */
52
+ close: () => void;
53
+ /** Inject an out-of-band context line. `speak: true` makes the companion react
54
+ * now; false stages it for the next turn. */
55
+ injectEvent: (text: string, speak?: boolean) => void;
56
+ provider: CallCredentials['provider'];
57
+ }
58
+ /** Open a live call from pre-minted credentials. */
59
+ export declare function openCompanionCall(creds: CallCredentials, opts?: CompanionCallOptions, bridge?: VoiceToolBridge): Promise<CompanionCall>;