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