@foisit/vue-wrapper 2.0.0 → 2.4.1
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/README.md +631 -33
- package/index.d.ts +3 -0
- package/index.mjs +2222 -0
- package/lib/components/AssistantProvider.vue.d.ts +16 -0
- package/lib/composables/useAssistant.d.ts +3 -0
- package/lib/services/AssistantService.d.ts +42 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,35 +1,77 @@
|
|
|
1
1
|
# @foisit/vue-wrapper
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@foisit/vue-wrapper)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
5
|
|
|
5
|
-
>
|
|
6
|
-
|
|
6
|
+
> **The AI-Powered Conversational Assistant for Vue Applications**
|
|
7
|
+
|
|
8
|
+
Transform your Vue app into an intelligent, voice-ready platform. Foisit provides a drop-in AI layer that understands natural language, manages multi-step workflows, and executes actions—all with zero backend required.
|
|
9
|
+
|
|
10
|
+
> [!NOTE] > **Voice Support Status**: Voice recognition and responses are currently in development and will be released in a future update. The current version focuses on high-performance text-based interactions and AI intent matching.
|
|
7
11
|
|
|
8
12
|
---
|
|
9
13
|
|
|
10
|
-
##
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Features](#features)
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Quick Start](#quick-start)
|
|
19
|
+
- [Core Concepts](#core-concepts)
|
|
20
|
+
- [API Reference](#api-reference)
|
|
21
|
+
- [Advanced Usage](#advanced-usage)
|
|
22
|
+
- [Examples](#examples)
|
|
23
|
+
- [TypeScript Support](#typescript-support)
|
|
24
|
+
- [Best Practices](#best-practices)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- **Natural Language Understanding** - AI-powered intent matching using GPT-4o mini (proxied securely)
|
|
31
|
+
- **Smart Slot Filling** - Auto-generates forms for missing parameters
|
|
32
|
+
- **Critical Action Protection** - Built-in confirmation dialogs for dangerous operations
|
|
33
|
+
- **Premium UI** - Glassmorphic overlay with dark/light mode support
|
|
34
|
+
- **Zero Backend Required** - Secure proxy architecture keeps API keys server-side
|
|
35
|
+
- **Vue Native** - Uses Composition API, `provide/inject`, and Vue 3 patterns
|
|
36
|
+
- **Type-Safe** - Full TypeScript support with comprehensive types
|
|
37
|
+
- **Responsive** - Works flawlessly on desktop and mobile
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
11
42
|
|
|
12
43
|
```bash
|
|
13
44
|
npm install @foisit/vue-wrapper
|
|
14
45
|
```
|
|
15
46
|
|
|
47
|
+
### Peer Dependencies
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"vue": "^3.3.0"
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
16
55
|
---
|
|
17
56
|
|
|
18
|
-
##
|
|
57
|
+
## Quick Start
|
|
19
58
|
|
|
20
|
-
|
|
59
|
+
### Step 1: Wrap Your App
|
|
21
60
|
|
|
22
61
|
```vue
|
|
23
62
|
<script setup lang="ts">
|
|
24
63
|
import { AssistantProvider } from '@foisit/vue-wrapper';
|
|
25
64
|
|
|
26
65
|
const config = {
|
|
27
|
-
introMessage: '
|
|
66
|
+
introMessage: 'Welcome! How can I assist you today?',
|
|
28
67
|
enableSmartIntent: true,
|
|
29
68
|
commands: [
|
|
30
69
|
{
|
|
31
|
-
command: '
|
|
32
|
-
action: () =>
|
|
70
|
+
command: 'navigate to profile',
|
|
71
|
+
action: () => {
|
|
72
|
+
window.location.href = '/profile';
|
|
73
|
+
return 'Navigating to profile...';
|
|
74
|
+
},
|
|
33
75
|
},
|
|
34
76
|
],
|
|
35
77
|
};
|
|
@@ -37,63 +79,619 @@ const config = {
|
|
|
37
79
|
|
|
38
80
|
<template>
|
|
39
81
|
<AssistantProvider :config="config">
|
|
40
|
-
<
|
|
82
|
+
<YourApp />
|
|
41
83
|
</AssistantProvider>
|
|
42
84
|
</template>
|
|
43
85
|
```
|
|
44
86
|
|
|
87
|
+
### Step 2: Use the Service
|
|
88
|
+
|
|
89
|
+
```vue
|
|
90
|
+
<script setup lang="ts">
|
|
91
|
+
import { inject } from 'vue';
|
|
92
|
+
import type { AssistantService } from '@foisit/vue-wrapper';
|
|
93
|
+
|
|
94
|
+
const assistant = inject<AssistantService>('assistantService');
|
|
95
|
+
|
|
96
|
+
const openAssistant = () => {
|
|
97
|
+
assistant?.toggle();
|
|
98
|
+
};
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<template>
|
|
102
|
+
<button @click="openAssistant">Open Assistant</button>
|
|
103
|
+
</template>
|
|
104
|
+
```
|
|
105
|
+
|
|
45
106
|
---
|
|
46
107
|
|
|
47
|
-
##
|
|
108
|
+
## Core Concepts
|
|
48
109
|
|
|
49
|
-
|
|
110
|
+
### 1. Commands
|
|
50
111
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
112
|
+
Commands are the building blocks of your assistant. Each command represents an action users can trigger through natural language.
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
{
|
|
116
|
+
command: 'delete account',
|
|
117
|
+
description: 'Permanently delete user account',
|
|
118
|
+
action: () => accountService.delete()
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 2. Parameters (Slot Filling)
|
|
123
|
+
|
|
124
|
+
Define parameters and Foisit will automatically generate forms to collect them:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
{
|
|
128
|
+
command: 'create user',
|
|
129
|
+
description: 'Create a new user account',
|
|
130
|
+
parameters: [
|
|
131
|
+
{ name: 'username', type: 'string', required: true },
|
|
132
|
+
{ name: 'email', type: 'string', required: true },
|
|
133
|
+
{ name: 'age', type: 'number', required: false }
|
|
134
|
+
],
|
|
135
|
+
action: (params) => userService.create(params)
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Supported Parameter Types:**
|
|
140
|
+
|
|
141
|
+
- `string` - Text input
|
|
142
|
+
- `number` - Numeric input
|
|
143
|
+
- `date` - Date picker
|
|
144
|
+
- `select` - Dropdown (static or async options)
|
|
145
|
+
- `file` - File upload input
|
|
146
|
+
|
|
147
|
+
### 3. File Parameters
|
|
148
|
+
|
|
149
|
+
Collect files via the built-in form UI and receive them in your command `action`.
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
{
|
|
153
|
+
command: 'upload file',
|
|
154
|
+
description: 'Pick a file and return it to the action',
|
|
155
|
+
parameters: [
|
|
54
156
|
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
157
|
+
name: 'attachment',
|
|
158
|
+
type: 'file',
|
|
159
|
+
required: true,
|
|
160
|
+
accept: ['image/*', 'audio/*', 'video/*'],
|
|
161
|
+
multiple: false,
|
|
162
|
+
// delivery: 'file' | 'base64' (default: 'file')
|
|
163
|
+
delivery: 'file',
|
|
59
164
|
},
|
|
60
165
|
],
|
|
166
|
+
action: async (params) => {
|
|
167
|
+
const file = params?.attachment;
|
|
168
|
+
if (!file) return { type: 'error', message: 'No file provided.' };
|
|
169
|
+
return {
|
|
170
|
+
type: 'success',
|
|
171
|
+
message: `File received. Name: ${file.name}, Type: ${file.type || 'unknown'}, Size: ${file.size} bytes`,
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`FileParameter` supports validations like `maxFiles`, `maxSizeBytes`, `maxTotalBytes`, and media/image constraints like `maxDurationSec`, `maxWidth`, and `maxHeight`.
|
|
178
|
+
|
|
179
|
+
### 4. Critical Actions
|
|
180
|
+
|
|
181
|
+
Protect dangerous operations with automatic confirmation dialogs:
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
{
|
|
185
|
+
command: 'delete all data',
|
|
186
|
+
critical: true, // Requires confirmation
|
|
187
|
+
description: 'Permanently delete all application data',
|
|
188
|
+
action: async () => {
|
|
189
|
+
await dataService.deleteAll();
|
|
190
|
+
return 'All data deleted successfully.';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 5. Select Parameters (Static)
|
|
196
|
+
|
|
197
|
+
Provide predefined options:
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
{
|
|
201
|
+
command: 'set theme',
|
|
202
|
+
parameters: [{
|
|
203
|
+
name: 'theme',
|
|
204
|
+
type: 'select',
|
|
205
|
+
options: [
|
|
206
|
+
{ label: 'Light Mode', value: 'light' },
|
|
207
|
+
{ label: 'Dark Mode', value: 'dark' },
|
|
208
|
+
{ label: 'Auto', value: 'auto' }
|
|
209
|
+
]
|
|
210
|
+
}],
|
|
211
|
+
action: (params) => setTheme(params.theme)
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 6. Dynamic Select Parameters
|
|
216
|
+
|
|
217
|
+
Load options from APIs:
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
{
|
|
221
|
+
command: 'assign to user',
|
|
222
|
+
parameters: [{
|
|
223
|
+
name: 'userId',
|
|
224
|
+
type: 'select',
|
|
225
|
+
getOptions: async () => {
|
|
226
|
+
const users = await userService.getAll();
|
|
227
|
+
return users.map(u => ({
|
|
228
|
+
label: `${u.name} (${u.email})`,
|
|
229
|
+
value: u.id
|
|
230
|
+
}));
|
|
231
|
+
}
|
|
232
|
+
}],
|
|
233
|
+
action: (params) => taskService.assign(params.userId)
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## API Reference
|
|
240
|
+
|
|
241
|
+
### `AssistantService` (via `inject`)
|
|
242
|
+
|
|
243
|
+
Injectable service for programmatic control:
|
|
244
|
+
|
|
245
|
+
#### Methods
|
|
246
|
+
|
|
247
|
+
##### `toggle(onSubmit?, onClose?)`
|
|
248
|
+
|
|
249
|
+
Opens or closes the assistant overlay.
|
|
250
|
+
|
|
251
|
+
```vue
|
|
252
|
+
<script setup>
|
|
253
|
+
import { inject } from 'vue';
|
|
254
|
+
|
|
255
|
+
const assistant = inject('assistantService');
|
|
256
|
+
|
|
257
|
+
// Basic usage
|
|
258
|
+
const open = () => assistant.toggle();
|
|
259
|
+
|
|
260
|
+
// With callbacks
|
|
261
|
+
const openWithCallbacks = () => {
|
|
262
|
+
assistant.toggle(
|
|
263
|
+
(userInput) => console.log('User said:', userInput),
|
|
264
|
+
() => console.log('Assistant closed')
|
|
265
|
+
);
|
|
61
266
|
};
|
|
267
|
+
</script>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
##### `addCommand(command, action?)`
|
|
271
|
+
|
|
272
|
+
Dynamically add or update a command at runtime. Commands registered with `addCommand` apply immediately for the running session; they are stored in memory and are not automatically persisted across page reloads.
|
|
273
|
+
|
|
274
|
+
```vue
|
|
275
|
+
<script setup>
|
|
276
|
+
import { inject, onMounted } from 'vue';
|
|
277
|
+
|
|
278
|
+
const assistant = inject('assistantService');
|
|
279
|
+
|
|
280
|
+
onMounted(() => {
|
|
281
|
+
// Add a simple command
|
|
282
|
+
assistant.addCommand('refresh data', async () => {
|
|
283
|
+
await dataService.refresh();
|
|
284
|
+
return 'Data refreshed!';
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Add a command with full config
|
|
288
|
+
assistant.addCommand({
|
|
289
|
+
command: 'export report',
|
|
290
|
+
description: 'Export data as PDF',
|
|
291
|
+
parameters: [
|
|
292
|
+
{
|
|
293
|
+
name: 'format',
|
|
294
|
+
type: 'select',
|
|
295
|
+
options: [
|
|
296
|
+
{ label: 'PDF', value: 'pdf' },
|
|
297
|
+
{ label: 'Excel', value: 'xlsx' },
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
action: async (params) => {
|
|
302
|
+
await reportService.export(params.format);
|
|
303
|
+
return `Report exported as ${params.format}`;
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
</script>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Dynamic Updates (Add / Remove / Update commands at runtime) ✅
|
|
311
|
+
|
|
312
|
+
- Use `addCommand` to add or replace a command for the current runtime.
|
|
313
|
+
- Use `removeCommand(commandPhrase)` to unregister a command immediately.
|
|
314
|
+
- When adding temporary commands inside components, remove them in `onUnmounted` (or equivalent) to avoid leaving stale commands behind.
|
|
315
|
+
|
|
316
|
+
Example — register and remove a temporary command:
|
|
317
|
+
|
|
318
|
+
```vue
|
|
319
|
+
import { onMounted, onUnmounted, inject } from 'vue'; const assistant = inject('assistantService'); onMounted(() => { assistant?.addCommand('temp action', () => 'Temporary action'); }); onUnmounted(() => { assistant?.removeCommand('temp action'); });
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Notes:
|
|
323
|
+
|
|
324
|
+
- Commands with optional parameters can return a `form` InteractiveResponse to prompt the user when no params are provided.
|
|
325
|
+
- Commands are not persisted by default; to persist them, re-register at app startup.
|
|
326
|
+
|
|
327
|
+
##### `removeCommand(commandPhrase)`
|
|
328
|
+
|
|
329
|
+
Remove a registered command.
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
assistant.removeCommand('delete account');
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
##### `getCommands()`
|
|
336
|
+
|
|
337
|
+
Get list of all registered command names.
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
const commands = assistant.getCommands();
|
|
341
|
+
console.log('Available commands:', commands);
|
|
62
342
|
```
|
|
63
343
|
|
|
64
344
|
---
|
|
65
345
|
|
|
66
|
-
##
|
|
346
|
+
## Configuration Options
|
|
347
|
+
|
|
348
|
+
### `AssistantConfig`
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
interface AssistantConfig {
|
|
352
|
+
// Activation keyword (optional)
|
|
353
|
+
activationCommand?: string;
|
|
354
|
+
|
|
355
|
+
// Welcome message shown when assistant opens
|
|
356
|
+
introMessage?: string;
|
|
357
|
+
|
|
358
|
+
// Response for unrecognized inputs
|
|
359
|
+
fallbackResponse?: string;
|
|
360
|
+
|
|
361
|
+
// Enable AI-powered natural language understanding
|
|
362
|
+
enableSmartIntent?: boolean;
|
|
363
|
+
|
|
364
|
+
// Input field placeholder text
|
|
365
|
+
inputPlaceholder?: string;
|
|
67
366
|
|
|
68
|
-
|
|
367
|
+
// List of commands
|
|
368
|
+
commands: AssistantCommand[];
|
|
69
369
|
|
|
70
|
-
|
|
71
|
-
|
|
370
|
+
// Floating button configuration
|
|
371
|
+
floatingButton?: {
|
|
372
|
+
visible?: boolean;
|
|
373
|
+
tooltip?: string;
|
|
374
|
+
customHtml?: string;
|
|
375
|
+
position?: { bottom: string; right: string };
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
```
|
|
72
379
|
|
|
73
380
|
---
|
|
74
381
|
|
|
75
|
-
##
|
|
382
|
+
## Advanced Usage
|
|
76
383
|
|
|
77
|
-
|
|
384
|
+
### Example 1: Multi-Step Booking System with Reactive State
|
|
78
385
|
|
|
79
386
|
```vue
|
|
80
387
|
<script setup lang="ts">
|
|
81
|
-
import {
|
|
388
|
+
import { ref, inject, onMounted } from 'vue';
|
|
389
|
+
import type { AssistantService } from '@foisit/vue-wrapper';
|
|
82
390
|
|
|
83
|
-
const
|
|
391
|
+
const bookings = ref([]);
|
|
392
|
+
const assistant = inject<AssistantService>('assistantService');
|
|
84
393
|
|
|
85
|
-
|
|
86
|
-
assistant
|
|
87
|
-
|
|
394
|
+
onMounted(() => {
|
|
395
|
+
assistant?.addCommand({
|
|
396
|
+
command: 'book appointment',
|
|
397
|
+
description: 'Schedule a new appointment',
|
|
398
|
+
parameters: [
|
|
399
|
+
{
|
|
400
|
+
name: 'service',
|
|
401
|
+
type: 'select',
|
|
402
|
+
required: true,
|
|
403
|
+
getOptions: async () => {
|
|
404
|
+
const services = await fetch('/api/services').then((r) => r.json());
|
|
405
|
+
return services.map((s) => ({
|
|
406
|
+
label: s.name,
|
|
407
|
+
value: s.id,
|
|
408
|
+
}));
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
{ name: 'date', type: 'date', required: true },
|
|
412
|
+
{ name: 'notes', type: 'string', required: false },
|
|
413
|
+
],
|
|
414
|
+
action: async (params) => {
|
|
415
|
+
const booking = await fetch('/api/bookings', {
|
|
416
|
+
method: 'POST',
|
|
417
|
+
body: JSON.stringify(params),
|
|
418
|
+
}).then((r) => r.json());
|
|
419
|
+
|
|
420
|
+
bookings.value.push(booking);
|
|
421
|
+
return {
|
|
422
|
+
type: 'success',
|
|
423
|
+
message: `Appointment booked for ${params.date}!`,
|
|
424
|
+
};
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
});
|
|
88
428
|
</script>
|
|
89
429
|
|
|
90
430
|
<template>
|
|
91
|
-
<
|
|
431
|
+
<div>
|
|
432
|
+
<h1>My Bookings: {{ bookings.length }}</h1>
|
|
433
|
+
<button @click="assistant?.toggle()">Book New Appointment</button>
|
|
434
|
+
</div>
|
|
92
435
|
</template>
|
|
93
436
|
```
|
|
94
437
|
|
|
438
|
+
### Example 2: E-Commerce with Vue Router
|
|
439
|
+
|
|
440
|
+
```vue
|
|
441
|
+
<script setup lang="ts">
|
|
442
|
+
import { inject, onMounted } from 'vue';
|
|
443
|
+
import { useRouter } from 'vue-router';
|
|
444
|
+
import type { AssistantService } from '@foisit/vue-wrapper';
|
|
445
|
+
|
|
446
|
+
const router = useRouter();
|
|
447
|
+
const assistant = inject<AssistantService>('assistantService');
|
|
448
|
+
|
|
449
|
+
onMounted(() => {
|
|
450
|
+
assistant?.addCommand({
|
|
451
|
+
command: 'search products',
|
|
452
|
+
parameters: [
|
|
453
|
+
{ name: 'query', type: 'string', required: true },
|
|
454
|
+
{
|
|
455
|
+
name: 'category',
|
|
456
|
+
type: 'select',
|
|
457
|
+
required: false,
|
|
458
|
+
options: [
|
|
459
|
+
{ label: 'Electronics', value: 'electronics' },
|
|
460
|
+
{ label: 'Clothing', value: 'clothing' },
|
|
461
|
+
{ label: 'Books', value: 'books' },
|
|
462
|
+
],
|
|
463
|
+
},
|
|
464
|
+
{ name: 'minPrice', type: 'number', required: false },
|
|
465
|
+
],
|
|
466
|
+
action: async (params) => {
|
|
467
|
+
const results = await searchProducts(params);
|
|
468
|
+
router.push(`/products?q=${params.query}`);
|
|
469
|
+
return `Found ${results.length} products matching "${params.query}"`;
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
</script>
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Example 3: Form Validation with Composables
|
|
477
|
+
|
|
478
|
+
```vue
|
|
479
|
+
<script setup lang="ts">
|
|
480
|
+
import { ref, inject, onMounted } from 'vue';
|
|
481
|
+
import { useAuth } from '@/composables/useAuth';
|
|
482
|
+
import type { AssistantService } from '@foisit/vue-wrapper';
|
|
483
|
+
|
|
484
|
+
const { register } = useAuth();
|
|
485
|
+
const user = ref(null);
|
|
486
|
+
const assistant = inject<AssistantService>('assistantService');
|
|
487
|
+
|
|
488
|
+
onMounted(() => {
|
|
489
|
+
assistant?.addCommand({
|
|
490
|
+
command: 'create account',
|
|
491
|
+
parameters: [
|
|
492
|
+
{ name: 'email', type: 'string', required: true },
|
|
493
|
+
{ name: 'password', type: 'string', required: true },
|
|
494
|
+
{ name: 'age', type: 'number', required: true },
|
|
495
|
+
],
|
|
496
|
+
action: async (params) => {
|
|
497
|
+
// Validation
|
|
498
|
+
if (params.age < 18) {
|
|
499
|
+
return {
|
|
500
|
+
type: 'error',
|
|
501
|
+
message: '❌ You must be 18 or older to create an account.',
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (!params.email.includes('@')) {
|
|
506
|
+
return {
|
|
507
|
+
type: 'error',
|
|
508
|
+
message: '❌ Please provide a valid email address.',
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Create account
|
|
513
|
+
try {
|
|
514
|
+
const newUser = await register(params);
|
|
515
|
+
user.value = newUser;
|
|
516
|
+
return {
|
|
517
|
+
type: 'success',
|
|
518
|
+
message: '✅ Account created successfully!',
|
|
519
|
+
};
|
|
520
|
+
} catch (error) {
|
|
521
|
+
return {
|
|
522
|
+
type: 'error',
|
|
523
|
+
message: `❌ Registration failed: ${error.message}`,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
</script>
|
|
530
|
+
|
|
531
|
+
<template>
|
|
532
|
+
<div>{{ user ? `Welcome ${user.email}` : 'No user' }}</div>
|
|
533
|
+
</template>
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## TypeScript Support
|
|
539
|
+
|
|
540
|
+
### Full Type Definitions
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
import type { AssistantCommand, InteractiveResponse } from '@foisit/core';
|
|
544
|
+
|
|
545
|
+
// Type-safe command definition
|
|
546
|
+
const myCommand: AssistantCommand = {
|
|
547
|
+
command: 'update settings',
|
|
548
|
+
description: 'Update user preferences',
|
|
549
|
+
parameters: [
|
|
550
|
+
{
|
|
551
|
+
name: 'theme',
|
|
552
|
+
type: 'select',
|
|
553
|
+
required: true,
|
|
554
|
+
options: [
|
|
555
|
+
{ label: 'Light', value: 'light' },
|
|
556
|
+
{ label: 'Dark', value: 'dark' },
|
|
557
|
+
],
|
|
558
|
+
},
|
|
559
|
+
],
|
|
560
|
+
action: async (params: { theme: string }): Promise<InteractiveResponse> => {
|
|
561
|
+
await settingsService.update(params.theme);
|
|
562
|
+
return {
|
|
563
|
+
type: 'success',
|
|
564
|
+
message: `Theme updated to ${params.theme}`,
|
|
565
|
+
};
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
```
|
|
569
|
+
|
|
95
570
|
---
|
|
96
571
|
|
|
97
|
-
##
|
|
572
|
+
## Best Practices
|
|
573
|
+
|
|
574
|
+
### 1. Use `onMounted` for Commands
|
|
575
|
+
|
|
576
|
+
Register commands in `onMounted` to ensure the assistant is ready:
|
|
577
|
+
|
|
578
|
+
```vue
|
|
579
|
+
<script setup>
|
|
580
|
+
import { inject, onMounted } from 'vue';
|
|
581
|
+
|
|
582
|
+
const assistant = inject('assistantService');
|
|
583
|
+
|
|
584
|
+
onMounted(() => {
|
|
585
|
+
assistant?.addCommand('my command', () => 'Done');
|
|
586
|
+
});
|
|
587
|
+
</script>
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### 2. Type Safety with TypeScript
|
|
591
|
+
|
|
592
|
+
Use proper type imports for better IDE support:
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
import type { AssistantService } from '@foisit/vue-wrapper';
|
|
596
|
+
|
|
597
|
+
const assistant = inject<AssistantService>('assistantService');
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### 3. Reactive State Updates
|
|
601
|
+
|
|
602
|
+
Use Vue's reactivity for state changes:
|
|
603
|
+
|
|
604
|
+
```javascript
|
|
605
|
+
action: async () => {
|
|
606
|
+
items.value.push(newItem); // ✅ Reactive update
|
|
607
|
+
return 'Item added';
|
|
608
|
+
};
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### 4. Error Handling
|
|
612
|
+
|
|
613
|
+
Always handle errors gracefully:
|
|
614
|
+
|
|
615
|
+
```javascript
|
|
616
|
+
action: async (params) => {
|
|
617
|
+
try {
|
|
618
|
+
await apiCall(params);
|
|
619
|
+
return { type: 'success', message: '✅ Success!' };
|
|
620
|
+
} catch (error) {
|
|
621
|
+
return { type: 'error', message: `❌ ${error.message}` };
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
## Testing
|
|
629
|
+
|
|
630
|
+
### Unit Testing with Vitest
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
import { mount } from '@vue/test-utils';
|
|
634
|
+
import { AssistantProvider } from '@foisit/vue-wrapper';
|
|
635
|
+
import App from './App.vue';
|
|
636
|
+
|
|
637
|
+
test('renders assistant', () => {
|
|
638
|
+
const wrapper = mount(App, {
|
|
639
|
+
global: {
|
|
640
|
+
components: { AssistantProvider },
|
|
641
|
+
provide: {
|
|
642
|
+
assistantConfig: { commands: [] },
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
// Test your app with assistant
|
|
648
|
+
});
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Related Packages
|
|
654
|
+
|
|
655
|
+
- **[@foisit/core](../core)** - Core engine (auto-installed)
|
|
656
|
+
- **[@foisit/angular-wrapper](../angular-wrapper)** - Angular integration
|
|
657
|
+
- **[@foisit/react-wrapper](../react-wrapper)** - React integration
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Troubleshooting
|
|
662
|
+
|
|
663
|
+
### Assistant service is undefined
|
|
664
|
+
|
|
665
|
+
Make sure you're using `inject` after the component is mounted and within the `AssistantProvider`.
|
|
666
|
+
|
|
667
|
+
### Commands not executing
|
|
668
|
+
|
|
669
|
+
Check browser console for errors. Ensure `action` functions are returning values or promises.
|
|
670
|
+
|
|
671
|
+
### TypeScript errors
|
|
672
|
+
|
|
673
|
+
Make sure you're using Vue 3.3+ and have proper type definitions.
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## License
|
|
678
|
+
|
|
679
|
+
MIT © [Foisit](https://github.com/boluwatifee4/foisit)
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
## Contributing
|
|
684
|
+
|
|
685
|
+
Contributions are welcome! Please read our [Contributing Guide](../../CONTRIBUTING.md) first.
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## Support
|
|
690
|
+
|
|
691
|
+
- Email: support@foisit.com
|
|
692
|
+
- Discord: [Join our community](https://discord.gg/foisit)
|
|
693
|
+
- Issues: [GitHub Issues](https://github.com/boluwatifee4/foisit/issues)
|
|
694
|
+
|
|
695
|
+
---
|
|
98
696
|
|
|
99
|
-
|
|
697
|
+
**Made with ❤️ by the Foisit Team**
|