vanilla-agent 1.23.0 → 1.24.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanilla-agent",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
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/types.ts CHANGED
@@ -105,6 +105,23 @@ export type AgentWidgetMessageFeedback = {
105
105
 
106
106
  /**
107
107
  * Configuration for message action buttons (copy, upvote, downvote)
108
+ *
109
+ * **Client Token Mode**: When using `clientToken`, feedback is automatically
110
+ * sent to your Travrse backend. Just enable the buttons and you're done!
111
+ * The `onFeedback` and `onCopy` callbacks are optional for additional local handling.
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * // With clientToken - feedback is automatic!
116
+ * config: {
117
+ * clientToken: 'ct_live_...',
118
+ * messageActions: {
119
+ * showUpvote: true,
120
+ * showDownvote: true,
121
+ * // No onFeedback needed - sent to backend automatically
122
+ * }
123
+ * }
124
+ * ```
108
125
  */
109
126
  export type AgentWidgetMessageActionsConfig = {
110
127
  /**
@@ -118,13 +135,15 @@ export type AgentWidgetMessageActionsConfig = {
118
135
  */
119
136
  showCopy?: boolean;
120
137
  /**
121
- * Show upvote button
122
- * @default false (requires backend)
138
+ * Show upvote button.
139
+ * When using `clientToken`, feedback is sent to the backend automatically.
140
+ * @default false
123
141
  */
124
142
  showUpvote?: boolean;
125
143
  /**
126
- * Show downvote button
127
- * @default false (requires backend)
144
+ * Show downvote button.
145
+ * When using `clientToken`, feedback is sent to the backend automatically.
146
+ * @default false
128
147
  */
129
148
  showDownvote?: boolean;
130
149
  /**
@@ -145,11 +164,19 @@ export type AgentWidgetMessageActionsConfig = {
145
164
  */
146
165
  layout?: "pill-inside" | "row-inside";
147
166
  /**
148
- * Callback when user submits feedback (upvote/downvote)
167
+ * Callback when user submits feedback (upvote/downvote).
168
+ *
169
+ * **Note**: When using `clientToken`, feedback is AUTOMATICALLY sent to your
170
+ * backend via `/v1/client/feedback`. This callback is called IN ADDITION to
171
+ * the automatic submission, useful for updating local UI or analytics.
149
172
  */
150
173
  onFeedback?: (feedback: AgentWidgetMessageFeedback) => void;
151
174
  /**
152
- * Callback when user copies a message
175
+ * Callback when user copies a message.
176
+ *
177
+ * **Note**: When using `clientToken`, copy events are AUTOMATICALLY tracked
178
+ * via `/v1/client/feedback`. This callback is called IN ADDITION to the
179
+ * automatic tracking.
153
180
  */
154
181
  onCopy?: (message: AgentWidgetMessage) => void;
155
182
  };
@@ -22,6 +22,154 @@ function getParserTypeFromConfig(config: AgentWidgetConfig): ParserType {
22
22
  return config.parserType ?? detectParserTypeFromStreamParser(config.streamParser) ?? "plain";
23
23
  }
24
24
 
25
+ // Helper to generate toolCall config
26
+ function generateToolCallConfig(config: any, indent: string): string[] {
27
+ const lines: string[] = [];
28
+ if (config.toolCall) {
29
+ lines.push(`${indent}toolCall: {`);
30
+ Object.entries(config.toolCall).forEach(([key, value]) => {
31
+ if (typeof value === "string") {
32
+ lines.push(`${indent} ${key}: "${value}",`);
33
+ }
34
+ });
35
+ lines.push(`${indent}},`);
36
+ }
37
+ return lines;
38
+ }
39
+
40
+ // Helper to generate messageActions config (excluding callbacks)
41
+ function generateMessageActionsConfig(config: any, indent: string): string[] {
42
+ const lines: string[] = [];
43
+ if (config.messageActions) {
44
+ const hasSerializableProps = Object.entries(config.messageActions).some(
45
+ ([key, value]) => key !== "onFeedback" && key !== "onCopy" && value !== undefined
46
+ );
47
+ if (hasSerializableProps) {
48
+ lines.push(`${indent}messageActions: {`);
49
+ Object.entries(config.messageActions).forEach(([key, value]) => {
50
+ // Skip function callbacks
51
+ if (key === "onFeedback" || key === "onCopy") return;
52
+ if (typeof value === "string") {
53
+ lines.push(`${indent} ${key}: "${value}",`);
54
+ } else if (typeof value === "boolean") {
55
+ lines.push(`${indent} ${key}: ${value},`);
56
+ }
57
+ });
58
+ lines.push(`${indent}},`);
59
+ }
60
+ }
61
+ return lines;
62
+ }
63
+
64
+ // Helper to generate markdown config (excluding renderer functions)
65
+ function generateMarkdownConfig(config: any, indent: string): string[] {
66
+ const lines: string[] = [];
67
+ if (config.markdown) {
68
+ const hasOptions = config.markdown.options && Object.keys(config.markdown.options).length > 0;
69
+ const hasDisableDefaultStyles = config.markdown.disableDefaultStyles !== undefined;
70
+
71
+ if (hasOptions || hasDisableDefaultStyles) {
72
+ lines.push(`${indent}markdown: {`);
73
+
74
+ if (hasOptions) {
75
+ lines.push(`${indent} options: {`);
76
+ Object.entries(config.markdown.options).forEach(([key, value]) => {
77
+ if (typeof value === "string") {
78
+ lines.push(`${indent} ${key}: "${value}",`);
79
+ } else if (typeof value === "boolean") {
80
+ lines.push(`${indent} ${key}: ${value},`);
81
+ }
82
+ });
83
+ lines.push(`${indent} },`);
84
+ }
85
+
86
+ if (hasDisableDefaultStyles) {
87
+ lines.push(`${indent} disableDefaultStyles: ${config.markdown.disableDefaultStyles},`);
88
+ }
89
+
90
+ lines.push(`${indent}},`);
91
+ }
92
+ }
93
+ return lines;
94
+ }
95
+
96
+ // Helper to generate layout config (excluding render functions and slots)
97
+ function generateLayoutConfig(config: any, indent: string): string[] {
98
+ const lines: string[] = [];
99
+ if (config.layout) {
100
+ const hasHeader = config.layout.header && Object.keys(config.layout.header).some(
101
+ (key: string) => key !== "render"
102
+ );
103
+ const hasMessages = config.layout.messages && Object.keys(config.layout.messages).some(
104
+ (key: string) => key !== "renderUserMessage" && key !== "renderAssistantMessage"
105
+ );
106
+
107
+ if (hasHeader || hasMessages) {
108
+ lines.push(`${indent}layout: {`);
109
+
110
+ // Header config (excluding render function)
111
+ if (hasHeader) {
112
+ lines.push(`${indent} header: {`);
113
+ Object.entries(config.layout.header).forEach(([key, value]) => {
114
+ if (key === "render") return; // Skip render function
115
+ if (typeof value === "string") {
116
+ lines.push(`${indent} ${key}: "${value}",`);
117
+ } else if (typeof value === "boolean") {
118
+ lines.push(`${indent} ${key}: ${value},`);
119
+ }
120
+ });
121
+ lines.push(`${indent} },`);
122
+ }
123
+
124
+ // Messages config (excluding render functions)
125
+ if (hasMessages) {
126
+ lines.push(`${indent} messages: {`);
127
+ Object.entries(config.layout.messages).forEach(([key, value]) => {
128
+ // Skip render functions
129
+ if (key === "renderUserMessage" || key === "renderAssistantMessage") return;
130
+
131
+ if (key === "avatar" && typeof value === "object" && value !== null) {
132
+ lines.push(`${indent} avatar: {`);
133
+ Object.entries(value as Record<string, unknown>).forEach(([avatarKey, avatarValue]) => {
134
+ if (typeof avatarValue === "string") {
135
+ lines.push(`${indent} ${avatarKey}: "${avatarValue}",`);
136
+ } else if (typeof avatarValue === "boolean") {
137
+ lines.push(`${indent} ${avatarKey}: ${avatarValue},`);
138
+ }
139
+ });
140
+ lines.push(`${indent} },`);
141
+ } else if (key === "timestamp" && typeof value === "object" && value !== null) {
142
+ // Only emit serializable timestamp properties (skip format function)
143
+ const hasSerializableTimestamp = Object.entries(value as Record<string, unknown>).some(
144
+ ([k]) => k !== "format"
145
+ );
146
+ if (hasSerializableTimestamp) {
147
+ lines.push(`${indent} timestamp: {`);
148
+ Object.entries(value as Record<string, unknown>).forEach(([tsKey, tsValue]) => {
149
+ if (tsKey === "format") return; // Skip format function
150
+ if (typeof tsValue === "string") {
151
+ lines.push(`${indent} ${tsKey}: "${tsValue}",`);
152
+ } else if (typeof tsValue === "boolean") {
153
+ lines.push(`${indent} ${tsKey}: ${tsValue},`);
154
+ }
155
+ });
156
+ lines.push(`${indent} },`);
157
+ }
158
+ } else if (typeof value === "string") {
159
+ lines.push(`${indent} ${key}: "${value}",`);
160
+ } else if (typeof value === "boolean") {
161
+ lines.push(`${indent} ${key}: ${value},`);
162
+ }
163
+ });
164
+ lines.push(`${indent} },`);
165
+ }
166
+
167
+ lines.push(`${indent}},`);
168
+ }
169
+ }
170
+ return lines;
171
+ }
172
+
25
173
  export function generateCodeSnippet(config: any, format: CodeFormat = "esm"): string {
26
174
  // Remove non-serializable properties
27
175
  const cleanConfig = { ...config };
@@ -159,6 +307,18 @@ function generateESMCode(config: any): string {
159
307
  lines.push(" },");
160
308
  }
161
309
 
310
+ // Add toolCall config
311
+ lines.push(...generateToolCallConfig(config, " "));
312
+
313
+ // Add messageActions config
314
+ lines.push(...generateMessageActionsConfig(config, " "));
315
+
316
+ // Add markdown config
317
+ lines.push(...generateMarkdownConfig(config, " "));
318
+
319
+ // Add layout config
320
+ lines.push(...generateLayoutConfig(config, " "));
321
+
162
322
  if (config.debug) {
163
323
  lines.push(` debug: ${config.debug},`);
164
324
  }
@@ -295,6 +455,18 @@ function generateReactComponentCode(config: any): string {
295
455
  lines.push(" },");
296
456
  }
297
457
 
458
+ // Add toolCall config
459
+ lines.push(...generateToolCallConfig(config, " "));
460
+
461
+ // Add messageActions config
462
+ lines.push(...generateMessageActionsConfig(config, " "));
463
+
464
+ // Add markdown config
465
+ lines.push(...generateMarkdownConfig(config, " "));
466
+
467
+ // Add layout config
468
+ lines.push(...generateLayoutConfig(config, " "));
469
+
298
470
  if (config.debug) {
299
471
  lines.push(` debug: ${config.debug},`);
300
472
  }
@@ -548,6 +720,18 @@ function generateReactAdvancedCode(config: any): string {
548
720
  lines.push(" },");
549
721
  }
550
722
 
723
+ // Add toolCall config
724
+ lines.push(...generateToolCallConfig(config, " "));
725
+
726
+ // Add messageActions config
727
+ lines.push(...generateMessageActionsConfig(config, " "));
728
+
729
+ // Add markdown config
730
+ lines.push(...generateMarkdownConfig(config, " "));
731
+
732
+ // Add layout config
733
+ lines.push(...generateLayoutConfig(config, " "));
734
+
551
735
  if (config.debug) {
552
736
  lines.push(` debug: ${config.debug},`);
553
737
  }
@@ -788,6 +972,18 @@ function generateScriptInstallerCode(config: any): string {
788
972
  lines.push(" },");
789
973
  }
790
974
 
975
+ // Add toolCall config
976
+ lines.push(...generateToolCallConfig(config, " "));
977
+
978
+ // Add messageActions config
979
+ lines.push(...generateMessageActionsConfig(config, " "));
980
+
981
+ // Add markdown config
982
+ lines.push(...generateMarkdownConfig(config, " "));
983
+
984
+ // Add layout config
985
+ lines.push(...generateLayoutConfig(config, " "));
986
+
791
987
  if (config.debug) {
792
988
  lines.push(` debug: ${config.debug},`);
793
989
  }
@@ -922,6 +1118,18 @@ function generateScriptManualCode(config: any): string {
922
1118
  lines.push(" },");
923
1119
  }
924
1120
 
1121
+ // Add toolCall config
1122
+ lines.push(...generateToolCallConfig(config, " "));
1123
+
1124
+ // Add messageActions config
1125
+ lines.push(...generateMessageActionsConfig(config, " "));
1126
+
1127
+ // Add markdown config
1128
+ lines.push(...generateMarkdownConfig(config, " "));
1129
+
1130
+ // Add layout config
1131
+ lines.push(...generateLayoutConfig(config, " "));
1132
+
925
1133
  if (config.debug) {
926
1134
  lines.push(` debug: ${config.debug},`);
927
1135
  }
@@ -1029,6 +1237,35 @@ function generateScriptAdvancedCode(config: any): string {
1029
1237
  lines.push(" ],");
1030
1238
  }
1031
1239
 
1240
+ if (config.suggestionChipsConfig) {
1241
+ lines.push(" suggestionChipsConfig: {");
1242
+ if (config.suggestionChipsConfig.fontFamily) {
1243
+ lines.push(` fontFamily: "${config.suggestionChipsConfig.fontFamily}",`);
1244
+ }
1245
+ if (config.suggestionChipsConfig.fontWeight) {
1246
+ lines.push(` fontWeight: "${config.suggestionChipsConfig.fontWeight}",`);
1247
+ }
1248
+ if (config.suggestionChipsConfig.paddingX) {
1249
+ lines.push(` paddingX: "${config.suggestionChipsConfig.paddingX}",`);
1250
+ }
1251
+ if (config.suggestionChipsConfig.paddingY) {
1252
+ lines.push(` paddingY: "${config.suggestionChipsConfig.paddingY}",`);
1253
+ }
1254
+ lines.push(" },");
1255
+ }
1256
+
1257
+ // Add toolCall config
1258
+ lines.push(...generateToolCallConfig(config, " "));
1259
+
1260
+ // Add messageActions config
1261
+ lines.push(...generateMessageActionsConfig(config, " "));
1262
+
1263
+ // Add markdown config
1264
+ lines.push(...generateMarkdownConfig(config, " "));
1265
+
1266
+ // Add layout config
1267
+ lines.push(...generateLayoutConfig(config, " "));
1268
+
1032
1269
  lines.push(" };");
1033
1270
  lines.push("</script>");
1034
1271
  lines.push("");