lua-cli 3.43.0 → 3.44.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.
@@ -11,6 +11,7 @@ import { PostProcessor } from 'lua-cli';
11
11
  ## Overview
12
12
 
13
13
  PostProcessors enable:
14
+
14
15
  - Format and style agent responses
15
16
  - Add branding and signatures
16
17
  - Translate responses to user's language
@@ -27,7 +28,12 @@ class PostProcessor {
27
28
  constructor(config: PostProcessorConfig);
28
29
  getName(): string;
29
30
  getDescription(): string;
30
- execute(user: UserDataInstance, message: string, response: string, channel: string): Promise<PostProcessorResponse>;
31
+ execute(
32
+ user: UserDataInstance,
33
+ message: PostProcessorMessage,
34
+ response: string,
35
+ channel: string
36
+ ): Promise<PostProcessorResponse>;
31
37
  }
32
38
  ```
33
39
 
@@ -47,20 +53,42 @@ interface PostProcessorConfig {
47
53
  */
48
54
  execute: (
49
55
  user: UserDataInstance,
50
- message: string, // Original user message
51
- response: string, // Agent's response
52
- channel: string // Channel (whatsapp, web, etc.)
56
+ message: PostProcessorMessage, // The user's message: a string OR its parts — use messageText(message)
57
+ response: string, // Agent's response
58
+ channel: string // Channel (whatsapp, web, etc.)
53
59
  ) => Promise<PostProcessorResponse>;
54
60
  }
55
61
  ```
56
62
 
63
+ ## The `message` argument
64
+
65
+ `message` is the user's message exactly as Lua received it: either a plain `string`, or an array of
66
+ message parts (`[{ type: 'text', text }, { type: 'image', ... }]`). Messages sent from Lua Desktop and most
67
+ channels arrive as parts, so never call string methods on `message` directly. Use `messageText`:
68
+
69
+ ```typescript
70
+ import { PostProcessor, messageText } from 'lua-cli';
71
+
72
+ export default new PostProcessor({
73
+ name: 'mention-question',
74
+ description: 'Reminds the user what they asked',
75
+ execute: async (user, message, response) => {
76
+ const asked = messageText(message); // '' when the message has no text (e.g. an image only)
77
+ return { modifiedResponse: asked ? `${response}\n\n(You asked: ${asked})` : response };
78
+ },
79
+ });
80
+ ```
81
+
82
+ A postprocessor that throws doesn't block the reply: Lua sends the unmodified response and records the error
83
+ in the agent's logs.
84
+
57
85
  ## Response Type
58
86
 
59
87
  PostProcessors must return:
60
88
 
61
89
  ```typescript
62
90
  interface PostProcessorResponse {
63
- modifiedResponse: string; // The formatted response text
91
+ modifiedResponse: string; // The formatted response text
64
92
  }
65
93
  ```
66
94
 
@@ -79,15 +107,15 @@ export const brandingFooter = new PostProcessor({
79
107
  const footer = '\n\n---\nšŸ’¼ Powered by Acme Corp\n🌐 www.acme.com | šŸ“§ support@acme.com';
80
108
 
81
109
  return {
82
- modifiedResponse: response + footer
110
+ modifiedResponse: response + footer,
83
111
  };
84
- }
112
+ },
85
113
  });
86
114
  ```
87
115
 
88
116
  ### Markdown Formatter
89
117
 
90
- ```typescript
118
+ ````typescript
91
119
  import { PostProcessor } from 'lua-cli';
92
120
 
93
121
  export const markdownFormatter = new PostProcessor({
@@ -116,13 +144,13 @@ export const markdownFormatter = new PostProcessor({
116
144
  formatted = formatted.replace(/\n/g, '<br>');
117
145
 
118
146
  return { modifiedResponse: formatted };
119
- }
147
+ },
120
148
  });
121
- ```
149
+ ````
122
150
 
123
151
  ### WhatsApp Formatter
124
152
 
125
- ```typescript
153
+ ````typescript
126
154
  import { PostProcessor } from 'lua-cli';
127
155
 
128
156
  export const whatsappFormatter = new PostProcessor({
@@ -157,9 +185,9 @@ export const whatsappFormatter = new PostProcessor({
157
185
  }
158
186
 
159
187
  return { modifiedResponse: formatted };
160
- }
188
+ },
161
189
  });
162
- ```
190
+ ````
163
191
 
164
192
  ### Response Translator
165
193
 
@@ -188,7 +216,7 @@ export const responseTranslator = new PostProcessor({
188
216
  pt: 'Portuguese',
189
217
  ja: 'Japanese',
190
218
  ko: 'Korean',
191
- zh: 'Chinese'
219
+ zh: 'Chinese',
192
220
  };
193
221
 
194
222
  const targetLanguage = languageNames[userLanguage] || userLanguage;
@@ -199,7 +227,7 @@ export const responseTranslator = new PostProcessor({
199
227
  );
200
228
 
201
229
  return { modifiedResponse: translatedResponse };
202
- }
230
+ },
203
231
  });
204
232
  ```
205
233
 
@@ -218,7 +246,7 @@ export const linkInjector = new PostProcessor({
218
246
  pricing: 'View pricing: https://example.com/pricing',
219
247
  support: 'Get support: https://example.com/support',
220
248
  documentation: 'Read docs: https://example.com/docs',
221
- account: 'Manage account: https://example.com/account'
249
+ account: 'Manage account: https://example.com/account',
222
250
  };
223
251
 
224
252
  let modified = response;
@@ -237,7 +265,7 @@ export const linkInjector = new PostProcessor({
237
265
  }
238
266
 
239
267
  return { modifiedResponse: modified };
240
- }
268
+ },
241
269
  });
242
270
  ```
243
271
 
@@ -268,7 +296,7 @@ export const sentimentAnalyzer = new PostProcessor({
268
296
  sentiment: result.sentiment,
269
297
  score: result.score,
270
298
  channel,
271
- timestamp: new Date().toISOString()
299
+ timestamp: new Date().toISOString(),
272
300
  });
273
301
 
274
302
  // Add positive emoji for positive sentiments
@@ -280,7 +308,7 @@ export const sentimentAnalyzer = new PostProcessor({
280
308
  }
281
309
 
282
310
  return { modifiedResponse: response };
283
- }
311
+ },
284
312
  });
285
313
  ```
286
314
 
@@ -295,23 +323,30 @@ export const legalDisclaimer = new PostProcessor({
295
323
 
296
324
  execute: async (user, message, response, channel) => {
297
325
  const financialKeywords = [
298
- 'invest', 'stock', 'trading', 'financial', 'money',
299
- 'portfolio', 'crypto', 'bitcoin', 'tax', 'retirement'
326
+ 'invest',
327
+ 'stock',
328
+ 'trading',
329
+ 'financial',
330
+ 'money',
331
+ 'portfolio',
332
+ 'crypto',
333
+ 'bitcoin',
334
+ 'tax',
335
+ 'retirement',
300
336
  ];
301
337
 
302
338
  const lowerResponse = response.toLowerCase();
303
- const containsFinancialContent = financialKeywords.some(
304
- keyword => lowerResponse.includes(keyword)
305
- );
339
+ const containsFinancialContent = financialKeywords.some((keyword) => lowerResponse.includes(keyword));
306
340
 
307
341
  if (containsFinancialContent) {
308
- const disclaimer = '\n\nāš ļø Disclaimer: This information is for educational purposes only and should not be considered financial advice. Please consult with a licensed financial advisor before making investment decisions.';
342
+ const disclaimer =
343
+ '\n\nāš ļø Disclaimer: This information is for educational purposes only and should not be considered financial advice. Please consult with a licensed financial advisor before making investment decisions.';
309
344
 
310
345
  return { modifiedResponse: response + disclaimer };
311
346
  }
312
347
 
313
348
  return { modifiedResponse: response };
314
- }
349
+ },
315
350
  });
316
351
  ```
317
352
 
@@ -331,15 +366,14 @@ export const responseSummarizer = new PostProcessor({
331
366
  }
332
367
 
333
368
  // Generate summary
334
- const summary = await AI.generate(
335
- 'Create a 1-sentence summary (TL;DR) of this response.',
336
- [{ type: 'text', text: response }]
337
- );
369
+ const summary = await AI.generate('Create a 1-sentence summary (TL;DR) of this response.', [
370
+ { type: 'text', text: response },
371
+ ]);
338
372
 
339
373
  const modified = `**TL;DR:** ${summary}\n\n---\n\n${response}`;
340
374
 
341
375
  return { modifiedResponse: modified };
342
- }
376
+ },
343
377
  });
344
378
  ```
345
379
 
@@ -371,7 +405,7 @@ export const ctaInjector = new PostProcessor({
371
405
  }
372
406
 
373
407
  return { modifiedResponse: response + cta };
374
- }
408
+ },
375
409
  });
376
410
  ```
377
411
 
@@ -398,7 +432,7 @@ export const profanityFilter = new PostProcessor({
398
432
  }
399
433
 
400
434
  return { modifiedResponse: filtered };
401
- }
435
+ },
402
436
  });
403
437
  ```
404
438
 
@@ -419,12 +453,12 @@ export const responseLogger = new PostProcessor({
419
453
  agentResponse: response,
420
454
  responseLength: response.length,
421
455
  channel,
422
- timestamp: new Date().toISOString()
456
+ timestamp: new Date().toISOString(),
423
457
  });
424
458
 
425
459
  // Return response unchanged
426
460
  return { modifiedResponse: response };
427
- }
461
+ },
428
462
  });
429
463
  ```
430
464
 
@@ -456,7 +490,7 @@ export const channelFormatter = new PostProcessor({
456
490
  default:
457
491
  return { modifiedResponse: response };
458
492
  }
459
- }
493
+ },
460
494
  });
461
495
  ```
462
496
 
@@ -505,13 +539,13 @@ export const safePostProcessor = new PostProcessor({
505
539
  error: error.message,
506
540
  userId: user.id,
507
541
  originalResponse: response,
508
- timestamp: new Date().toISOString()
542
+ timestamp: new Date().toISOString(),
509
543
  });
510
544
 
511
545
  // Return original response on error
512
546
  return { modifiedResponse: response };
513
547
  }
514
- }
548
+ },
515
549
  });
516
550
  ```
517
551
 
@@ -529,10 +563,7 @@ return { modifiedResponse: response };
529
563
  ### String Manipulation
530
564
 
531
565
  ```typescript
532
- const modified = response
533
- .replace(/old/g, 'new')
534
- .trim()
535
- .toUpperCase();
566
+ const modified = response.replace(/old/g, 'new').trim().toUpperCase();
536
567
 
537
568
  return { modifiedResponse: modified };
538
569
  ```