@far-world-labs/verblets 0.1.2 → 0.1.3
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/.github/workflows/ci.yml +3 -0
- package/README.md +45 -462
- package/package.json +2 -2
- package/src/chains/list/index.spec.js +6 -1
- package/src/lib/search-js-files/index.js +26 -9
- package/src/lib/transcribe/index.js +23 -6
- package/src/prompts/intent.js +15 -16
- package/src/verblets/intent/index.examples.js +14 -9
package/.github/workflows/ci.yml
CHANGED
package/README.md
CHANGED
|
@@ -108,76 +108,75 @@ Codebase utilities analyze, test, and improve code quality using AI reasoning. T
|
|
|
108
108
|
This example shows how verblets enable building systems that understand context, make nuanced decisions, and adapt to complex real-world scenarios - capabilities that would be nearly impossible with traditional programming approaches.
|
|
109
109
|
|
|
110
110
|
```javascript
|
|
111
|
+
import bulkMap from './src/chains/bulk-map/index.js';
|
|
112
|
+
import list from './src/chains/list/index.js';
|
|
111
113
|
import {
|
|
112
|
-
|
|
113
|
-
sentiment,
|
|
114
|
+
anonymize,
|
|
114
115
|
bool,
|
|
115
116
|
enum,
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
intent,
|
|
118
|
+
listFilter,
|
|
118
119
|
questions,
|
|
119
120
|
sort,
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
toObject,
|
|
122
|
+
sentiment,
|
|
123
|
+
bulkScore
|
|
122
124
|
} from 'verblets';
|
|
123
125
|
|
|
124
126
|
// Intelligent customer support system that handles complex, contextual requests
|
|
125
|
-
async function handleCustomerRequest(
|
|
126
|
-
// 1. Understand what the customer actually wants
|
|
127
|
+
async function handleCustomerRequest(message, history, catalog) {
|
|
127
128
|
const customerIntent = await intent({
|
|
128
|
-
text:
|
|
129
|
+
text: message,
|
|
129
130
|
operations: [
|
|
130
131
|
{ name: 'refund-request', parameters: { reason: 'string', orderNumber: 'string?' } },
|
|
131
132
|
{ name: 'product-inquiry', parameters: { productType: 'string', feature: 'string?' } },
|
|
132
133
|
{ name: 'technical-support', parameters: { issue: 'string', urgency: 'string' } },
|
|
133
|
-
{ name: 'complaint', parameters: { category: 'string', severity: 'string' } }
|
|
134
|
-
]
|
|
134
|
+
{ name: 'complaint', parameters: { category: 'string', severity: 'string' } }
|
|
135
|
+
]
|
|
135
136
|
});
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
const isUrgent = await bool(`Is this customer request urgent? ${customerMessage}`);
|
|
138
|
+
const emotion = await sentiment(message);
|
|
139
|
+
const urgent = await bool(`Is this urgent? ${message}`);
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
const responseStrategy = await enum(customerMessage, {
|
|
141
|
+
const strategy = await enum(message, {
|
|
143
142
|
immediate_escalation: 'Customer is very upset, escalate to human agent',
|
|
144
143
|
detailed_help: 'Customer needs comprehensive assistance',
|
|
145
144
|
quick_resolution: 'Simple issue that can be resolved quickly',
|
|
146
|
-
educational: 'Customer needs to understand how something works'
|
|
145
|
+
educational: 'Customer needs to understand how something works'
|
|
147
146
|
});
|
|
148
147
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
`Customer says: "${customerMessage}". What should we ask to help them better?`
|
|
148
|
+
const followUpQuestions = await questions(
|
|
149
|
+
`Customer says: "${message}". What should we ask to help them better?`
|
|
152
150
|
);
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
productCatalog,
|
|
152
|
+
const candidates = await listFilter(
|
|
153
|
+
catalog,
|
|
157
154
|
`Products that might solve: ${
|
|
158
155
|
customerIntent.parameters.issue || customerIntent.parameters.productType
|
|
159
156
|
}`
|
|
160
157
|
);
|
|
161
158
|
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
const scores = await bulkScore(candidates, 'resolution likelihood');
|
|
160
|
+
const prioritized = await sort(candidates, `by likelihood score ${scores.join(', ')}`);
|
|
161
|
+
|
|
162
|
+
const bulletPoints = await bulkMap(
|
|
163
|
+
prioritized.map(p => p.name),
|
|
164
|
+
'Write a friendly one-line apology referencing <list>.'
|
|
166
165
|
);
|
|
167
166
|
|
|
168
|
-
|
|
167
|
+
const sampleReplies = await list('3 reassuring follow-up messages for this customer');
|
|
168
|
+
|
|
169
169
|
const caseSummary = await anonymize(
|
|
170
|
-
`Customer ${customerIntent.intent.operation}: ${
|
|
171
|
-
History: ${
|
|
170
|
+
`Customer ${customerIntent.intent.operation}: ${message}.
|
|
171
|
+
History: ${history}. Resolution: ${prioritized[0]}`
|
|
172
172
|
);
|
|
173
173
|
|
|
174
|
-
// 8. Structure the complete response
|
|
175
174
|
const response = await toObject(
|
|
176
175
|
`
|
|
177
176
|
Customer needs ${customerIntent.intent.operation} help.
|
|
178
|
-
They are ${
|
|
179
|
-
Best approach: ${
|
|
180
|
-
Top solution: ${
|
|
177
|
+
They are ${emotion} and ${urgent ? 'urgent' : 'not urgent'}.
|
|
178
|
+
Best approach: ${strategy}.
|
|
179
|
+
Top solution: ${prioritized[0]?.name}
|
|
181
180
|
`,
|
|
182
181
|
{
|
|
183
182
|
type: 'object',
|
|
@@ -187,15 +186,18 @@ async function handleCustomerRequest(customerMessage, customerHistory, productCa
|
|
|
187
186
|
emotion: { type: 'string' },
|
|
188
187
|
strategy: { type: 'string' },
|
|
189
188
|
recommendedSolution: { type: 'string' },
|
|
190
|
-
followUpQuestions: { type: 'array' }
|
|
191
|
-
}
|
|
189
|
+
followUpQuestions: { type: 'array' }
|
|
190
|
+
}
|
|
192
191
|
}
|
|
193
192
|
);
|
|
194
193
|
|
|
194
|
+
|
|
195
195
|
return {
|
|
196
196
|
...response,
|
|
197
|
-
followUpQuestions:
|
|
197
|
+
followUpQuestions: followUpQuestions.slice(0, 3),
|
|
198
198
|
anonymizedCase: caseSummary,
|
|
199
|
+
bulletPoints,
|
|
200
|
+
sampleReplies
|
|
199
201
|
};
|
|
200
202
|
}
|
|
201
203
|
|
|
@@ -207,26 +209,28 @@ const result = await handleCustomerRequest(
|
|
|
207
209
|
{
|
|
208
210
|
name: 'Premium Wireless Headphones',
|
|
209
211
|
category: 'audio',
|
|
210
|
-
features: ['noise-canceling', 'wireless']
|
|
212
|
+
features: ['noise-canceling', 'wireless']
|
|
211
213
|
},
|
|
212
214
|
{ name: 'Express Shipping Upgrade', category: 'service', features: ['priority', 'tracking'] },
|
|
213
|
-
{ name: 'Gift Card', category: 'compensation', features: ['flexible', 'immediate'] }
|
|
215
|
+
{ name: 'Gift Card', category: 'compensation', features: ['flexible', 'immediate'] }
|
|
214
216
|
]
|
|
215
217
|
);
|
|
216
218
|
|
|
217
219
|
/* Returns something like:
|
|
218
220
|
{
|
|
219
|
-
intent: "refund-request",
|
|
221
|
+
intent: "refund-request",
|
|
220
222
|
urgency: "high",
|
|
221
223
|
emotion: "frustrated",
|
|
222
224
|
strategy: "immediate_escalation",
|
|
223
225
|
recommendedSolution: "Express Shipping Upgrade",
|
|
224
226
|
followUpQuestions: [
|
|
225
227
|
"What's your order number so I can track this immediately?",
|
|
226
|
-
"Would you like us to expedite a replacement for tomorrow delivery?",
|
|
228
|
+
"Would you like us to expedite a replacement for tomorrow delivery?",
|
|
227
229
|
"How can we make this right for your daughter's birthday?"
|
|
228
230
|
],
|
|
229
231
|
anonymizedCase: "Customer refund-request: Customer frustrated about delayed premium headphones order for child's birthday..."
|
|
232
|
+
bulletPoints: ["Apologies for the delay on Premium Wireless Headphones", ...],
|
|
233
|
+
sampleReplies: ["We're monitoring shipping updates...", ...]
|
|
230
234
|
}
|
|
231
235
|
*/
|
|
232
236
|
```
|
|
@@ -240,427 +244,6 @@ This system demonstrates capabilities that would require thousands of lines of t
|
|
|
240
244
|
- **Privacy-aware data handling** for compliance
|
|
241
245
|
- **Structured output** that integrates with existing systems
|
|
242
246
|
|
|
243
|
-
<<<<<<< HEAD
|
|
244
|
-
With verblets, complex AI-powered workflows become as simple as calling functions.
|
|
245
|
-
=======
|
|
246
|
-
- **list** - Generate contextual lists
|
|
247
|
-
```javascript
|
|
248
|
-
await list("potential failure points in our microservices architecture");
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
- **intent** - Understand user intentions and extract structured data
|
|
252
|
-
```javascript
|
|
253
|
-
// Define what operations your system can handle
|
|
254
|
-
const operations = [
|
|
255
|
-
{
|
|
256
|
-
name: "book-flight",
|
|
257
|
-
parameters: {
|
|
258
|
-
destination: "string",
|
|
259
|
-
date: "string",
|
|
260
|
-
class: "string"
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
name: "find-song",
|
|
265
|
-
parameters: {
|
|
266
|
-
lyrics: "string",
|
|
267
|
-
artist: "string?"
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
];
|
|
271
|
-
|
|
272
|
-
// It understands flight booking requests
|
|
273
|
-
const flightRequest = await intent({
|
|
274
|
-
text: "I need a business class flight to Tokyo next Friday",
|
|
275
|
-
operations
|
|
276
|
-
});
|
|
277
|
-
/* Returns:
|
|
278
|
-
{
|
|
279
|
-
"queryText": "I need a business class flight to Tokyo next Friday",
|
|
280
|
-
"intent": {
|
|
281
|
-
"operation": "book-flight",
|
|
282
|
-
"displayName": "Book Flight"
|
|
283
|
-
},
|
|
284
|
-
"parameters": {
|
|
285
|
-
"destination": "Tokyo",
|
|
286
|
-
"date": "next Friday",
|
|
287
|
-
"class": "business"
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
*/
|
|
291
|
-
|
|
292
|
-
- **auto** - Use function calling to select and prepare operations
|
|
293
|
-
```javascript
|
|
294
|
-
// First, we have our available functions defined as schemas
|
|
295
|
-
const availableFunctions = [
|
|
296
|
-
{
|
|
297
|
-
"name": "bool",
|
|
298
|
-
"description": "Answer yes/no questions about facts or situations",
|
|
299
|
-
"parameters": {
|
|
300
|
-
"type": "object",
|
|
301
|
-
"properties": {
|
|
302
|
-
"text": {
|
|
303
|
-
"type": "string",
|
|
304
|
-
"description": "The question to answer"
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
{
|
|
310
|
-
"name": "list",
|
|
311
|
-
"description": "Generate lists of relevant items",
|
|
312
|
-
"parameters": {
|
|
313
|
-
"type": "object",
|
|
314
|
-
"properties": {
|
|
315
|
-
"text": {
|
|
316
|
-
"type": "string",
|
|
317
|
-
"description": "What to list"
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
// ... many more function definitions ...
|
|
323
|
-
];
|
|
324
|
-
|
|
325
|
-
// When someone has an urgent question
|
|
326
|
-
const result = await auto(
|
|
327
|
-
"Help! My dog just ate an avocado! Is this dangerous?"
|
|
328
|
-
);
|
|
329
|
-
/* First, auto selects the appropriate function:
|
|
330
|
-
{
|
|
331
|
-
"name": "bool", // Recognizes this needs a yes/no answer
|
|
332
|
-
"arguments": {
|
|
333
|
-
"text": "Help! My dog just ate an avocado! Is this dangerous?"
|
|
334
|
-
},
|
|
335
|
-
"functionArgsAsArray": [
|
|
336
|
-
{
|
|
337
|
-
"text": "Help! My dog just ate an avocado! Is this dangerous?"
|
|
338
|
-
}
|
|
339
|
-
]
|
|
340
|
-
}
|
|
341
|
-
*/
|
|
342
|
-
|
|
343
|
-
// Then it automatically runs the selected function internally, passing arguments it extracts
|
|
344
|
-
const answer = await bool(result.arguments.text);
|
|
345
|
-
// Returns: true (yes, it can be dangerous)
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
- **questions** - Explore topics through intelligent question generation
|
|
349
|
-
```javascript
|
|
350
|
-
|
|
351
|
-
const investigation = await questions(
|
|
352
|
-
"Why isn't my houseplant thriving?",
|
|
353
|
-
{
|
|
354
|
-
searchBreadth: 0.7, // Explore more broadly (0-1)
|
|
355
|
-
shouldStop: (q, all) => all.length > 20 // Custom stopping condition
|
|
356
|
-
}
|
|
357
|
-
);
|
|
358
|
-
/* Returns targeted diagnostic questions:
|
|
359
|
-
[
|
|
360
|
-
"Which direction does the window face?",
|
|
361
|
-
"Are the leaves turning yellow or brown?",
|
|
362
|
-
"Is the soil staying wet for long periods?",
|
|
363
|
-
"Are there any visible pests on the leaves?",
|
|
364
|
-
"When was it last repotted?",
|
|
365
|
-
"Is there good drainage in the pot?",
|
|
366
|
-
"What's the humidity level in the room?",
|
|
367
|
-
// ... continues until stopping condition ...
|
|
368
|
-
]
|
|
369
|
-
*/
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
- **shorten-text** - Intelligently compress text while preserving meaning
|
|
373
|
-
```javascript
|
|
374
|
-
// Shorten long content while keeping key information
|
|
375
|
-
const story = `Once upon a time, in a bustling city called Metropolis,
|
|
376
|
-
there lived a young programmer named Ada. She spent her days writing
|
|
377
|
-
elegant code and her nights dreaming of artificial intelligence.
|
|
378
|
-
One day, while debugging a particularly tricky neural network,
|
|
379
|
-
she discovered something extraordinary...`;
|
|
380
|
-
|
|
381
|
-
const shortened = await shortenText(story, {
|
|
382
|
-
targetTokenCount: 20,
|
|
383
|
-
minCharsToRemove: 15
|
|
384
|
-
});
|
|
385
|
-
/* Returns:
|
|
386
|
-
"Once upon a time, in Metropolis, a programmer named Ada
|
|
387
|
-
spent her days writing code... discovered something extraordinary"
|
|
388
|
-
*/
|
|
389
|
-
|
|
390
|
-
// Preserve structure while reducing size
|
|
391
|
-
const documentation = `# API Reference
|
|
392
|
-
## Authentication
|
|
393
|
-
All requests must include an API key in the header.
|
|
394
|
-
The key should be prefixed with 'Bearer '.
|
|
395
|
-
|
|
396
|
-
## Rate Limiting
|
|
397
|
-
Requests are limited to 100 per minute.
|
|
398
|
-
Exceeding this will result in a 429 response.
|
|
399
|
-
|
|
400
|
-
## Endpoints
|
|
401
|
-
GET /users - Retrieve user list
|
|
402
|
-
POST /users - Create new user
|
|
403
|
-
DELETE /users/{id} - Remove user`;
|
|
404
|
-
|
|
405
|
-
const compact = await shortenText(documentation, {
|
|
406
|
-
targetTokenCount: 30,
|
|
407
|
-
minCharsToRemove: 20
|
|
408
|
-
});
|
|
409
|
-
/* Returns:
|
|
410
|
-
"# API Reference
|
|
411
|
-
## Authentication
|
|
412
|
-
All requests need API key... 'Bearer '
|
|
413
|
-
|
|
414
|
-
## Rate Limiting
|
|
415
|
-
100 per minute... 429 response
|
|
416
|
-
|
|
417
|
-
## Endpoints
|
|
418
|
-
GET /users...DELETE /users/{id}"
|
|
419
|
-
*/
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
- **bulk-map** - Map over lists in retryable batches using the `listMap` verblet
|
|
423
|
-
```javascript
|
|
424
|
-
import { bulkMap } from './src/index.js';
|
|
425
|
-
|
|
426
|
-
const gadgets = [
|
|
427
|
-
'solar-powered flashlight',
|
|
428
|
-
'quantum laptop',
|
|
429
|
-
'smart refrigerator',
|
|
430
|
-
// ...more items
|
|
431
|
-
];
|
|
432
|
-
const results = await bulkMap(
|
|
433
|
-
gadgets,
|
|
434
|
-
'Give each item a catchphrase worthy of a blockbuster commercial',
|
|
435
|
-
{ chunkSize: 5, maxAttempts: 2 }
|
|
436
|
-
);
|
|
437
|
-
// results[0] === 'Illuminate your world with the sun'
|
|
438
|
-
// results[1] === 'Computing beyond limits'
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
- **bulk-reduce** - Reduce long lists sequentially using `listReduce`
|
|
442
|
-
```javascript
|
|
443
|
-
import bulkReduce from './src/chains/bulk-reduce/index.js';
|
|
444
|
-
|
|
445
|
-
const logLines = [
|
|
446
|
-
'User logged in',
|
|
447
|
-
'User viewed dashboard',
|
|
448
|
-
'User logged out'
|
|
449
|
-
];
|
|
450
|
-
const summary = await bulkReduce(logLines, 'Summarize the events');
|
|
451
|
-
// e.g. 'User session: login, dashboard view and logout'
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
<<<<<<< HEAD
|
|
455
|
-
**bulk-partition** - Discover the best categories and group large lists consistently
|
|
456
|
-
```javascript
|
|
457
|
-
import bulkPartition from './src/chains/bulk-partition/index.js';
|
|
458
|
-
|
|
459
|
-
const feedback = [
|
|
460
|
-
'Great interface and onboarding',
|
|
461
|
-
'Price is a bit steep',
|
|
462
|
-
'Love the mobile app',
|
|
463
|
-
'Needs more integrations'
|
|
464
|
-
];
|
|
465
|
-
const result = await bulkPartition(
|
|
466
|
-
feedback,
|
|
467
|
-
'Is each line praise, criticism, or a feature request?',
|
|
468
|
-
{ chunkSize: 2, topN: 3 }
|
|
469
|
-
);
|
|
470
|
-
// {
|
|
471
|
-
// praise: ['Great interface and onboarding', 'Love the mobile app'],
|
|
472
|
-
// criticism: ['Price is a bit steep'],
|
|
473
|
-
// 'feature request': ['Needs more integrations']
|
|
474
|
-
// }
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
- **themes** - Extract recurring themes from text
|
|
478
|
-
```javascript
|
|
479
|
-
const mainThemes = await themes(longReport, { topN: 3 });
|
|
480
|
-
// ['strategy', 'market challenges', 'team morale']
|
|
481
|
-
```
|
|
482
|
-
=======
|
|
483
|
-
- **bulk-find** - Search lists in batches using `listFind`
|
|
484
|
-
```javascript
|
|
485
|
-
import bulkFind, { bulkFindRetry } from './src/lib/bulk-find/index.js';
|
|
486
|
-
|
|
487
|
-
const diaryEntries = [
|
|
488
|
-
'Hiked up the mountains today and saw breathtaking views',
|
|
489
|
-
'Visited the local market and tried a spicy stew',
|
|
490
|
-
'Spotted penguins playing on the beach this morning'
|
|
491
|
-
];
|
|
492
|
-
const match = await bulkFindRetry(diaryEntries, 'mentions penguins', {
|
|
493
|
-
chunkSize: 2,
|
|
494
|
-
maxAttempts: 2
|
|
495
|
-
});
|
|
496
|
-
// => 'Spotted penguins playing on the beach this morning'
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
>>>>>>> f71abac (Restore eslint disable comment)
|
|
500
|
-
- **search-best-first** - Intelligently explore solution spaces
|
|
501
|
-
```javascript
|
|
502
|
-
// Find the best recipe adjustments when ingredients are missing
|
|
503
|
-
const search = new BestFirstSearch({
|
|
504
|
-
initialState: {
|
|
505
|
-
recipe: "Classic Tiramisu",
|
|
506
|
-
missing: ["mascarpone cheese", "ladyfingers"],
|
|
507
|
-
available: ["cream cheese", "pound cake", "whipped cream"]
|
|
508
|
-
},
|
|
509
|
-
goalTest: state => state.substitutions.complete && state.flavor.preserved,
|
|
510
|
-
heuristic: state => state.flavor.similarity
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
const path = await search.findPath();
|
|
514
|
-
/* Returns sequence of steps:
|
|
515
|
-
[
|
|
516
|
-
{
|
|
517
|
-
action: "substitute mascarpone",
|
|
518
|
-
details: "Mix 8oz cream cheese with 1/4 cup whipped cream",
|
|
519
|
-
confidence: 0.85
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
action: "substitute ladyfingers",
|
|
523
|
-
details: "Slice pound cake, toast until crisp, soak in coffee",
|
|
524
|
-
confidence: 0.75
|
|
525
|
-
},
|
|
526
|
-
{
|
|
527
|
-
action: "adjust ratios",
|
|
528
|
-
details: "Increase coffee soak time to 45 seconds for pound cake",
|
|
529
|
-
confidence: 0.9
|
|
530
|
-
}
|
|
531
|
-
]
|
|
532
|
-
*/
|
|
533
|
-
|
|
534
|
-
// Or find the optimal way to refactor complex code
|
|
535
|
-
const refactorPath = await new BestFirstSearch({
|
|
536
|
-
initialState: {
|
|
537
|
-
file: "src/legacy-parser.js",
|
|
538
|
-
metrics: {
|
|
539
|
-
complexity: 85,
|
|
540
|
-
coverage: 0.4,
|
|
541
|
-
maintainability: "D"
|
|
542
|
-
}
|
|
543
|
-
},
|
|
544
|
-
goalTest: state =>
|
|
545
|
-
state.metrics.complexity < 30 &&
|
|
546
|
-
state.metrics.coverage > 0.8 &&
|
|
547
|
-
state.metrics.maintainability === "A",
|
|
548
|
-
heuristic: state =>
|
|
549
|
-
(1 / state.metrics.complexity) *
|
|
550
|
-
state.metrics.coverage *
|
|
551
|
-
(state.metrics.maintainability === "A" ? 1 : 0.5)
|
|
552
|
-
}).findPath();
|
|
553
|
-
/* Returns optimal refactoring sequence:
|
|
554
|
-
[
|
|
555
|
-
{
|
|
556
|
-
action: "extract function",
|
|
557
|
-
target: "parseNestedBlocks()",
|
|
558
|
-
benefit: "Reduces complexity by 40%"
|
|
559
|
-
},
|
|
560
|
-
{
|
|
561
|
-
action: "add unit tests",
|
|
562
|
-
coverage: ["error handling", "edge cases"],
|
|
563
|
-
benefit: "Coverage increases to 85%"
|
|
564
|
-
},
|
|
565
|
-
{
|
|
566
|
-
action: "implement strategy pattern",
|
|
567
|
-
components: ["BlockParser", "InlineParser"],
|
|
568
|
-
benefit: "Maintainability improves to grade A"
|
|
569
|
-
}
|
|
570
|
-
]
|
|
571
|
-
*/
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
- **test-advice** - Get comprehensive testing and code quality insights
|
|
575
|
-
```javascript
|
|
576
|
-
// Get deep analysis of your code's test coverage and quality
|
|
577
|
-
const insights = await testAdvice("src/payment-processor.js");
|
|
578
|
-
/* Returns array of findings across multiple dimensions:
|
|
579
|
-
[
|
|
580
|
-
{
|
|
581
|
-
"name": "Boundary Testing",
|
|
582
|
-
"expected": "Handle zero-amount transactions",
|
|
583
|
-
"saw": "No validation for $0.00 payments in processPayment()",
|
|
584
|
-
"isSuccess": false
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
"name": "Success Scenarios",
|
|
588
|
-
"expected": "Processes standard credit card payment",
|
|
589
|
-
"saw": "Correctly handles Visa/MC format: line 47 validateCard()",
|
|
590
|
-
"isSuccess": true
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
"name": "Clean Code",
|
|
594
|
-
"expected": "Single responsibility in transaction logging",
|
|
595
|
-
"saw": "logPayment() mixing business logic with logging: line 92",
|
|
596
|
-
"isSuccess": false
|
|
597
|
-
},
|
|
598
|
-
// ... analyzes across 8 dimensions:
|
|
599
|
-
// - Boundary cases
|
|
600
|
-
// - Success scenarios
|
|
601
|
-
// - Failure modes
|
|
602
|
-
// - Potential defects
|
|
603
|
-
// - Best practices
|
|
604
|
-
// - Clean code principles
|
|
605
|
-
// - Code quality
|
|
606
|
-
// - Refactoring opportunities
|
|
607
|
-
]
|
|
608
|
-
*/
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
- **veiled-variants** - Mask sensitive queries with safer alternatives
|
|
612
|
-
```javascript
|
|
613
|
-
const alternatives = await veiledVariants({
|
|
614
|
-
prompt: "If pigeons are government spies, how can I ask for counter-surveillance tips without sounding paranoid?"
|
|
615
|
-
});
|
|
616
|
-
/* Returns 15 reframed queries */
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
- **scan-js** - Analyze code for quality and maintainability
|
|
620
|
-
```javascript
|
|
621
|
-
// Analyze your codebase for maintainability
|
|
622
|
-
const analysis = await scanJs({
|
|
623
|
-
entry: "src/app.js",
|
|
624
|
-
features: "maintainability"
|
|
625
|
-
});
|
|
626
|
-
/* Returns analysis of each function:
|
|
627
|
-
{
|
|
628
|
-
"src/app.js:::handlePayment": {
|
|
629
|
-
"complexity": "low",
|
|
630
|
-
"documentation": "well-documented",
|
|
631
|
-
"sideEffects": "isolated to database calls",
|
|
632
|
-
"errorHandling": "comprehensive",
|
|
633
|
-
"testability": "high"
|
|
634
|
-
},
|
|
635
|
-
"src/app.js:::validateInput": {
|
|
636
|
-
"complexity": "medium",
|
|
637
|
-
"documentation": "needs improvement",
|
|
638
|
-
"sideEffects": "pure function",
|
|
639
|
-
"errorHandling": "basic validation only",
|
|
640
|
-
"testability": "high"
|
|
641
|
-
}
|
|
642
|
-
// ... continues for all functions ...
|
|
643
|
-
}
|
|
644
|
-
*/
|
|
645
|
-
|
|
646
|
-
// Focus on specific quality aspects
|
|
647
|
-
const security = await scanJs({
|
|
648
|
-
entry: "src/auth/",
|
|
649
|
-
features: "security"
|
|
650
|
-
});
|
|
651
|
-
/* Returns security-focused analysis:
|
|
652
|
-
{
|
|
653
|
-
"src/auth/login.js:::hashPassword": {
|
|
654
|
-
"inputValidation": "sanitizes all inputs",
|
|
655
|
-
"cryptography": "uses current best practices",
|
|
656
|
-
"dataExposure": "no sensitive data in logs",
|
|
657
|
-
"authentication": "implements rate limiting"
|
|
658
|
-
}
|
|
659
|
-
// ... continues for all security-relevant functions ...
|
|
660
|
-
}
|
|
661
|
-
*/
|
|
662
|
-
```
|
|
663
|
-
>>>>>>> 01eb5cf (Add themes chain for dual reduce)
|
|
664
247
|
|
|
665
248
|
## Contributing
|
|
666
249
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
3
5
|
|
|
4
6
|
import toObject from '../../verblets/to-object/index.js';
|
|
5
7
|
import list from './index.js';
|
|
6
8
|
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
|
|
7
12
|
const loadSchema = async () => {
|
|
8
|
-
const file = (await fs.readFile('
|
|
13
|
+
const file = (await fs.readFile(join(__dirname, '../../json-schemas/cars-test.json'))).toString();
|
|
9
14
|
|
|
10
15
|
return toObject(file);
|
|
11
16
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import fs from '
|
|
2
|
-
import path from '
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
3
|
|
|
4
4
|
import parseJSParts from '../parse-js-parts/index.js';
|
|
5
5
|
import search from '../search-best-first/index.js';
|
|
@@ -10,12 +10,12 @@ export class Node {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
toString() {
|
|
13
|
-
return `${this.filename}
|
|
13
|
+
return `${this.filename}:${this.functionName}`;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const processLocalImport = async (source) => {
|
|
18
|
-
const importedFile = await fs.readFile(source, '
|
|
18
|
+
const importedFile = await fs.readFile(source, 'utf-8');
|
|
19
19
|
const parsedImport = parseJSParts(source, importedFile);
|
|
20
20
|
return Object.entries(parsedImport.functionsMap).map(([importKey, importValue]) => ({
|
|
21
21
|
filename: source,
|
|
@@ -28,18 +28,35 @@ const processNpmImport = async (source, includeNodeModules = false) => {
|
|
|
28
28
|
if (!includeNodeModules) return [];
|
|
29
29
|
|
|
30
30
|
try {
|
|
31
|
-
|
|
31
|
+
// Find the project root by looking for package.json
|
|
32
|
+
let currentDir = process.cwd();
|
|
33
|
+
let packageJsonPath = path.join(currentDir, 'package.json');
|
|
34
|
+
|
|
35
|
+
// If not found in current directory, try to find it in parent directories
|
|
36
|
+
while (
|
|
37
|
+
!(await fs
|
|
38
|
+
.access(packageJsonPath)
|
|
39
|
+
.then(() => true)
|
|
40
|
+
.catch(() => false))
|
|
41
|
+
) {
|
|
42
|
+
const parentDir = path.dirname(currentDir);
|
|
43
|
+
if (parentDir === currentDir) break; // Reached filesystem root
|
|
44
|
+
currentDir = parentDir;
|
|
45
|
+
packageJsonPath = path.join(currentDir, 'package.json');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
32
49
|
if (packageJson.dependencies[source] || packageJson.devDependencies[source]) {
|
|
33
|
-
const nodeModulePath =
|
|
50
|
+
const nodeModulePath = path.join(currentDir, 'node_modules', source);
|
|
34
51
|
const npmPackageJson = JSON.parse(
|
|
35
|
-
await fs.readFile(
|
|
52
|
+
await fs.readFile(path.join(nodeModulePath, 'package.json'), 'utf8')
|
|
36
53
|
);
|
|
37
54
|
const mainFilePath = npmPackageJson.main || 'index.js';
|
|
38
|
-
const importedFile = await fs.readFile(
|
|
55
|
+
const importedFile = await fs.readFile(path.join(nodeModulePath, mainFilePath), 'utf-8');
|
|
39
56
|
const parsedImport = parseJSParts(mainFilePath, importedFile);
|
|
40
57
|
|
|
41
58
|
return Object.entries(parsedImport.functionsMap).map(([importKey, importValue]) => ({
|
|
42
|
-
filename:
|
|
59
|
+
filename: path.join(nodeModulePath, mainFilePath),
|
|
43
60
|
functionName: importKey,
|
|
44
61
|
functionData: importValue,
|
|
45
62
|
}));
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import whisper
|
|
2
|
-
|
|
1
|
+
// Lazy import whisper to avoid initialization issues
|
|
2
|
+
let whisper;
|
|
3
|
+
let record;
|
|
4
|
+
|
|
5
|
+
async function getWhisper() {
|
|
6
|
+
if (!whisper) {
|
|
7
|
+
whisper = (await import('whisper-node')).default;
|
|
8
|
+
}
|
|
9
|
+
return whisper;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function getRecord() {
|
|
13
|
+
if (!record) {
|
|
14
|
+
record = (await import('node-record-lpcm16')).default;
|
|
15
|
+
}
|
|
16
|
+
return record;
|
|
17
|
+
}
|
|
3
18
|
|
|
4
19
|
export default class Transcriber {
|
|
5
20
|
constructor(targetWord, silenceDuration = 5000, wordPauseDuration = 2000) {
|
|
@@ -11,8 +26,9 @@ export default class Transcriber {
|
|
|
11
26
|
this.recording = null;
|
|
12
27
|
}
|
|
13
28
|
|
|
14
|
-
startRecording() {
|
|
15
|
-
|
|
29
|
+
async startRecording() {
|
|
30
|
+
const recordModule = await getRecord();
|
|
31
|
+
this.recording = recordModule.record({
|
|
16
32
|
sampleRateHertz: 16000,
|
|
17
33
|
threshold: 0,
|
|
18
34
|
recordProgram: 'rec',
|
|
@@ -29,8 +45,9 @@ export default class Transcriber {
|
|
|
29
45
|
}
|
|
30
46
|
}
|
|
31
47
|
|
|
32
|
-
transcribe(stream) {
|
|
33
|
-
|
|
48
|
+
async transcribe(stream) {
|
|
49
|
+
const whisperModule = await getWhisper();
|
|
50
|
+
whisperModule
|
|
34
51
|
.transcribeStream(stream, { streaming: true })
|
|
35
52
|
.then((transcription) => {
|
|
36
53
|
this.handleTranscription(transcription);
|
package/src/prompts/intent.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import fs from '
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
contentIsExample,
|
|
5
|
-
contentIsSchema,
|
|
6
|
-
onlyJSON,
|
|
7
|
-
contentIsIntent,
|
|
8
|
-
contentIsOperationOption,
|
|
9
|
-
contentIsParametersOptions,
|
|
10
|
-
} from './constants.js';
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
11
4
|
import wrapVariable from './wrap-variable.js';
|
|
5
|
+
import { onlyJSON } from './constants.js';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const contentIsIntent = 'The intent is:';
|
|
11
|
+
const contentIsSchema = 'The schema is:';
|
|
12
|
+
const contentIsExample = 'An example of the output is:';
|
|
13
|
+
const contentIsOperationOption = 'The possible operations are:';
|
|
14
|
+
const contentIsParametersOptions = 'The possible parameters are:';
|
|
12
15
|
|
|
13
16
|
const exampleJSON = `{
|
|
14
|
-
"
|
|
15
|
-
"intent": {
|
|
16
|
-
"operation": "play-music",
|
|
17
|
-
"displayName": "Play Music"
|
|
18
|
-
},
|
|
17
|
+
"intent": "play_music",
|
|
19
18
|
"parameters": {
|
|
20
19
|
"genre": "rock"
|
|
21
20
|
},
|
|
@@ -24,7 +23,7 @@ const exampleJSON = `{
|
|
|
24
23
|
}
|
|
25
24
|
}`;
|
|
26
25
|
|
|
27
|
-
const intentSchema = JSON.parse(await fs.readFile('
|
|
26
|
+
const intentSchema = JSON.parse(await fs.readFile(join(__dirname, '../json-schemas/intent.json')));
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* Approximates intent recognition like you might find with Wit.ai,
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
import Ajv from 'ajv';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import { describe, expect, it, beforeAll, afterAll } from 'vitest';
|
|
4
|
-
|
|
4
|
+
import { expect as aiExpect } from '../../chains/expect/index.js';
|
|
5
5
|
import { longTestTimeout } from '../../constants/common.js';
|
|
6
|
-
import
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { dirname, join } from 'path';
|
|
8
|
+
|
|
7
9
|
import intent from './index.js';
|
|
8
10
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
|
|
14
|
+
async function getIntentSchema() {
|
|
15
|
+
return JSON.parse(await fs.readFile(join(__dirname, '../../json-schemas/intent.json')));
|
|
16
|
+
}
|
|
12
17
|
|
|
13
18
|
const examples = [
|
|
14
19
|
{
|
|
15
20
|
inputs: { text: 'Give me a flight to Burgas' },
|
|
16
|
-
want: { resultSchema },
|
|
21
|
+
want: { resultSchema: getIntentSchema },
|
|
17
22
|
},
|
|
18
23
|
{
|
|
19
24
|
inputs: {
|
|
20
25
|
text: 'Lookup a song by the quote \
|
|
21
26
|
"I just gotta tell you how I\'m feeling"',
|
|
22
27
|
},
|
|
23
|
-
want: { resultSchema },
|
|
28
|
+
want: { resultSchema: getIntentSchema },
|
|
24
29
|
},
|
|
25
30
|
];
|
|
26
31
|
|
|
@@ -85,7 +90,7 @@ describe('Intent verblet', () => {
|
|
|
85
90
|
const result = await intent({ text: travelRequest });
|
|
86
91
|
|
|
87
92
|
// Traditional schema validation
|
|
88
|
-
const schema = await
|
|
93
|
+
const schema = await getIntentSchema();
|
|
89
94
|
const ajv = new Ajv();
|
|
90
95
|
const validate = ajv.compile(schema);
|
|
91
96
|
expect(validate(result)).toBe(true);
|
|
@@ -112,7 +117,7 @@ describe('Intent verblet', () => {
|
|
|
112
117
|
const result = await intent({ text: musicQuery });
|
|
113
118
|
|
|
114
119
|
// Schema validation
|
|
115
|
-
const schema = await
|
|
120
|
+
const schema = await getIntentSchema();
|
|
116
121
|
const ajv = new Ajv();
|
|
117
122
|
const validate = ajv.compile(schema);
|
|
118
123
|
expect(validate(result)).toBe(true);
|