@primoia/vocall-vue 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 +569 -0
- package/dist/client/vocall-client.d.ts +146 -0
- package/dist/components/VocallChat.vue.d.ts +24 -0
- package/dist/components/VocallFab.vue.d.ts +11 -0
- package/dist/components/VocallStatus.vue.d.ts +7 -0
- package/dist/composables/use-vocall-action.d.ts +25 -0
- package/dist/composables/use-vocall-field.d.ts +31 -0
- package/dist/composables/use-vocall-voice.d.ts +32 -0
- package/dist/composables/use-vocall.d.ts +53 -0
- package/dist/index.d.ts +19 -0
- package/dist/plugin/vocall-plugin.d.ts +29 -0
- package/dist/protocol/types.d.ts +182 -0
- package/dist/style.css +1 -0
- package/dist/vocall-vue-sdk.js +1100 -0
- package/dist/vocall-vue-sdk.umd.cjs +1 -0
- package/dist/voice/frame-splitter.d.ts +15 -0
- package/dist/voice/voice-service.d.ts +34 -0
- package/dist/voice/web-voice-service.d.ts +41 -0
- package/package.json +63 -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,569 @@
|
|
|
1
|
+
# Vocall SDK for Vue
|
|
2
|
+
|
|
3
|
+
Vue 3 SDK for the Vocall platform -- connect your Vue application to a Vocall engine over WebSocket and let the AI assistant read, fill, and navigate your UI in real time.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Reactive composables built on Vue 3 Composition API (`ref`, `inject`, `watch`)
|
|
10
|
+
- Plugin-based setup with a shared `VocallClient` instance across your application
|
|
11
|
+
- Two-way field binding: register any `<input>`, `<select>`, or `<textarea>` so the engine can fill, clear, focus, and highlight it
|
|
12
|
+
- Action registration: expose buttons and callbacks the engine can trigger remotely
|
|
13
|
+
- Pre-built UI components (`VocallChat`, `VocallFab`, `VocallStatus`) with scoped styles
|
|
14
|
+
- Streaming chat tokens with automatic message assembly
|
|
15
|
+
- Automatic WebSocket reconnection with exponential back-off (up to 10 attempts)
|
|
16
|
+
- Full TypeScript support with exported types for every protocol message
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @vocall/vue-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Peer dependency: **Vue >= 3.4.0**
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### 1. Register the plugin
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// main.ts
|
|
36
|
+
import { createApp } from 'vue';
|
|
37
|
+
import { VocallPlugin } from '@vocall/vue-sdk';
|
|
38
|
+
import App from './App.vue';
|
|
39
|
+
|
|
40
|
+
const app = createApp(App);
|
|
41
|
+
|
|
42
|
+
app.use(VocallPlugin, {
|
|
43
|
+
url: 'ws://localhost:12900/connect',
|
|
44
|
+
token: 'my-api-token', // optional
|
|
45
|
+
visitorId: 'visitor-abc-123', // optional, auto-generated if omitted
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
app.mount('#app');
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Connect and send messages
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
import { onMounted } from 'vue';
|
|
56
|
+
import { useVocall, useVocallField, type ManifestMessage } from '@vocall/vue-sdk';
|
|
57
|
+
|
|
58
|
+
const {
|
|
59
|
+
status, messages, connected,
|
|
60
|
+
connect, disconnect, sendText, client,
|
|
61
|
+
} = useVocall();
|
|
62
|
+
|
|
63
|
+
// Register a field so the engine can fill it
|
|
64
|
+
const { fieldRef, value: nameValue } = useVocallField({
|
|
65
|
+
fieldId: 'customer_name',
|
|
66
|
+
client,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Build the manifest and connect
|
|
70
|
+
onMounted(() => {
|
|
71
|
+
const manifest: ManifestMessage = {
|
|
72
|
+
type: 'manifest',
|
|
73
|
+
app: 'my-app',
|
|
74
|
+
screens: {
|
|
75
|
+
home: {
|
|
76
|
+
id: 'home',
|
|
77
|
+
label: 'Home',
|
|
78
|
+
fields: [
|
|
79
|
+
{ id: 'customer_name', type: 'text', label: 'Customer Name', required: true },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
currentScreen: 'home',
|
|
84
|
+
};
|
|
85
|
+
connect(manifest);
|
|
86
|
+
});
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<p>Status: {{ status }}</p>
|
|
91
|
+
<input ref="fieldRef" v-model="nameValue" placeholder="Customer Name" />
|
|
92
|
+
<button @click="sendText('Fill the customer name with John Doe')">
|
|
93
|
+
Ask Vocall
|
|
94
|
+
</button>
|
|
95
|
+
</template>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Composables API
|
|
101
|
+
|
|
102
|
+
### `useVocall(options?)`
|
|
103
|
+
|
|
104
|
+
Main composable for connecting to the Vocall server. If the `VocallPlugin` was installed, the shared client is injected automatically; otherwise a new client is created from the provided options.
|
|
105
|
+
|
|
106
|
+
**Options** (`UseVocallOptions`):
|
|
107
|
+
|
|
108
|
+
| Property | Type | Default | Description |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `serverUrl` | `string` | `ws://localhost:12900/connect` | WebSocket server URL |
|
|
111
|
+
| `token` | `string` | -- | Optional auth token |
|
|
112
|
+
| `visitorId` | `string` | auto-generated | Persistent visitor identifier |
|
|
113
|
+
| `autoDispose` | `boolean` | `true` | Dispose the client when the component unmounts |
|
|
114
|
+
|
|
115
|
+
**Returns** (`UseVocallReturn`):
|
|
116
|
+
|
|
117
|
+
| Property | Type | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `status` | `Ref<VocallStatus>` | Current connection/processing status (readonly) |
|
|
120
|
+
| `messages` | `Ref<ChatMessage[]>` | Reactive chat message list |
|
|
121
|
+
| `connected` | `Ref<boolean>` | Whether the WebSocket is connected (readonly) |
|
|
122
|
+
| `sessionId` | `Ref<string \| null>` | Session ID assigned by the server (readonly) |
|
|
123
|
+
| `pendingConfirmSeq` | `Ref<number>` | Sequence number of a pending confirmation (-1 if none) |
|
|
124
|
+
| `pendingConfirmMessage` | `Ref<string \| null>` | Text of a pending confirmation dialog |
|
|
125
|
+
| `sendText(text)` | `(text: string) => void` | Send a chat message to the engine |
|
|
126
|
+
| `sendConfirm(seq, confirmed)` | `(seq: number, confirmed: boolean) => void` | Respond to a confirmation request |
|
|
127
|
+
| `connect(manifest)` | `(manifest: ManifestMessage) => void` | Open the WebSocket and send the manifest |
|
|
128
|
+
| `disconnect()` | `() => void` | Close the connection |
|
|
129
|
+
| `sendState(screen)` | `(screen: string) => void` | Send current field state to the server |
|
|
130
|
+
| `clearMessages()` | `() => void` | Clear the local chat history |
|
|
131
|
+
| `client` | `VocallClient` | Underlying client instance for advanced use |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### `useVocallField(options)`
|
|
136
|
+
|
|
137
|
+
Registers a form field with the Vocall client so the engine can fill, clear, focus, and highlight it.
|
|
138
|
+
|
|
139
|
+
**Options** (`UseVocallFieldOptions`):
|
|
140
|
+
|
|
141
|
+
| Property | Type | Description |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `fieldId` | `string` | Unique identifier matching a field in the manifest |
|
|
144
|
+
| `client` | `VocallClient` | Client instance from `useVocall().client` |
|
|
145
|
+
| `initialValue` | `string` | Optional initial value |
|
|
146
|
+
|
|
147
|
+
**Returns** (`UseVocallFieldReturn`):
|
|
148
|
+
|
|
149
|
+
| Property | Type | Description |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `fieldRef` | `Ref<HTMLInputElement \| HTMLSelectElement \| HTMLTextAreaElement \| null>` | Template ref to bind to the element |
|
|
152
|
+
| `value` | `Ref<string>` | Reactive model value (use with `v-model`) |
|
|
153
|
+
|
|
154
|
+
**Example:**
|
|
155
|
+
|
|
156
|
+
```vue
|
|
157
|
+
<script setup lang="ts">
|
|
158
|
+
import { useVocall, useVocallField } from '@vocall/vue-sdk';
|
|
159
|
+
|
|
160
|
+
const { client } = useVocall();
|
|
161
|
+
|
|
162
|
+
const { fieldRef: emailRef, value: emailValue } = useVocallField({
|
|
163
|
+
fieldId: 'email',
|
|
164
|
+
client,
|
|
165
|
+
});
|
|
166
|
+
</script>
|
|
167
|
+
|
|
168
|
+
<template>
|
|
169
|
+
<input ref="emailRef" v-model="emailValue" type="email" />
|
|
170
|
+
</template>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### `useVocallAction(options)`
|
|
176
|
+
|
|
177
|
+
Registers an action handler with the Vocall client so the engine can trigger it via the `click` command.
|
|
178
|
+
|
|
179
|
+
**Options** (`UseVocallActionOptions`):
|
|
180
|
+
|
|
181
|
+
| Property | Type | Description |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `actionId` | `string` | Unique identifier matching an action in the manifest |
|
|
184
|
+
| `client` | `VocallClient` | Client instance from `useVocall().client` |
|
|
185
|
+
| `handler` | `() => void \| Promise<void>` | Callback invoked when the engine triggers this action |
|
|
186
|
+
|
|
187
|
+
**Example:**
|
|
188
|
+
|
|
189
|
+
```vue
|
|
190
|
+
<script setup lang="ts">
|
|
191
|
+
import { useVocall, useVocallAction } from '@vocall/vue-sdk';
|
|
192
|
+
|
|
193
|
+
const { client } = useVocall();
|
|
194
|
+
|
|
195
|
+
useVocallAction({
|
|
196
|
+
actionId: 'submit_form',
|
|
197
|
+
client,
|
|
198
|
+
handler: async () => {
|
|
199
|
+
await saveData();
|
|
200
|
+
console.log('Form submitted by Vocall');
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
</script>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Plugin
|
|
209
|
+
|
|
210
|
+
### `VocallPlugin`
|
|
211
|
+
|
|
212
|
+
Install Vocall as a Vue plugin to create a single shared `VocallClient` instance that is provided to all components via `inject`.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { createApp } from 'vue';
|
|
216
|
+
import { VocallPlugin } from '@vocall/vue-sdk';
|
|
217
|
+
|
|
218
|
+
const app = createApp(App);
|
|
219
|
+
|
|
220
|
+
app.use(VocallPlugin, {
|
|
221
|
+
url: 'ws://localhost:12900/connect',
|
|
222
|
+
token: 'my-api-token',
|
|
223
|
+
visitorId: 'visitor-abc-123',
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
app.mount('#app');
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Options** (`VocallPluginOptions`):
|
|
230
|
+
|
|
231
|
+
| Property | Type | Required | Description |
|
|
232
|
+
|---|---|---|---|
|
|
233
|
+
| `url` | `string` | No | WebSocket server URL. Defaults to `ws://localhost:12900/connect` |
|
|
234
|
+
| `token` | `string` | No | Optional authentication token |
|
|
235
|
+
| `visitorId` | `string` | No | Visitor identifier. Auto-generated and persisted in `localStorage` if omitted |
|
|
236
|
+
|
|
237
|
+
When the plugin is installed, the client is also available on `this.$vocall` for Options API components.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Components
|
|
242
|
+
|
|
243
|
+
### `VocallChat`
|
|
244
|
+
|
|
245
|
+
A full chat panel with message list, text input, and header showing connection status.
|
|
246
|
+
|
|
247
|
+
**Props:**
|
|
248
|
+
|
|
249
|
+
| Prop | Type | Description |
|
|
250
|
+
|---|---|---|
|
|
251
|
+
| `messages` | `ChatMessage[]` | Array of chat messages to display |
|
|
252
|
+
| `status` | `VocallStatus` | Current engine status |
|
|
253
|
+
| `connected` | `boolean` | Whether the client is connected |
|
|
254
|
+
| `sessionId` | `string \| null` | Optional session identifier |
|
|
255
|
+
|
|
256
|
+
**Events:**
|
|
257
|
+
|
|
258
|
+
| Event | Payload | Description |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| `send` | `text: string` | Emitted when the user submits a message |
|
|
261
|
+
| `clear` | -- | Emitted when the user clicks the clear button |
|
|
262
|
+
| `close` | -- | Emitted when the user clicks the close button |
|
|
263
|
+
|
|
264
|
+
```vue
|
|
265
|
+
<template>
|
|
266
|
+
<VocallChat
|
|
267
|
+
:messages="messages"
|
|
268
|
+
:status="status"
|
|
269
|
+
:connected="connected"
|
|
270
|
+
@send="sendText"
|
|
271
|
+
@clear="clearMessages"
|
|
272
|
+
@close="chatOpen = false"
|
|
273
|
+
/>
|
|
274
|
+
</template>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### `VocallFab`
|
|
278
|
+
|
|
279
|
+
A floating action button (fixed bottom-right) that changes color based on the engine status and shows a spinner during `thinking` or `executing` states.
|
|
280
|
+
|
|
281
|
+
**Props:**
|
|
282
|
+
|
|
283
|
+
| Prop | Type | Description |
|
|
284
|
+
|---|---|---|
|
|
285
|
+
| `status` | `VocallStatus` | Current engine status |
|
|
286
|
+
| `connected` | `boolean` | Whether the client is connected |
|
|
287
|
+
|
|
288
|
+
**Events:**
|
|
289
|
+
|
|
290
|
+
| Event | Description |
|
|
291
|
+
|---|---|
|
|
292
|
+
| `click` | Emitted when the FAB is clicked |
|
|
293
|
+
|
|
294
|
+
```vue
|
|
295
|
+
<template>
|
|
296
|
+
<VocallFab :status="status" :connected="connected" @click="toggleChat" />
|
|
297
|
+
</template>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### `VocallStatus`
|
|
301
|
+
|
|
302
|
+
A small status pill that becomes visible when the engine is actively processing (thinking, executing, speaking, listening, or recording). Hidden during idle and disconnected states.
|
|
303
|
+
|
|
304
|
+
**Props:**
|
|
305
|
+
|
|
306
|
+
| Prop | Type | Description |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| `status` | `VocallStatus` | Current engine status |
|
|
309
|
+
| `connected` | `boolean` | Whether the client is connected |
|
|
310
|
+
|
|
311
|
+
```vue
|
|
312
|
+
<template>
|
|
313
|
+
<VocallStatus :status="status" :connected="connected" />
|
|
314
|
+
</template>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## VocallClient API
|
|
320
|
+
|
|
321
|
+
The `VocallClient` class manages the WebSocket connection, field/action registry, and command execution. It is typically accessed via `useVocall().client`.
|
|
322
|
+
|
|
323
|
+
### Properties
|
|
324
|
+
|
|
325
|
+
| Property | Type | Description |
|
|
326
|
+
|---|---|---|
|
|
327
|
+
| `status` | `VocallStatus` | Current status |
|
|
328
|
+
| `messages` | `ChatMessage[]` | Chat message history |
|
|
329
|
+
| `sessionId` | `string \| null` | Server-assigned session ID |
|
|
330
|
+
| `connected` | `boolean` | Connection state |
|
|
331
|
+
| `registry` | `VocallFieldRegistry` | Field and action registry |
|
|
332
|
+
| `events` | `EventEmitter` | Internal event bus |
|
|
333
|
+
| `serverUrl` | `string` | WebSocket server URL (read/write) |
|
|
334
|
+
| `token` | `string \| undefined` | Auth token (read/write) |
|
|
335
|
+
| `visitorId` | `string` | Visitor identifier (read-only) |
|
|
336
|
+
|
|
337
|
+
### Methods
|
|
338
|
+
|
|
339
|
+
| Method | Description |
|
|
340
|
+
|---|---|
|
|
341
|
+
| `connect(manifest)` | Open the WebSocket and send the manifest |
|
|
342
|
+
| `disconnect()` | Close the connection intentionally |
|
|
343
|
+
| `sendText(text)` | Send a chat message |
|
|
344
|
+
| `sendConfirm(seq, confirmed)` | Respond to a confirmation dialog |
|
|
345
|
+
| `sendResult(seq, results, currentScreen?)` | Send command execution results |
|
|
346
|
+
| `sendState(screen)` | Send current field state snapshot |
|
|
347
|
+
| `dispose()` | Disconnect, remove listeners, and clear registries |
|
|
348
|
+
|
|
349
|
+
### Events
|
|
350
|
+
|
|
351
|
+
Subscribe to events via `client.events.on(event, handler)`:
|
|
352
|
+
|
|
353
|
+
| Event | Arguments | Description |
|
|
354
|
+
|---|---|---|
|
|
355
|
+
| `change` | -- | Fired whenever any reactive state changes |
|
|
356
|
+
| `confirm` | `seq: number, message: string` | A confirmation dialog was requested |
|
|
357
|
+
| `toast` | `message: string, level: string, duration: number` | A toast notification was requested |
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Manifest Structure
|
|
362
|
+
|
|
363
|
+
The manifest describes your application's screens, fields, and actions. It is sent to the engine on connection.
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import type { ManifestMessage } from '@vocall/vue-sdk';
|
|
367
|
+
|
|
368
|
+
const manifest: ManifestMessage = {
|
|
369
|
+
type: 'manifest',
|
|
370
|
+
app: 'invoice-app',
|
|
371
|
+
version: '1.0.0',
|
|
372
|
+
currentScreen: 'dashboard',
|
|
373
|
+
user: {
|
|
374
|
+
name: 'Jane Doe',
|
|
375
|
+
email: 'jane@example.com',
|
|
376
|
+
org: 'Acme Corp',
|
|
377
|
+
role: 'admin',
|
|
378
|
+
},
|
|
379
|
+
persona: {
|
|
380
|
+
name: 'Emma',
|
|
381
|
+
role: 'Invoice Assistant',
|
|
382
|
+
instructions: 'Help the user issue invoices and manage taxpayers.',
|
|
383
|
+
},
|
|
384
|
+
context: {
|
|
385
|
+
locale: 'en-US',
|
|
386
|
+
timezone: 'America/New_York',
|
|
387
|
+
},
|
|
388
|
+
screens: {
|
|
389
|
+
dashboard: {
|
|
390
|
+
id: 'dashboard',
|
|
391
|
+
label: 'Dashboard',
|
|
392
|
+
route: '/dashboard',
|
|
393
|
+
fields: [
|
|
394
|
+
{ id: 'search', type: 'text', label: 'Search', placeholder: 'Search...' },
|
|
395
|
+
],
|
|
396
|
+
actions: [
|
|
397
|
+
{ id: 'new_invoice', label: 'New Invoice' },
|
|
398
|
+
],
|
|
399
|
+
},
|
|
400
|
+
invoice_form: {
|
|
401
|
+
id: 'invoice_form',
|
|
402
|
+
label: 'Issue Invoice',
|
|
403
|
+
route: '/invoices/new',
|
|
404
|
+
fields: [
|
|
405
|
+
{ id: 'customer_name', type: 'text', label: 'Customer', required: true },
|
|
406
|
+
{ id: 'amount', type: 'currency', label: 'Amount', required: true },
|
|
407
|
+
{ id: 'due_date', type: 'date', label: 'Due Date' },
|
|
408
|
+
{ id: 'notes', type: 'textarea', label: 'Notes', maxLength: 500 },
|
|
409
|
+
{
|
|
410
|
+
id: 'status',
|
|
411
|
+
type: 'select',
|
|
412
|
+
label: 'Status',
|
|
413
|
+
options: [
|
|
414
|
+
{ value: 'draft', label: 'Draft' },
|
|
415
|
+
{ value: 'sent', label: 'Sent' },
|
|
416
|
+
],
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
actions: [
|
|
420
|
+
{ id: 'save_invoice', label: 'Save', requiresConfirmation: true },
|
|
421
|
+
{ id: 'cancel', label: 'Cancel', destructive: true },
|
|
422
|
+
],
|
|
423
|
+
modals: [
|
|
424
|
+
{ id: 'customer_search', label: 'Search Customer', searchable: true },
|
|
425
|
+
],
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Field Types
|
|
434
|
+
|
|
435
|
+
The `FieldType` enum defines all supported field types:
|
|
436
|
+
|
|
437
|
+
| Type | Value | Description |
|
|
438
|
+
|---|---|---|
|
|
439
|
+
| `Text` | `text` | Plain text input |
|
|
440
|
+
| `Number` | `number` | Numeric input |
|
|
441
|
+
| `Currency` | `currency` | Monetary value input |
|
|
442
|
+
| `Date` | `date` | Date picker |
|
|
443
|
+
| `Datetime` | `datetime` | Date and time picker |
|
|
444
|
+
| `Email` | `email` | Email address input |
|
|
445
|
+
| `Phone` | `phone` | Phone number input |
|
|
446
|
+
| `Masked` | `masked` | Input with a custom mask pattern |
|
|
447
|
+
| `Select` | `select` | Dropdown select |
|
|
448
|
+
| `Autocomplete` | `autocomplete` | Autocomplete / typeahead |
|
|
449
|
+
| `Checkbox` | `checkbox` | Boolean checkbox |
|
|
450
|
+
| `Radio` | `radio` | Radio button group |
|
|
451
|
+
| `Textarea` | `textarea` | Multi-line text area |
|
|
452
|
+
| `File` | `file` | File upload |
|
|
453
|
+
| `Hidden` | `hidden` | Hidden field (not visible to the user) |
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## UI Actions
|
|
458
|
+
|
|
459
|
+
The engine can send commands containing one or more of the following 14 UI actions:
|
|
460
|
+
|
|
461
|
+
| Action | Target | Description |
|
|
462
|
+
|---|---|---|
|
|
463
|
+
| `navigate` | `screen` | Navigate to a different screen |
|
|
464
|
+
| `fill` | `field` | Fill a field with a value (supports typewriter animation) |
|
|
465
|
+
| `clear` | `field` | Clear a field's value |
|
|
466
|
+
| `select` | `field` | Set the value of a select/dropdown field |
|
|
467
|
+
| `click` | `action` | Trigger a registered action handler |
|
|
468
|
+
| `highlight` | `field` | Temporarily highlight a field element |
|
|
469
|
+
| `focus` | `field` | Focus a field element |
|
|
470
|
+
| `scroll_to` | `field` | Scroll the viewport to a field |
|
|
471
|
+
| `show_toast` | -- | Display a toast notification |
|
|
472
|
+
| `ask_confirm` | -- | Show a confirmation dialog and wait for user response |
|
|
473
|
+
| `open_modal` | `modal` | Open a modal by ID with an optional search query |
|
|
474
|
+
| `close_modal` | -- | Close the currently open modal |
|
|
475
|
+
| `enable` | `field` | Enable a disabled field |
|
|
476
|
+
| `disable` | `field` | Disable a field |
|
|
477
|
+
|
|
478
|
+
Sequential actions (`navigate`, `click`, `open_modal`, `close_modal`, `ask_confirm`, `show_toast`) are executed one at a time. All other actions run in parallel for optimal performance. Failed actions are retried up to 3 times with a 300 ms delay.
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Demo
|
|
483
|
+
|
|
484
|
+
A demo application is available in the `demo/` directory. It demonstrates plugin setup, field registration, action handling, and the chat overlay using all three provided components.
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## Testing
|
|
489
|
+
|
|
490
|
+
The SDK includes a comprehensive test suite with ~184 tests covering protocol types, WebSocket client, Vue composables, plugin integration, and voice utilities.
|
|
491
|
+
|
|
492
|
+
### Running Tests
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
npm test # Run all tests
|
|
496
|
+
npm test -- --coverage # Run with coverage report
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Test Structure
|
|
500
|
+
|
|
501
|
+
| File | Tests | What it covers |
|
|
502
|
+
|---|---|---|
|
|
503
|
+
| `src/protocol/__tests__/types.test.ts` | 24 | Protocol type enums, message interfaces, field types |
|
|
504
|
+
| `src/client/__tests__/vocall-client.test.ts` | 94 | WebSocket connection, reconnection, command execution, streaming |
|
|
505
|
+
| `src/composables/__tests__/use-vocall.test.ts` | 25 | useVocall composable, reactive state |
|
|
506
|
+
| `src/composables/__tests__/use-vocall-field.test.ts` | 13 | useVocallField composable, template ref binding |
|
|
507
|
+
| `src/composables/__tests__/use-vocall-action.test.ts` | 7 | useVocallAction composable, callback registration |
|
|
508
|
+
| `src/plugin/__tests__/vocall-plugin.test.ts` | 8 | VocallPlugin installation, provide/inject |
|
|
509
|
+
| `src/voice/__tests__/frame-splitter.test.ts` | 13 | Audio frame splitting for voice pipeline |
|
|
510
|
+
|
|
511
|
+
### Test Configuration
|
|
512
|
+
|
|
513
|
+
- **Framework:** Vitest with Vue Test Utils
|
|
514
|
+
- **Environment:** jsdom
|
|
515
|
+
- **Config:** [vitest.config.ts](vitest.config.ts) | [src/testing/setup.ts](src/testing/setup.ts)
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Development
|
|
520
|
+
|
|
521
|
+
### Building the SDK
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
npm install
|
|
525
|
+
npm run build
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Running the Demo
|
|
529
|
+
|
|
530
|
+
The demo application is in the `demo/` directory:
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
cd demo
|
|
534
|
+
npm install
|
|
535
|
+
npm run dev # http://localhost:5173
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
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.
|
|
539
|
+
|
|
540
|
+
### Docker
|
|
541
|
+
|
|
542
|
+
When running from the workspace, the demo is available as a Docker container:
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
# From the workspace root
|
|
546
|
+
make serve-all # Starts engine + all demos
|
|
547
|
+
# Vue demo at http://localhost:21004
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Related
|
|
553
|
+
|
|
554
|
+
This SDK is part of the [Primoia Vocall Workspace](https://github.com/primoia/primoia-vocall-workspace).
|
|
555
|
+
|
|
556
|
+
| Resource | Link |
|
|
557
|
+
|---|---|
|
|
558
|
+
| Workspace (setup, Docker) | [primoia-vocall-workspace](https://github.com/primoia/primoia-vocall-workspace#readme) |
|
|
559
|
+
| Angular SDK | [vocall-sdk-angular](https://github.com/primoia/vocall-sdk-angular) |
|
|
560
|
+
| Next.js SDK | [vocall-sdk-nextjs](https://github.com/primoia/vocall-sdk-nextjs) |
|
|
561
|
+
| Kotlin SDK | [vocall-sdk-kotlin](https://github.com/primoia/vocall-sdk-kotlin) |
|
|
562
|
+
| Swift SDK | [vocall-sdk-swift](https://github.com/primoia/vocall-sdk-swift) |
|
|
563
|
+
| Flutter SDK | [jarvis-sdk-flutter](https://github.com/primoia/jarvis-sdk-flutter) |
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
## License
|
|
568
|
+
|
|
569
|
+
Proprietary. All rights reserved.
|