@primoia/vocall-react 0.1.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/LICENSE +21 -0
- package/README.md +519 -0
- package/dist/index.cjs +2056 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +530 -0
- package/dist/index.d.ts +530 -0
- package/dist/index.js +2015 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Primoia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# Vocall SDK for Next.js / React
|
|
2
|
+
|
|
3
|
+
Integrate AI-powered voice and chat assistants into React and Next.js applications using the Vocall AAP (Agent-Application Protocol).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **React-native hooks** -- `useVocall`, `useVocallField`, and `useVocallAction` provide reactive state with zero boilerplate.
|
|
10
|
+
- **Plug-and-play components** -- `VocallChat`, `VocallFab`, and `VocallStatusPill` give you a full chat overlay out of the box.
|
|
11
|
+
- **Declarative manifest** -- Describe your screens, fields, and actions once; the engine handles the rest.
|
|
12
|
+
- **Automatic command execution** -- The SDK receives server commands (fill, navigate, click, etc.) and applies them to registered DOM elements.
|
|
13
|
+
- **Typewriter fill animation** -- Field values are filled character-by-character for a natural feel.
|
|
14
|
+
- **Auto-reconnect** -- Exponential back-off reconnection with up to 10 retry attempts.
|
|
15
|
+
- **Streaming tokens** -- Chat responses stream token-by-token via `useSyncExternalStore` for tear-free rendering.
|
|
16
|
+
- **Next.js App Router ready** -- All hooks and components are marked `'use client'`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @vocall/react-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Peer dependencies:** `react >= 18.0.0` and `react-dom >= 18.0.0`.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### 1. Wrap your app with `VocallProvider`
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// app/layout.tsx (Next.js App Router example)
|
|
36
|
+
import { VocallProvider } from '@vocall/react-sdk';
|
|
37
|
+
|
|
38
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
39
|
+
return (
|
|
40
|
+
<html lang="en">
|
|
41
|
+
<body>
|
|
42
|
+
<VocallProvider serverUrl="wss://your-vocall-server/connect">
|
|
43
|
+
{children}
|
|
44
|
+
</VocallProvider>
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Connect and send messages
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
'use client';
|
|
55
|
+
|
|
56
|
+
import { useVocall, useVocallField, ManifestMessage, FieldType } from '@vocall/react-sdk';
|
|
57
|
+
import { useEffect, useState } from 'react';
|
|
58
|
+
|
|
59
|
+
const manifest: ManifestMessage = {
|
|
60
|
+
type: 'manifest',
|
|
61
|
+
app: 'my-app',
|
|
62
|
+
screens: {
|
|
63
|
+
home: {
|
|
64
|
+
id: 'home',
|
|
65
|
+
label: 'Home',
|
|
66
|
+
fields: [
|
|
67
|
+
{ id: 'name', type: FieldType.Text, label: 'Name' },
|
|
68
|
+
{ id: 'email', type: FieldType.Email, label: 'Email' },
|
|
69
|
+
],
|
|
70
|
+
actions: [
|
|
71
|
+
{ id: 'submit', label: 'Submit' },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export default function HomePage() {
|
|
78
|
+
const { connect, connected, status, messages, sendText } = useVocall();
|
|
79
|
+
const nameField = useVocallField('home', 'name');
|
|
80
|
+
const emailField = useVocallField('home', 'email');
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
connect(manifest);
|
|
84
|
+
}, [connect]);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div>
|
|
88
|
+
<p>Status: {status} | Connected: {String(connected)}</p>
|
|
89
|
+
|
|
90
|
+
<input ref={nameField.ref} placeholder="Name" />
|
|
91
|
+
<input ref={emailField.ref} placeholder="Email" />
|
|
92
|
+
|
|
93
|
+
<ul>
|
|
94
|
+
{messages.map((msg, i) => (
|
|
95
|
+
<li key={i}><strong>{msg.role}:</strong> {msg.text}</li>
|
|
96
|
+
))}
|
|
97
|
+
</ul>
|
|
98
|
+
|
|
99
|
+
<input
|
|
100
|
+
onKeyDown={(e) => {
|
|
101
|
+
if (e.key === 'Enter') sendText(e.currentTarget.value);
|
|
102
|
+
}}
|
|
103
|
+
placeholder="Ask the assistant..."
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Hooks API
|
|
113
|
+
|
|
114
|
+
### `useVocall()`
|
|
115
|
+
|
|
116
|
+
Main hook for interacting with the Vocall client. Must be used inside a `<VocallProvider>`.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const {
|
|
120
|
+
client, // VocallClient -- the underlying client instance
|
|
121
|
+
status, // VocallStatus -- current status enum value
|
|
122
|
+
messages, // ChatMessage[] -- conversation history (read-only)
|
|
123
|
+
connected, // boolean -- true when the WebSocket is open
|
|
124
|
+
sessionId, // string | null -- server-assigned session ID
|
|
125
|
+
sendText, // (text: string) => void
|
|
126
|
+
connect, // (manifest: ManifestMessage) => void
|
|
127
|
+
disconnect, // () => void
|
|
128
|
+
clearMessages, // () => void
|
|
129
|
+
} = useVocall();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
All reactive values (`status`, `messages`, `connected`, `sessionId`) are backed by `useSyncExternalStore` for concurrent-safe reads.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### `useVocallField(screenId, fieldId, options?)`
|
|
137
|
+
|
|
138
|
+
Registers a DOM element as a controllable field. The engine can then fill, clear, focus, highlight, scroll to, enable, or disable it.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const { ref, registered } = useVocallField('invoice', 'recipient_name');
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
| Return | Type | Description |
|
|
145
|
+
|-----------|-----------------------------------|-----------------------------------------------|
|
|
146
|
+
| `ref` | `(el: HTMLElement \| null) => void` | Callback ref -- attach to your input element. |
|
|
147
|
+
| `registered` | `boolean` | Whether the field is currently registered. |
|
|
148
|
+
|
|
149
|
+
**Usage:**
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
<input ref={ref} placeholder="Recipient" />
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Custom value accessors** (for controlled inputs):
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
const [value, setValue] = useState('');
|
|
159
|
+
const { ref } = useVocallField('invoice', 'amount', {
|
|
160
|
+
setValue: (v) => setValue(v),
|
|
161
|
+
getValue: () => value,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
<input ref={ref} value={value} onChange={(e) => setValue(e.target.value)} />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### `useVocallAction(screenId, actionId, callback)`
|
|
170
|
+
|
|
171
|
+
Registers a callback that the engine invokes when the server sends a `click` command for the given action.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
useVocallAction('invoice', 'submit', async () => {
|
|
175
|
+
await submitForm();
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The callback ref is kept stable internally, so the latest closure is always called without re-registering on every render.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Components
|
|
184
|
+
|
|
185
|
+
### `VocallChat`
|
|
186
|
+
|
|
187
|
+
A ready-made chat panel with message bubbles, status indicators, and a text input.
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
import { VocallChat } from '@vocall/react-sdk';
|
|
191
|
+
|
|
192
|
+
<VocallChat
|
|
193
|
+
open={chatOpen}
|
|
194
|
+
onClose={() => setChatOpen(false)}
|
|
195
|
+
assistantName="Emma"
|
|
196
|
+
className="my-chat"
|
|
197
|
+
style={{ bottom: 80 }}
|
|
198
|
+
/>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Prop | Type | Default | Description |
|
|
202
|
+
|-----------------|-----------------------|-----------|-------------------------------------|
|
|
203
|
+
| `open` | `boolean` | -- | Controls visibility. |
|
|
204
|
+
| `onClose` | `() => void` | -- | Called when the user clicks close. |
|
|
205
|
+
| `assistantName` | `string` | `"Emma"` | Name shown in the header. |
|
|
206
|
+
| `className` | `string` | -- | CSS class for the container. |
|
|
207
|
+
| `style` | `React.CSSProperties` | -- | Inline styles for the container. |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### `VocallFab`
|
|
212
|
+
|
|
213
|
+
A floating action button that reflects the current connection status through color changes and displays a spinner during `thinking` and `executing` states.
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import { VocallFab } from '@vocall/react-sdk';
|
|
217
|
+
|
|
218
|
+
<VocallFab onClick={() => setChatOpen((o) => !o)} />
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
| Prop | Type | Description |
|
|
222
|
+
|-------------|-----------------------|----------------------------------|
|
|
223
|
+
| `onClick` | `() => void` | Called when the FAB is clicked. |
|
|
224
|
+
| `className` | `string` | CSS class for the button. |
|
|
225
|
+
| `style` | `React.CSSProperties` | Inline styles for the button. |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### `VocallStatusPill`
|
|
230
|
+
|
|
231
|
+
A small inline pill that appears only when the assistant is actively working (thinking, executing, speaking, listening, or recording). Hides automatically when idle or disconnected.
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
import { VocallStatusPill } from '@vocall/react-sdk';
|
|
235
|
+
|
|
236
|
+
<VocallStatusPill className="my-status" />
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
| Prop | Type | Description |
|
|
240
|
+
|-------------|-----------------------|--------------------------------|
|
|
241
|
+
| `className` | `string` | CSS class for the pill. |
|
|
242
|
+
| `style` | `React.CSSProperties` | Inline styles for the pill. |
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## VocallClient API
|
|
247
|
+
|
|
248
|
+
The `VocallClient` class manages the WebSocket connection and the field/action registries. You can access it directly via `useVocallClient()` or through the `client` property returned by `useVocall()`.
|
|
249
|
+
|
|
250
|
+
### Constructor
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const client = new VocallClient(serverUrl, { token?, visitorId? });
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Parameter | Type | Description |
|
|
257
|
+
|-------------|----------|------------------------------------------------------------|
|
|
258
|
+
| `serverUrl` | `string` | WebSocket URL of the Vocall engine (e.g. `wss://host/connect`). |
|
|
259
|
+
| `token` | `string` | Optional authentication token. |
|
|
260
|
+
| `visitorId` | `string` | Optional visitor ID. Auto-generated and persisted in `localStorage` if omitted. |
|
|
261
|
+
|
|
262
|
+
### Core Methods
|
|
263
|
+
|
|
264
|
+
| Method | Description |
|
|
265
|
+
|------------------------------------------------------|------------------------------------------------------|
|
|
266
|
+
| `connect(manifest: ManifestMessage)` | Opens the WebSocket and sends the manifest. |
|
|
267
|
+
| `disconnect()` | Closes the connection intentionally (no reconnect). |
|
|
268
|
+
| `sendText(text: string)` | Sends a user chat message to the engine. |
|
|
269
|
+
| `sendConfirm(seq: number, confirmed: boolean)` | Responds to an `ask_confirm` action. |
|
|
270
|
+
| `sendResult(seq: number, results, state?)` | Sends command execution results back to the engine. |
|
|
271
|
+
| `sendState(state: StateMessage)` | Sends current UI state to the engine. |
|
|
272
|
+
| `clearMessages()` | Clears the local chat history. |
|
|
273
|
+
| `destroy()` | Disconnects and removes all listeners. |
|
|
274
|
+
|
|
275
|
+
### State Getters
|
|
276
|
+
|
|
277
|
+
| Property | Type | Description |
|
|
278
|
+
|-------------|---------------------------|----------------------------------------------|
|
|
279
|
+
| `status` | `VocallStatus` | Current engine status. |
|
|
280
|
+
| `connected` | `boolean` | Whether the WebSocket is open. |
|
|
281
|
+
| `messages` | `readonly ChatMessage[]` | Conversation history. |
|
|
282
|
+
| `sessionId` | `string \| null` | Server-assigned session ID. |
|
|
283
|
+
| `visitorId` | `string` | Persistent visitor identifier. |
|
|
284
|
+
|
|
285
|
+
### Callbacks
|
|
286
|
+
|
|
287
|
+
Set these on the client instance to handle navigation, modals, toasts, and confirmation dialogs in your application:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
client.onNavigate = (screenId) => router.push(`/${screenId}`);
|
|
291
|
+
client.onToast = (message, level, duration) => showToast(message, level);
|
|
292
|
+
client.onConfirm = (seq, message) => showConfirmDialog(seq, message);
|
|
293
|
+
client.onOpenModal = (modalId, query) => openModal(modalId);
|
|
294
|
+
client.onCloseModal = () => closeModal();
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Field and Action Registration
|
|
298
|
+
|
|
299
|
+
These methods are called automatically by `useVocallField` and `useVocallAction`, but are available for manual use:
|
|
300
|
+
|
|
301
|
+
| Method | Description |
|
|
302
|
+
|--------------------------------------------------------|--------------------------------------------|
|
|
303
|
+
| `registerField(screenId, fieldId, entry)` | Registers a field element. |
|
|
304
|
+
| `unregisterField(screenId, fieldId)` | Removes a field registration. |
|
|
305
|
+
| `registerAction(screenId, actionId, callback)` | Registers an action callback. |
|
|
306
|
+
| `unregisterAction(screenId, actionId)` | Removes an action registration. |
|
|
307
|
+
| `unregisterScreen(screenId)` | Removes all fields and actions for a screen. |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Manifest Structure
|
|
312
|
+
|
|
313
|
+
The manifest describes your application's screens, fields, and actions to the Vocall engine. It is sent automatically upon connection.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import { ManifestMessage, FieldType } from '@vocall/react-sdk';
|
|
317
|
+
|
|
318
|
+
const manifest: ManifestMessage = {
|
|
319
|
+
type: 'manifest',
|
|
320
|
+
app: 'my-erp',
|
|
321
|
+
version: '1.0.0',
|
|
322
|
+
currentScreen: 'dashboard',
|
|
323
|
+
user: {
|
|
324
|
+
name: 'Jane Doe',
|
|
325
|
+
email: 'jane@example.com',
|
|
326
|
+
org: 'Acme Corp',
|
|
327
|
+
role: 'admin',
|
|
328
|
+
},
|
|
329
|
+
persona: {
|
|
330
|
+
name: 'Emma',
|
|
331
|
+
role: 'ERP Assistant',
|
|
332
|
+
instructions: 'Help the user manage invoices and clients.',
|
|
333
|
+
},
|
|
334
|
+
context: {
|
|
335
|
+
locale: 'en-US',
|
|
336
|
+
tenant: 'acme',
|
|
337
|
+
},
|
|
338
|
+
screens: {
|
|
339
|
+
dashboard: {
|
|
340
|
+
id: 'dashboard',
|
|
341
|
+
label: 'Dashboard',
|
|
342
|
+
route: '/dashboard',
|
|
343
|
+
fields: [
|
|
344
|
+
{ id: 'search', type: FieldType.Text, label: 'Search' },
|
|
345
|
+
],
|
|
346
|
+
actions: [
|
|
347
|
+
{ id: 'refresh', label: 'Refresh Data' },
|
|
348
|
+
{ id: 'export', label: 'Export CSV', requiresConfirmation: true },
|
|
349
|
+
],
|
|
350
|
+
modals: [
|
|
351
|
+
{ id: 'client_picker', label: 'Select Client', searchable: true },
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
invoice: {
|
|
355
|
+
id: 'invoice',
|
|
356
|
+
label: 'New Invoice',
|
|
357
|
+
route: '/invoices/new',
|
|
358
|
+
fields: [
|
|
359
|
+
{ id: 'recipient', type: FieldType.Autocomplete, label: 'Recipient', required: true },
|
|
360
|
+
{ id: 'amount', type: FieldType.Currency, label: 'Amount', min: 0 },
|
|
361
|
+
{ id: 'due_date', type: FieldType.Date, label: 'Due Date', required: true },
|
|
362
|
+
{ id: 'notes', type: FieldType.Textarea, label: 'Notes', maxLength: 500 },
|
|
363
|
+
{
|
|
364
|
+
id: 'status',
|
|
365
|
+
type: FieldType.Select,
|
|
366
|
+
label: 'Status',
|
|
367
|
+
options: [
|
|
368
|
+
{ value: 'draft', label: 'Draft' },
|
|
369
|
+
{ value: 'sent', label: 'Sent' },
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
actions: [
|
|
374
|
+
{ id: 'save_draft', label: 'Save Draft' },
|
|
375
|
+
{ id: 'send', label: 'Send Invoice', destructive: true, requiresConfirmation: true },
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Field Types
|
|
385
|
+
|
|
386
|
+
The `FieldType` enum defines the supported field types in the manifest:
|
|
387
|
+
|
|
388
|
+
| Value | Description |
|
|
389
|
+
|----------------|-------------------------------------------------|
|
|
390
|
+
| `text` | Plain text input. |
|
|
391
|
+
| `number` | Numeric input. |
|
|
392
|
+
| `currency` | Currency/monetary value input. |
|
|
393
|
+
| `date` | Date picker. |
|
|
394
|
+
| `datetime` | Date and time picker. |
|
|
395
|
+
| `email` | Email address input. |
|
|
396
|
+
| `phone` | Phone number input. |
|
|
397
|
+
| `masked` | Input with a custom mask pattern. |
|
|
398
|
+
| `select` | Dropdown select (provide `options`). |
|
|
399
|
+
| `autocomplete` | Searchable select / autocomplete. |
|
|
400
|
+
| `checkbox` | Boolean checkbox. |
|
|
401
|
+
| `radio` | Radio button group. |
|
|
402
|
+
| `textarea` | Multi-line text area. |
|
|
403
|
+
| `file` | File upload. |
|
|
404
|
+
| `hidden` | Hidden field (not visible to the user). |
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## UI Actions
|
|
409
|
+
|
|
410
|
+
The Vocall engine can send 14 UI actions to the client. These are executed automatically by the SDK when commands arrive over the WebSocket.
|
|
411
|
+
|
|
412
|
+
| Action | Target | Description |
|
|
413
|
+
|----------------|-----------|------------------------------------------------------|
|
|
414
|
+
| `navigate` | screen | Navigate to a different screen. |
|
|
415
|
+
| `fill` | field | Set a field's value (with optional typewriter animation). |
|
|
416
|
+
| `clear` | field | Clear a field's value. |
|
|
417
|
+
| `select` | field | Set the selected value of a select/radio field. |
|
|
418
|
+
| `click` | action | Invoke a registered action callback. |
|
|
419
|
+
| `highlight` | field | Scroll to and visually highlight a field. |
|
|
420
|
+
| `focus` | field | Move focus to a field. |
|
|
421
|
+
| `scroll_to` | field | Scroll a field into view. |
|
|
422
|
+
| `show_toast` | -- | Display a toast notification. |
|
|
423
|
+
| `ask_confirm` | -- | Prompt the user for confirmation. |
|
|
424
|
+
| `open_modal` | modal | Open a modal dialog. |
|
|
425
|
+
| `close_modal` | -- | Close the currently open modal. |
|
|
426
|
+
| `enable` | field | Enable a disabled input. |
|
|
427
|
+
| `disable` | field | Disable an input. |
|
|
428
|
+
|
|
429
|
+
Actions are classified as **sequential** (`navigate`, `click`, `open_modal`, `close_modal`, `ask_confirm`, `show_toast`) or **parallel** (all others). Sequential actions execute one at a time in order; parallel actions execute concurrently for performance. All actions include automatic retry logic with up to 3 attempts.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Demo
|
|
434
|
+
|
|
435
|
+
A working demo application is available in the `demo/` directory. It demonstrates the full integration including provider setup, field binding, action registration, and the chat overlay components.
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Testing
|
|
440
|
+
|
|
441
|
+
The SDK includes a comprehensive test suite with ~156 tests covering protocol types, WebSocket client, React hooks, context provider, and components.
|
|
442
|
+
|
|
443
|
+
### Running Tests
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
npm test # Run all tests
|
|
447
|
+
npm test -- --coverage # Run with coverage report
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Test Structure
|
|
451
|
+
|
|
452
|
+
| File | Tests | What it covers |
|
|
453
|
+
|---|---|---|
|
|
454
|
+
| `src/protocol/__tests__/types.test.ts` | 30 | Protocol type enums, message interfaces, field types |
|
|
455
|
+
| `src/client/__tests__/vocall-client.test.ts` | 94 | WebSocket connection, reconnection, command execution, streaming |
|
|
456
|
+
| `src/hooks/__tests__/use-vocall.test.tsx` | 10 | useVocall hook, state reactivity |
|
|
457
|
+
| `src/hooks/__tests__/use-vocall-field.test.tsx` | 7 | useVocallField hook, DOM element binding |
|
|
458
|
+
| `src/hooks/__tests__/use-vocall-action.test.tsx` | 4 | useVocallAction hook, callback registration |
|
|
459
|
+
| `src/context/__tests__/vocall-provider.test.tsx` | 11 | VocallProvider context, client lifecycle |
|
|
460
|
+
|
|
461
|
+
### Test Configuration
|
|
462
|
+
|
|
463
|
+
- **Framework:** Vitest with React Testing Library
|
|
464
|
+
- **Environment:** jsdom
|
|
465
|
+
- **Config:** [vitest.config.ts](vitest.config.ts) | [vitest.setup.ts](vitest.setup.ts)
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Development
|
|
470
|
+
|
|
471
|
+
### Building the SDK
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
npm install
|
|
475
|
+
npm run build
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Running the Demo
|
|
479
|
+
|
|
480
|
+
The demo application is in the `demo/` directory:
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
cd demo
|
|
484
|
+
npm install
|
|
485
|
+
npm run dev # http://localhost:3000
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
The demo connects to a Vocall server at `ws://localhost:12900/connect`. See the [workspace README](https://github.com/primoia/primoia-vocall-workspace#quick-start) for local server setup.
|
|
489
|
+
|
|
490
|
+
### Docker
|
|
491
|
+
|
|
492
|
+
When running from the workspace, the demo is available as a Docker container:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
# From the workspace root
|
|
496
|
+
make serve-all # Starts engine + all demos
|
|
497
|
+
# Next.js demo at http://localhost:21003
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Related
|
|
503
|
+
|
|
504
|
+
This SDK is part of the [Primoia Vocall Workspace](https://github.com/primoia/primoia-vocall-workspace).
|
|
505
|
+
|
|
506
|
+
| Resource | Link |
|
|
507
|
+
|---|---|
|
|
508
|
+
| Workspace (setup, Docker) | [primoia-vocall-workspace](https://github.com/primoia/primoia-vocall-workspace#readme) |
|
|
509
|
+
| Angular SDK | [vocall-sdk-angular](https://github.com/primoia/vocall-sdk-angular) |
|
|
510
|
+
| Vue SDK | [vocall-sdk-vue](https://github.com/primoia/vocall-sdk-vue) |
|
|
511
|
+
| Kotlin SDK | [vocall-sdk-kotlin](https://github.com/primoia/vocall-sdk-kotlin) |
|
|
512
|
+
| Swift SDK | [vocall-sdk-swift](https://github.com/primoia/vocall-sdk-swift) |
|
|
513
|
+
| Flutter SDK | [jarvis-sdk-flutter](https://github.com/primoia/jarvis-sdk-flutter) |
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## License
|
|
518
|
+
|
|
519
|
+
Proprietary. All rights reserved.
|