vanilla-agent 1.7.0 → 1.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanilla-agent",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "Themeable, plugable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/index.ts CHANGED
@@ -39,6 +39,7 @@ export {
39
39
  export {
40
40
  createPlainTextParser,
41
41
  createJsonStreamParser,
42
+ createFlexibleJsonStreamParser,
42
43
  createRegexJsonParser,
43
44
  createXmlParser
44
45
  } from "./utils/formatting";
@@ -301,6 +301,91 @@ export const createJsonStreamParser = (): AgentWidgetStreamParser => {
301
301
  };
302
302
  };
303
303
 
304
+ /**
305
+ * Flexible JSON stream parser that can extract text from various field names.
306
+ * This parser looks for display text in multiple possible fields, making it
307
+ * compatible with different JSON response formats.
308
+ *
309
+ * @param textExtractor Optional function to extract display text from parsed JSON.
310
+ * If not provided, looks for common text fields.
311
+ */
312
+ export const createFlexibleJsonStreamParser = (
313
+ textExtractor?: (parsed: any) => string | null
314
+ ): AgentWidgetStreamParser => {
315
+ let extractedText: string | null = null;
316
+ let processedLength = 0;
317
+
318
+ // Default text extractor that handles common patterns
319
+ const defaultExtractor = (parsed: any): string | null => {
320
+ if (!parsed || typeof parsed !== "object") return null;
321
+
322
+ // Check for action-based text fields
323
+ if (parsed.action) {
324
+ switch (parsed.action) {
325
+ case 'nav_then_click':
326
+ return parsed.on_load_text || parsed.text || null;
327
+ case 'message':
328
+ case 'message_and_click':
329
+ case 'checkout':
330
+ return parsed.text || null;
331
+ default:
332
+ return parsed.text || parsed.display_text || parsed.message || null;
333
+ }
334
+ }
335
+
336
+ // Fallback to common text field names
337
+ return parsed.text || parsed.display_text || parsed.message || parsed.content || null;
338
+ };
339
+
340
+ const extractText = textExtractor || defaultExtractor;
341
+
342
+ return {
343
+ getExtractedText: () => extractedText,
344
+ processChunk: (accumulatedContent: string): AgentWidgetStreamParserResult | string | null => {
345
+ // Validate that the accumulated content looks like JSON
346
+ const trimmed = accumulatedContent.trim();
347
+ if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
348
+ return null;
349
+ }
350
+
351
+ // Skip if no new content
352
+ if (accumulatedContent.length <= processedLength) {
353
+ return extractedText !== null
354
+ ? { text: extractedText, raw: accumulatedContent }
355
+ : null;
356
+ }
357
+
358
+ try {
359
+ // Parse partial JSON - allow partial strings and objects
360
+ // STR | OBJ allows incomplete strings and objects during streaming
361
+ const parsed = parsePartialJson(accumulatedContent, STR | OBJ);
362
+
363
+ // Extract text using the provided or default extractor
364
+ const newText = extractText(parsed);
365
+ if (newText !== null) {
366
+ extractedText = newText;
367
+ }
368
+ } catch (error) {
369
+ // If parsing fails completely, keep the last extracted text
370
+ // This can happen with very malformed JSON
371
+ }
372
+
373
+ // Update processed length
374
+ processedLength = accumulatedContent.length;
375
+
376
+ // Always return the raw JSON for action parsing
377
+ // Text may be null during early streaming, that's ok
378
+ return {
379
+ text: extractedText || "",
380
+ raw: accumulatedContent
381
+ };
382
+ },
383
+ close: () => {
384
+ // No cleanup needed
385
+ }
386
+ };
387
+ };
388
+
304
389
  /**
305
390
  * XML stream parser.
306
391
  * Extracts text from <text>...</text> tags in XML responses.