vanilla-agent 1.23.0 → 1.25.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/dist/index.cjs +24 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -7
- package/dist/index.d.ts +70 -7
- package/dist/index.global.js +69 -68
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +24 -23
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/widget.css +0 -4
- package/package.json +1 -1
- package/src/components/feedback.ts +2 -0
- package/src/defaults.ts +86 -36
- package/src/index.ts +6 -1
- package/src/install.ts +24 -1
- package/src/styles/widget.css +0 -4
- package/src/types.ts +61 -6
- package/src/ui.ts +32 -1
- package/src/utils/code-generators.ts +514 -414
- package/src/utils/message-id.ts +2 -0
- package/src/utils/theme.ts +86 -6
|
@@ -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
|
}
|
|
@@ -674,131 +858,123 @@ function generateReactAdvancedCode(config: any): string {
|
|
|
674
858
|
return lines.join("\n");
|
|
675
859
|
}
|
|
676
860
|
|
|
677
|
-
|
|
861
|
+
// Helper to build a serializable config object for JSON export
|
|
862
|
+
function buildSerializableConfig(config: any): Record<string, any> {
|
|
678
863
|
const parserType = getParserTypeFromConfig(config as AgentWidgetConfig);
|
|
679
864
|
const shouldEmitParserType = parserType !== "plain";
|
|
680
|
-
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (config.
|
|
689
|
-
if (config.
|
|
690
|
-
if (
|
|
691
|
-
|
|
692
|
-
if (config.
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
Object.entries(config.launcher).forEach(([key, value]) => {
|
|
703
|
-
if (typeof value === "string") {
|
|
704
|
-
lines.push(` ${key}: "${value}",`);
|
|
705
|
-
} else if (typeof value === "boolean") {
|
|
706
|
-
lines.push(` ${key}: ${value},`);
|
|
707
|
-
}
|
|
708
|
-
});
|
|
709
|
-
lines.push(" },");
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
if (config.copy) {
|
|
713
|
-
lines.push(" copy: {");
|
|
714
|
-
Object.entries(config.copy).forEach(([key, value]) => {
|
|
715
|
-
lines.push(` ${key}: "${value}",`);
|
|
865
|
+
|
|
866
|
+
const serializableConfig: Record<string, any> = {};
|
|
867
|
+
|
|
868
|
+
if (config.apiUrl) serializableConfig.apiUrl = config.apiUrl;
|
|
869
|
+
if (config.flowId) serializableConfig.flowId = config.flowId;
|
|
870
|
+
if (shouldEmitParserType) serializableConfig.parserType = parserType;
|
|
871
|
+
if (config.theme) serializableConfig.theme = config.theme;
|
|
872
|
+
if (config.launcher) serializableConfig.launcher = config.launcher;
|
|
873
|
+
if (config.copy) serializableConfig.copy = config.copy;
|
|
874
|
+
if (config.sendButton) serializableConfig.sendButton = config.sendButton;
|
|
875
|
+
if (config.voiceRecognition) serializableConfig.voiceRecognition = config.voiceRecognition;
|
|
876
|
+
if (config.statusIndicator) serializableConfig.statusIndicator = config.statusIndicator;
|
|
877
|
+
if (config.features) serializableConfig.features = config.features;
|
|
878
|
+
if (config.suggestionChips?.length > 0) serializableConfig.suggestionChips = config.suggestionChips;
|
|
879
|
+
if (config.suggestionChipsConfig) serializableConfig.suggestionChipsConfig = config.suggestionChipsConfig;
|
|
880
|
+
if (config.debug) serializableConfig.debug = config.debug;
|
|
881
|
+
|
|
882
|
+
// Add toolCall config (only serializable parts)
|
|
883
|
+
if (config.toolCall) {
|
|
884
|
+
const toolCallConfig: Record<string, any> = {};
|
|
885
|
+
Object.entries(config.toolCall).forEach(([key, value]) => {
|
|
886
|
+
if (typeof value === "string") toolCallConfig[key] = value;
|
|
716
887
|
});
|
|
717
|
-
|
|
888
|
+
if (Object.keys(toolCallConfig).length > 0) {
|
|
889
|
+
serializableConfig.toolCall = toolCallConfig;
|
|
890
|
+
}
|
|
718
891
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
892
|
+
|
|
893
|
+
// Add messageActions config (excluding callbacks)
|
|
894
|
+
if (config.messageActions) {
|
|
895
|
+
const messageActionsConfig: Record<string, any> = {};
|
|
896
|
+
Object.entries(config.messageActions).forEach(([key, value]) => {
|
|
897
|
+
if (key !== "onFeedback" && key !== "onCopy" && value !== undefined) {
|
|
898
|
+
if (typeof value === "string" || typeof value === "boolean") {
|
|
899
|
+
messageActionsConfig[key] = value;
|
|
900
|
+
}
|
|
727
901
|
}
|
|
728
902
|
});
|
|
729
|
-
|
|
903
|
+
if (Object.keys(messageActionsConfig).length > 0) {
|
|
904
|
+
serializableConfig.messageActions = messageActionsConfig;
|
|
905
|
+
}
|
|
730
906
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
});
|
|
743
|
-
lines.push(" },");
|
|
907
|
+
|
|
908
|
+
// Add markdown config (excluding renderer functions)
|
|
909
|
+
if (config.markdown) {
|
|
910
|
+
const markdownConfig: Record<string, any> = {};
|
|
911
|
+
if (config.markdown.options) markdownConfig.options = config.markdown.options;
|
|
912
|
+
if (config.markdown.disableDefaultStyles !== undefined) {
|
|
913
|
+
markdownConfig.disableDefaultStyles = config.markdown.disableDefaultStyles;
|
|
914
|
+
}
|
|
915
|
+
if (Object.keys(markdownConfig).length > 0) {
|
|
916
|
+
serializableConfig.markdown = markdownConfig;
|
|
917
|
+
}
|
|
744
918
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
919
|
+
|
|
920
|
+
// Add layout config (excluding render functions)
|
|
921
|
+
if (config.layout) {
|
|
922
|
+
const layoutConfig: Record<string, any> = {};
|
|
923
|
+
|
|
924
|
+
if (config.layout.header) {
|
|
925
|
+
const headerConfig: Record<string, any> = {};
|
|
926
|
+
Object.entries(config.layout.header).forEach(([key, value]) => {
|
|
927
|
+
if (key !== "render" && (typeof value === "string" || typeof value === "boolean")) {
|
|
928
|
+
headerConfig[key] = value;
|
|
929
|
+
}
|
|
930
|
+
});
|
|
931
|
+
if (Object.keys(headerConfig).length > 0) {
|
|
932
|
+
layoutConfig.header = headerConfig;
|
|
753
933
|
}
|
|
754
|
-
});
|
|
755
|
-
lines.push(" },");
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
if (config.features) {
|
|
759
|
-
lines.push(" features: {");
|
|
760
|
-
Object.entries(config.features).forEach(([key, value]) => {
|
|
761
|
-
lines.push(` ${key}: ${value},`);
|
|
762
|
-
});
|
|
763
|
-
lines.push(" },");
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
if (config.suggestionChips && config.suggestionChips.length > 0) {
|
|
767
|
-
lines.push(" suggestionChips: [");
|
|
768
|
-
config.suggestionChips.forEach((chip: string) => {
|
|
769
|
-
lines.push(` "${chip}",`);
|
|
770
|
-
});
|
|
771
|
-
lines.push(" ],");
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
if (config.suggestionChipsConfig) {
|
|
775
|
-
lines.push(" suggestionChipsConfig: {");
|
|
776
|
-
if (config.suggestionChipsConfig.fontFamily) {
|
|
777
|
-
lines.push(` fontFamily: "${config.suggestionChipsConfig.fontFamily}",`);
|
|
778
934
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
935
|
+
|
|
936
|
+
if (config.layout.messages) {
|
|
937
|
+
const messagesConfig: Record<string, any> = {};
|
|
938
|
+
Object.entries(config.layout.messages).forEach(([key, value]) => {
|
|
939
|
+
if (key !== "renderUserMessage" && key !== "renderAssistantMessage") {
|
|
940
|
+
if (key === "avatar" && typeof value === "object" && value !== null) {
|
|
941
|
+
messagesConfig.avatar = value;
|
|
942
|
+
} else if (key === "timestamp" && typeof value === "object" && value !== null) {
|
|
943
|
+
// Exclude format function
|
|
944
|
+
const tsConfig: Record<string, any> = {};
|
|
945
|
+
Object.entries(value as Record<string, unknown>).forEach(([tsKey, tsValue]) => {
|
|
946
|
+
if (tsKey !== "format" && (typeof tsValue === "string" || typeof tsValue === "boolean")) {
|
|
947
|
+
tsConfig[tsKey] = tsValue;
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
if (Object.keys(tsConfig).length > 0) {
|
|
951
|
+
messagesConfig.timestamp = tsConfig;
|
|
952
|
+
}
|
|
953
|
+
} else if (typeof value === "string" || typeof value === "boolean") {
|
|
954
|
+
messagesConfig[key] = value;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
if (Object.keys(messagesConfig).length > 0) {
|
|
959
|
+
layoutConfig.messages = messagesConfig;
|
|
960
|
+
}
|
|
784
961
|
}
|
|
785
|
-
|
|
786
|
-
|
|
962
|
+
|
|
963
|
+
if (Object.keys(layoutConfig).length > 0) {
|
|
964
|
+
serializableConfig.layout = layoutConfig;
|
|
787
965
|
}
|
|
788
|
-
lines.push(" },");
|
|
789
966
|
}
|
|
967
|
+
|
|
968
|
+
return serializableConfig;
|
|
969
|
+
}
|
|
790
970
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
lines.push("</script>");
|
|
799
|
-
lines.push("<script src=\"https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/install.global.js\"></script>");
|
|
800
|
-
|
|
801
|
-
return lines.join("\n");
|
|
971
|
+
function generateScriptInstallerCode(config: any): string {
|
|
972
|
+
const serializableConfig = buildSerializableConfig(config);
|
|
973
|
+
|
|
974
|
+
// Escape single quotes in JSON for HTML attribute
|
|
975
|
+
const configJson = JSON.stringify(serializableConfig, null, 0).replace(/'/g, "'");
|
|
976
|
+
|
|
977
|
+
return `<script src="https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/install.global.js" data-config='${configJson}'></script>`;
|
|
802
978
|
}
|
|
803
979
|
|
|
804
980
|
function generateScriptManualCode(config: any): string {
|
|
@@ -922,6 +1098,18 @@ function generateScriptManualCode(config: any): string {
|
|
|
922
1098
|
lines.push(" },");
|
|
923
1099
|
}
|
|
924
1100
|
|
|
1101
|
+
// Add toolCall config
|
|
1102
|
+
lines.push(...generateToolCallConfig(config, " "));
|
|
1103
|
+
|
|
1104
|
+
// Add messageActions config
|
|
1105
|
+
lines.push(...generateMessageActionsConfig(config, " "));
|
|
1106
|
+
|
|
1107
|
+
// Add markdown config
|
|
1108
|
+
lines.push(...generateMarkdownConfig(config, " "));
|
|
1109
|
+
|
|
1110
|
+
// Add layout config
|
|
1111
|
+
lines.push(...generateLayoutConfig(config, " "));
|
|
1112
|
+
|
|
925
1113
|
if (config.debug) {
|
|
926
1114
|
lines.push(` debug: ${config.debug},`);
|
|
927
1115
|
}
|
|
@@ -935,312 +1123,224 @@ function generateScriptManualCode(config: any): string {
|
|
|
935
1123
|
}
|
|
936
1124
|
|
|
937
1125
|
function generateScriptAdvancedCode(config: any): string {
|
|
1126
|
+
const serializableConfig = buildSerializableConfig(config);
|
|
1127
|
+
const configJson = JSON.stringify(serializableConfig, null, 2);
|
|
1128
|
+
|
|
938
1129
|
const lines: string[] = [
|
|
939
|
-
"<!-- Load CSS -->",
|
|
940
|
-
"<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/widget.css\" />",
|
|
941
|
-
"",
|
|
942
|
-
"<!-- Chat Widget Configuration -->",
|
|
943
1130
|
"<script>",
|
|
944
|
-
"
|
|
1131
|
+
"(function() {",
|
|
1132
|
+
" 'use strict';",
|
|
1133
|
+
"",
|
|
1134
|
+
" // Configuration",
|
|
1135
|
+
` var CONFIG = ${configJson.split('\n').map((line, i) => i === 0 ? line : ' ' + line).join('\n')};`,
|
|
1136
|
+
"",
|
|
1137
|
+
" // Constants",
|
|
1138
|
+
" var CDN_BASE = 'https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist';",
|
|
1139
|
+
" var STORAGE_KEY = 'chat-widget-state';",
|
|
1140
|
+
" var PROCESSED_ACTIONS_KEY = 'chat-widget-processed-actions';",
|
|
1141
|
+
"",
|
|
1142
|
+
" // DOM context provider - extracts page elements for AI context",
|
|
1143
|
+
" var domContextProvider = function() {",
|
|
1144
|
+
" var selectors = {",
|
|
1145
|
+
" products: '[data-product-id], .product-card, .product-item, [role=\"article\"]',",
|
|
1146
|
+
" buttons: 'button, [role=\"button\"], .btn',",
|
|
1147
|
+
" links: 'a[href]',",
|
|
1148
|
+
" inputs: 'input, textarea, select'",
|
|
1149
|
+
" };",
|
|
1150
|
+
"",
|
|
1151
|
+
" var elements = [];",
|
|
1152
|
+
" Object.entries(selectors).forEach(function(entry) {",
|
|
1153
|
+
" var type = entry[0], selector = entry[1];",
|
|
1154
|
+
" document.querySelectorAll(selector).forEach(function(element) {",
|
|
1155
|
+
" if (!(element instanceof HTMLElement)) return;",
|
|
1156
|
+
" var widgetHost = element.closest('.vanilla-agent-host');",
|
|
1157
|
+
" if (widgetHost) return;",
|
|
1158
|
+
" var text = element.innerText ? element.innerText.trim() : '';",
|
|
1159
|
+
" if (!text) return;",
|
|
1160
|
+
"",
|
|
1161
|
+
" var selectorString = element.id ? '#' + element.id :",
|
|
1162
|
+
" element.getAttribute('data-testid') ? '[data-testid=\"' + element.getAttribute('data-testid') + '\"]' :",
|
|
1163
|
+
" element.getAttribute('data-product-id') ? '[data-product-id=\"' + element.getAttribute('data-product-id') + '\"]' :",
|
|
1164
|
+
" element.tagName.toLowerCase();",
|
|
1165
|
+
"",
|
|
1166
|
+
" var elementData = {",
|
|
1167
|
+
" type: type,",
|
|
1168
|
+
" tagName: element.tagName.toLowerCase(),",
|
|
1169
|
+
" selector: selectorString,",
|
|
1170
|
+
" innerText: text.substring(0, 200)",
|
|
1171
|
+
" };",
|
|
1172
|
+
"",
|
|
1173
|
+
" if (type === 'links' && element instanceof HTMLAnchorElement && element.href) {",
|
|
1174
|
+
" elementData.href = element.href;",
|
|
1175
|
+
" }",
|
|
1176
|
+
" elements.push(elementData);",
|
|
1177
|
+
" });",
|
|
1178
|
+
" });",
|
|
1179
|
+
"",
|
|
1180
|
+
" var counts = elements.reduce(function(acc, el) {",
|
|
1181
|
+
" acc[el.type] = (acc[el.type] || 0) + 1;",
|
|
1182
|
+
" return acc;",
|
|
1183
|
+
" }, {});",
|
|
1184
|
+
"",
|
|
1185
|
+
" return {",
|
|
1186
|
+
" page_elements: elements.slice(0, 50),",
|
|
1187
|
+
" page_element_count: elements.length,",
|
|
1188
|
+
" element_types: counts,",
|
|
1189
|
+
" page_url: window.location.href,",
|
|
1190
|
+
" page_title: document.title,",
|
|
1191
|
+
" timestamp: new Date().toISOString()",
|
|
1192
|
+
" };",
|
|
1193
|
+
" };",
|
|
1194
|
+
"",
|
|
1195
|
+
" // Load CSS dynamically",
|
|
1196
|
+
" var loadCSS = function() {",
|
|
1197
|
+
" if (document.querySelector('link[data-vanilla-agent]')) return;",
|
|
1198
|
+
" var link = document.createElement('link');",
|
|
1199
|
+
" link.rel = 'stylesheet';",
|
|
1200
|
+
" link.href = CDN_BASE + '/widget.css';",
|
|
1201
|
+
" link.setAttribute('data-vanilla-agent', 'true');",
|
|
1202
|
+
" document.head.appendChild(link);",
|
|
1203
|
+
" };",
|
|
1204
|
+
"",
|
|
1205
|
+
" // Load JS dynamically",
|
|
1206
|
+
" var loadJS = function(callback) {",
|
|
1207
|
+
" if (window.AgentWidget) { callback(); return; }",
|
|
1208
|
+
" var script = document.createElement('script');",
|
|
1209
|
+
" script.src = CDN_BASE + '/index.global.js';",
|
|
1210
|
+
" script.onload = callback;",
|
|
1211
|
+
" script.onerror = function() { console.error('Failed to load AgentWidget'); };",
|
|
1212
|
+
" document.head.appendChild(script);",
|
|
1213
|
+
" };",
|
|
1214
|
+
"",
|
|
1215
|
+
" // Create widget config with advanced features",
|
|
1216
|
+
" var createWidgetConfig = function(agentWidget) {",
|
|
1217
|
+
" var widgetConfig = Object.assign({}, CONFIG);",
|
|
1218
|
+
"",
|
|
1219
|
+
" // Flexible JSON stream parser for handling structured actions",
|
|
1220
|
+
" widgetConfig.streamParser = function() {",
|
|
1221
|
+
" return agentWidget.createFlexibleJsonStreamParser(function(parsed) {",
|
|
1222
|
+
" if (!parsed || typeof parsed !== 'object') return null;",
|
|
1223
|
+
" if (parsed.action === 'nav_then_click') return 'Navigating...';",
|
|
1224
|
+
" if (parsed.action === 'message') return parsed.text || '';",
|
|
1225
|
+
" if (parsed.action === 'message_and_click') return parsed.text || 'Processing...';",
|
|
1226
|
+
" return parsed.text || null;",
|
|
1227
|
+
" });",
|
|
1228
|
+
" };",
|
|
1229
|
+
"",
|
|
1230
|
+
" // Action parsers to detect JSON actions in responses",
|
|
1231
|
+
" widgetConfig.actionParsers = [",
|
|
1232
|
+
" agentWidget.defaultJsonActionParser,",
|
|
1233
|
+
" function(ctx) {",
|
|
1234
|
+
" var jsonSource = ctx.message.rawContent || ctx.text || ctx.message.content;",
|
|
1235
|
+
" if (!jsonSource || typeof jsonSource !== 'string') return null;",
|
|
1236
|
+
" var cleanJson = jsonSource",
|
|
1237
|
+
" .replace(/^```(?:json)?\\s*\\n?/, '')",
|
|
1238
|
+
" .replace(/\\n?```\\s*$/, '')",
|
|
1239
|
+
" .trim();",
|
|
1240
|
+
" if (!cleanJson.startsWith('{') || !cleanJson.endsWith('}')) return null;",
|
|
1241
|
+
" try {",
|
|
1242
|
+
" var parsed = JSON.parse(cleanJson);",
|
|
1243
|
+
" if (parsed.action) return { type: parsed.action, payload: parsed };",
|
|
1244
|
+
" } catch (e) { return null; }",
|
|
1245
|
+
" return null;",
|
|
1246
|
+
" }",
|
|
1247
|
+
" ];",
|
|
1248
|
+
"",
|
|
1249
|
+
" // Action handlers for navigation and other actions",
|
|
1250
|
+
" widgetConfig.actionHandlers = [",
|
|
1251
|
+
" agentWidget.defaultActionHandlers.message,",
|
|
1252
|
+
" agentWidget.defaultActionHandlers.messageAndClick,",
|
|
1253
|
+
" function(action, context) {",
|
|
1254
|
+
" if (action.type !== 'nav_then_click') return;",
|
|
1255
|
+
" var payload = action.payload || action.raw || {};",
|
|
1256
|
+
" var url = payload.page;",
|
|
1257
|
+
" var text = payload.on_load_text || 'Navigating...';",
|
|
1258
|
+
" if (!url) return { handled: true, displayText: text };",
|
|
1259
|
+
" var messageId = context.message ? context.message.id : null;",
|
|
1260
|
+
" var processedActions = JSON.parse(localStorage.getItem(PROCESSED_ACTIONS_KEY) || '[]');",
|
|
1261
|
+
" var actionKey = 'nav_' + messageId + '_' + url;",
|
|
1262
|
+
" if (processedActions.includes(actionKey)) {",
|
|
1263
|
+
" return { handled: true, displayText: text };",
|
|
1264
|
+
" }",
|
|
1265
|
+
" processedActions.push(actionKey);",
|
|
1266
|
+
" localStorage.setItem(PROCESSED_ACTIONS_KEY, JSON.stringify(processedActions));",
|
|
1267
|
+
" var targetUrl = url.startsWith('http') ? url : new URL(url, window.location.origin).toString();",
|
|
1268
|
+
" window.location.href = targetUrl;",
|
|
1269
|
+
" return { handled: true, displayText: text };",
|
|
1270
|
+
" }",
|
|
1271
|
+
" ];",
|
|
1272
|
+
"",
|
|
1273
|
+
" // Send DOM context with each request",
|
|
1274
|
+
" widgetConfig.requestMiddleware = function(ctx) {",
|
|
1275
|
+
" return Object.assign({}, ctx.payload, { metadata: domContextProvider() });",
|
|
1276
|
+
" };",
|
|
1277
|
+
"",
|
|
1278
|
+
" // Markdown postprocessor",
|
|
1279
|
+
" widgetConfig.postprocessMessage = function(ctx) {",
|
|
1280
|
+
" return agentWidget.markdownPostprocessor(ctx.text);",
|
|
1281
|
+
" };",
|
|
1282
|
+
"",
|
|
1283
|
+
" return widgetConfig;",
|
|
1284
|
+
" };",
|
|
1285
|
+
"",
|
|
1286
|
+
" // Initialize widget",
|
|
1287
|
+
" var init = function() {",
|
|
1288
|
+
" var agentWidget = window.AgentWidget;",
|
|
1289
|
+
" if (!agentWidget) {",
|
|
1290
|
+
" console.error('AgentWidget not loaded');",
|
|
1291
|
+
" return;",
|
|
1292
|
+
" }",
|
|
1293
|
+
"",
|
|
1294
|
+
" var widgetConfig = createWidgetConfig(agentWidget);",
|
|
1295
|
+
"",
|
|
1296
|
+
" // Load saved state",
|
|
1297
|
+
" var savedState = localStorage.getItem(STORAGE_KEY);",
|
|
1298
|
+
" if (savedState) {",
|
|
1299
|
+
" try {",
|
|
1300
|
+
" var parsed = JSON.parse(savedState);",
|
|
1301
|
+
" widgetConfig.initialMessages = parsed.messages || [];",
|
|
1302
|
+
" } catch (e) {",
|
|
1303
|
+
" console.error('Failed to load saved state:', e);",
|
|
1304
|
+
" }",
|
|
1305
|
+
" }",
|
|
1306
|
+
"",
|
|
1307
|
+
" // Initialize widget",
|
|
1308
|
+
" var handle = agentWidget.initAgentWidget({",
|
|
1309
|
+
" target: 'body',",
|
|
1310
|
+
" useShadowDom: false,",
|
|
1311
|
+
" config: widgetConfig",
|
|
1312
|
+
" });",
|
|
1313
|
+
"",
|
|
1314
|
+
" // Save state on message events",
|
|
1315
|
+
" window.addEventListener('vanilla-agent:message', function() {",
|
|
1316
|
+
" var session = handle.getSession ? handle.getSession() : null;",
|
|
1317
|
+
" if (session) {",
|
|
1318
|
+
" localStorage.setItem(STORAGE_KEY, JSON.stringify({",
|
|
1319
|
+
" messages: session.messages,",
|
|
1320
|
+
" timestamp: new Date().toISOString()",
|
|
1321
|
+
" }));",
|
|
1322
|
+
" }",
|
|
1323
|
+
" });",
|
|
1324
|
+
"",
|
|
1325
|
+
" // Clear state on clear chat",
|
|
1326
|
+
" window.addEventListener('vanilla-agent:clear-chat', function() {",
|
|
1327
|
+
" localStorage.removeItem(STORAGE_KEY);",
|
|
1328
|
+
" localStorage.removeItem(PROCESSED_ACTIONS_KEY);",
|
|
1329
|
+
" });",
|
|
1330
|
+
" };",
|
|
1331
|
+
"",
|
|
1332
|
+
" // Boot sequence: load CSS, then JS, then initialize",
|
|
1333
|
+
" loadCSS();",
|
|
1334
|
+
" loadJS(function() {",
|
|
1335
|
+
" if (document.readyState === 'loading') {",
|
|
1336
|
+
" document.addEventListener('DOMContentLoaded', init);",
|
|
1337
|
+
" } else {",
|
|
1338
|
+
" init();",
|
|
1339
|
+
" }",
|
|
1340
|
+
" });",
|
|
1341
|
+
"})();",
|
|
1342
|
+
"</script>"
|
|
945
1343
|
];
|
|
946
1344
|
|
|
947
|
-
if (config.apiUrl) lines.push(` apiUrl: "${config.apiUrl}",`);
|
|
948
|
-
if (config.flowId) lines.push(` flowId: "${config.flowId}",`);
|
|
949
|
-
|
|
950
|
-
if (config.theme) {
|
|
951
|
-
lines.push(" theme: {");
|
|
952
|
-
Object.entries(config.theme).forEach(([key, value]) => {
|
|
953
|
-
lines.push(` ${key}: "${value}",`);
|
|
954
|
-
});
|
|
955
|
-
lines.push(" },");
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
if (config.launcher) {
|
|
959
|
-
lines.push(" launcher: {");
|
|
960
|
-
Object.entries(config.launcher).forEach(([key, value]) => {
|
|
961
|
-
if (typeof value === "string") {
|
|
962
|
-
lines.push(` ${key}: "${value}",`);
|
|
963
|
-
} else if (typeof value === "boolean") {
|
|
964
|
-
lines.push(` ${key}: ${value},`);
|
|
965
|
-
}
|
|
966
|
-
});
|
|
967
|
-
lines.push(" },");
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
if (config.copy) {
|
|
971
|
-
lines.push(" copy: {");
|
|
972
|
-
Object.entries(config.copy).forEach(([key, value]) => {
|
|
973
|
-
lines.push(` ${key}: "${value}",`);
|
|
974
|
-
});
|
|
975
|
-
lines.push(" },");
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
if (config.sendButton) {
|
|
979
|
-
lines.push(" sendButton: {");
|
|
980
|
-
Object.entries(config.sendButton).forEach(([key, value]) => {
|
|
981
|
-
if (typeof value === "string") {
|
|
982
|
-
lines.push(` ${key}: "${value}",`);
|
|
983
|
-
} else if (typeof value === "boolean") {
|
|
984
|
-
lines.push(` ${key}: ${value},`);
|
|
985
|
-
}
|
|
986
|
-
});
|
|
987
|
-
lines.push(" },");
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
if (config.voiceRecognition) {
|
|
991
|
-
lines.push(" voiceRecognition: {");
|
|
992
|
-
Object.entries(config.voiceRecognition).forEach(([key, value]) => {
|
|
993
|
-
if (typeof value === "string") {
|
|
994
|
-
lines.push(` ${key}: "${value}",`);
|
|
995
|
-
} else if (typeof value === "boolean") {
|
|
996
|
-
lines.push(` ${key}: ${value},`);
|
|
997
|
-
} else if (typeof value === "number") {
|
|
998
|
-
lines.push(` ${key}: ${value},`);
|
|
999
|
-
}
|
|
1000
|
-
});
|
|
1001
|
-
lines.push(" },");
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
if (config.statusIndicator) {
|
|
1005
|
-
lines.push(" statusIndicator: {");
|
|
1006
|
-
Object.entries(config.statusIndicator).forEach(([key, value]) => {
|
|
1007
|
-
if (typeof value === "string") {
|
|
1008
|
-
lines.push(` ${key}: "${value}",`);
|
|
1009
|
-
} else if (typeof value === "boolean") {
|
|
1010
|
-
lines.push(` ${key}: ${value},`);
|
|
1011
|
-
}
|
|
1012
|
-
});
|
|
1013
|
-
lines.push(" },");
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
if (config.features) {
|
|
1017
|
-
lines.push(" features: {");
|
|
1018
|
-
Object.entries(config.features).forEach(([key, value]) => {
|
|
1019
|
-
lines.push(` ${key}: ${value},`);
|
|
1020
|
-
});
|
|
1021
|
-
lines.push(" },");
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
if (config.suggestionChips && config.suggestionChips.length > 0) {
|
|
1025
|
-
lines.push(" suggestionChips: [");
|
|
1026
|
-
config.suggestionChips.forEach((chip: string) => {
|
|
1027
|
-
lines.push(` "${chip}",`);
|
|
1028
|
-
});
|
|
1029
|
-
lines.push(" ],");
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
lines.push(" };");
|
|
1033
|
-
lines.push("</script>");
|
|
1034
|
-
lines.push("");
|
|
1035
|
-
lines.push("<!-- Load the widget library -->");
|
|
1036
|
-
lines.push("<script src=\"https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/index.global.js\"></script>");
|
|
1037
|
-
lines.push("");
|
|
1038
|
-
lines.push("<!-- Chat Widget Script with DOM Helper -->");
|
|
1039
|
-
lines.push("<script>");
|
|
1040
|
-
lines.push(" (function () {");
|
|
1041
|
-
lines.push(" 'use strict';");
|
|
1042
|
-
lines.push(" ");
|
|
1043
|
-
lines.push(" const STORAGE_KEY = 'chat-widget-state';");
|
|
1044
|
-
lines.push(" const PROCESSED_ACTIONS_KEY = 'chat-widget-processed-actions';");
|
|
1045
|
-
lines.push("");
|
|
1046
|
-
lines.push(" // DOM context provider - extracts page elements for AI context");
|
|
1047
|
-
lines.push(" const domContextProvider = () => {");
|
|
1048
|
-
lines.push(" const selectors = {");
|
|
1049
|
-
lines.push(" products: '[data-product-id], .product-card, .product-item, [role=\"article\"]',");
|
|
1050
|
-
lines.push(" buttons: 'button, [role=\"button\"], .btn',");
|
|
1051
|
-
lines.push(" links: 'a[href]',");
|
|
1052
|
-
lines.push(" inputs: 'input, textarea, select'");
|
|
1053
|
-
lines.push(" };");
|
|
1054
|
-
lines.push("");
|
|
1055
|
-
lines.push(" const elements = [];");
|
|
1056
|
-
lines.push(" Object.entries(selectors).forEach(([type, selector]) => {");
|
|
1057
|
-
lines.push(" document.querySelectorAll(selector).forEach((element) => {");
|
|
1058
|
-
lines.push(" if (!(element instanceof HTMLElement)) return;");
|
|
1059
|
-
lines.push(" ");
|
|
1060
|
-
lines.push(" // Exclude elements within the widget");
|
|
1061
|
-
lines.push(" const widgetHost = element.closest('.vanilla-agent-host');");
|
|
1062
|
-
lines.push(" if (widgetHost) return;");
|
|
1063
|
-
lines.push(" ");
|
|
1064
|
-
lines.push(" const text = element.innerText?.trim();");
|
|
1065
|
-
lines.push(" if (!text) return;");
|
|
1066
|
-
lines.push("");
|
|
1067
|
-
lines.push(" const selectorString =");
|
|
1068
|
-
lines.push(" element.id ? `#${element.id}` :");
|
|
1069
|
-
lines.push(" element.getAttribute('data-testid') ? `[data-testid=\"${element.getAttribute('data-testid')}\"]` :");
|
|
1070
|
-
lines.push(" element.getAttribute('data-product-id') ? `[data-product-id=\"${element.getAttribute('data-product-id')}\"]` :");
|
|
1071
|
-
lines.push(" element.tagName.toLowerCase();");
|
|
1072
|
-
lines.push("");
|
|
1073
|
-
lines.push(" const elementData = {");
|
|
1074
|
-
lines.push(" type,");
|
|
1075
|
-
lines.push(" tagName: element.tagName.toLowerCase(),");
|
|
1076
|
-
lines.push(" selector: selectorString,");
|
|
1077
|
-
lines.push(" innerText: text.substring(0, 200)");
|
|
1078
|
-
lines.push(" };");
|
|
1079
|
-
lines.push("");
|
|
1080
|
-
lines.push(" if (type === 'links' && element instanceof HTMLAnchorElement && element.href) {");
|
|
1081
|
-
lines.push(" elementData.href = element.href;");
|
|
1082
|
-
lines.push(" }");
|
|
1083
|
-
lines.push("");
|
|
1084
|
-
lines.push(" elements.push(elementData);");
|
|
1085
|
-
lines.push(" });");
|
|
1086
|
-
lines.push(" });");
|
|
1087
|
-
lines.push("");
|
|
1088
|
-
lines.push(" const counts = elements.reduce((acc, el) => {");
|
|
1089
|
-
lines.push(" acc[el.type] = (acc[el.type] || 0) + 1;");
|
|
1090
|
-
lines.push(" return acc;");
|
|
1091
|
-
lines.push(" }, {});");
|
|
1092
|
-
lines.push("");
|
|
1093
|
-
lines.push(" return {");
|
|
1094
|
-
lines.push(" page_elements: elements.slice(0, 50),");
|
|
1095
|
-
lines.push(" page_element_count: elements.length,");
|
|
1096
|
-
lines.push(" element_types: counts,");
|
|
1097
|
-
lines.push(" page_url: window.location.href,");
|
|
1098
|
-
lines.push(" page_title: document.title,");
|
|
1099
|
-
lines.push(" timestamp: new Date().toISOString()");
|
|
1100
|
-
lines.push(" };");
|
|
1101
|
-
lines.push(" };");
|
|
1102
|
-
lines.push("");
|
|
1103
|
-
lines.push(" const createWidgetConfig = (agentWidget) => ({");
|
|
1104
|
-
lines.push(" ...window.ChatWidgetConfig,");
|
|
1105
|
-
lines.push(" // Flexible JSON stream parser for handling structured actions");
|
|
1106
|
-
lines.push(" streamParser: () => agentWidget.createFlexibleJsonStreamParser((parsed) => {");
|
|
1107
|
-
lines.push(" if (!parsed || typeof parsed !== 'object') return null;");
|
|
1108
|
-
lines.push(" ");
|
|
1109
|
-
lines.push(" // Extract display text based on action type");
|
|
1110
|
-
lines.push(" if (parsed.action === 'nav_then_click') {");
|
|
1111
|
-
lines.push(" return 'Navigating...';");
|
|
1112
|
-
lines.push(" } else if (parsed.action === 'message') {");
|
|
1113
|
-
lines.push(" return parsed.text || '';");
|
|
1114
|
-
lines.push(" } else if (parsed.action === 'message_and_click') {");
|
|
1115
|
-
lines.push(" return parsed.text || 'Processing...';");
|
|
1116
|
-
lines.push(" }");
|
|
1117
|
-
lines.push(" ");
|
|
1118
|
-
lines.push(" return parsed.text || null;");
|
|
1119
|
-
lines.push(" }),");
|
|
1120
|
-
lines.push(" // Action parsers to detect JSON actions in responses");
|
|
1121
|
-
lines.push(" actionParsers: [");
|
|
1122
|
-
lines.push(" agentWidget.defaultJsonActionParser,");
|
|
1123
|
-
lines.push(" // Custom parser for markdown-wrapped JSON");
|
|
1124
|
-
lines.push(" ({ text, message }) => {");
|
|
1125
|
-
lines.push(" const jsonSource = message.rawContent || text || message.content;");
|
|
1126
|
-
lines.push(" if (!jsonSource || typeof jsonSource !== 'string') return null;");
|
|
1127
|
-
lines.push(" ");
|
|
1128
|
-
lines.push(" // Strip markdown code fences");
|
|
1129
|
-
lines.push(" let cleanJson = jsonSource");
|
|
1130
|
-
lines.push(" .replace(/^```(?:json)?\\s*\\n?/, '')");
|
|
1131
|
-
lines.push(" .replace(/\\n?```\\s*$/, '')");
|
|
1132
|
-
lines.push(" .trim();");
|
|
1133
|
-
lines.push(" ");
|
|
1134
|
-
lines.push(" if (!cleanJson.startsWith('{') || !cleanJson.endsWith('}')) return null;");
|
|
1135
|
-
lines.push(" ");
|
|
1136
|
-
lines.push(" try {");
|
|
1137
|
-
lines.push(" const parsed = JSON.parse(cleanJson);");
|
|
1138
|
-
lines.push(" if (parsed.action) {");
|
|
1139
|
-
lines.push(" return { type: parsed.action, payload: parsed };");
|
|
1140
|
-
lines.push(" }");
|
|
1141
|
-
lines.push(" } catch (e) {");
|
|
1142
|
-
lines.push(" return null;");
|
|
1143
|
-
lines.push(" }");
|
|
1144
|
-
lines.push(" return null;");
|
|
1145
|
-
lines.push(" }");
|
|
1146
|
-
lines.push(" ],");
|
|
1147
|
-
lines.push(" // Action handlers for navigation and other actions");
|
|
1148
|
-
lines.push(" actionHandlers: [");
|
|
1149
|
-
lines.push(" agentWidget.defaultActionHandlers.message,");
|
|
1150
|
-
lines.push(" agentWidget.defaultActionHandlers.messageAndClick,");
|
|
1151
|
-
lines.push(" // Handler for nav_then_click action");
|
|
1152
|
-
lines.push(" (action, context) => {");
|
|
1153
|
-
lines.push(" if (action.type !== 'nav_then_click') return;");
|
|
1154
|
-
lines.push(" ");
|
|
1155
|
-
lines.push(" const payload = action.payload || action.raw || {};");
|
|
1156
|
-
lines.push(" const url = payload?.page;");
|
|
1157
|
-
lines.push(" const text = payload?.on_load_text || 'Navigating...';");
|
|
1158
|
-
lines.push(" ");
|
|
1159
|
-
lines.push(" if (!url) return { handled: true, displayText: text };");
|
|
1160
|
-
lines.push(" ");
|
|
1161
|
-
lines.push(" // Check if already processed");
|
|
1162
|
-
lines.push(" const messageId = context.message?.id;");
|
|
1163
|
-
lines.push(" const processedActions = JSON.parse(localStorage.getItem(PROCESSED_ACTIONS_KEY) || '[]');");
|
|
1164
|
-
lines.push(" const actionKey = `nav_${messageId}_${url}`;");
|
|
1165
|
-
lines.push(" ");
|
|
1166
|
-
lines.push(" if (processedActions.includes(actionKey)) {");
|
|
1167
|
-
lines.push(" return { handled: true, displayText: text };");
|
|
1168
|
-
lines.push(" }");
|
|
1169
|
-
lines.push(" ");
|
|
1170
|
-
lines.push(" processedActions.push(actionKey);");
|
|
1171
|
-
lines.push(" localStorage.setItem(PROCESSED_ACTIONS_KEY, JSON.stringify(processedActions));");
|
|
1172
|
-
lines.push(" ");
|
|
1173
|
-
lines.push(" const targetUrl = url.startsWith('http')");
|
|
1174
|
-
lines.push(" ? url");
|
|
1175
|
-
lines.push(" : new URL(url, window.location.origin).toString();");
|
|
1176
|
-
lines.push(" ");
|
|
1177
|
-
lines.push(" window.location.href = targetUrl;");
|
|
1178
|
-
lines.push(" ");
|
|
1179
|
-
lines.push(" return { handled: true, displayText: text };");
|
|
1180
|
-
lines.push(" }");
|
|
1181
|
-
lines.push(" ],");
|
|
1182
|
-
lines.push(" // Send DOM context with each request");
|
|
1183
|
-
lines.push(" requestMiddleware: ({ payload }) => ({");
|
|
1184
|
-
lines.push(" ...payload,");
|
|
1185
|
-
lines.push(" metadata: domContextProvider()");
|
|
1186
|
-
lines.push(" }),");
|
|
1187
|
-
lines.push(" postprocessMessage: ({ text }) => agentWidget.markdownPostprocessor(text)");
|
|
1188
|
-
lines.push(" });");
|
|
1189
|
-
lines.push("");
|
|
1190
|
-
lines.push(" // Initialize widget when DOM is loaded");
|
|
1191
|
-
lines.push(" function init() {");
|
|
1192
|
-
lines.push(" const agentWidget = window.AgentWidget;");
|
|
1193
|
-
lines.push(" if (!agentWidget) {");
|
|
1194
|
-
lines.push(" console.error('AgentWidget not loaded');");
|
|
1195
|
-
lines.push(" return;");
|
|
1196
|
-
lines.push(" }");
|
|
1197
|
-
lines.push("");
|
|
1198
|
-
lines.push(" const widgetConfig = createWidgetConfig(agentWidget);");
|
|
1199
|
-
lines.push("");
|
|
1200
|
-
lines.push(" // Load saved state");
|
|
1201
|
-
lines.push(" const savedState = localStorage.getItem(STORAGE_KEY);");
|
|
1202
|
-
lines.push(" if (savedState) {");
|
|
1203
|
-
lines.push(" try {");
|
|
1204
|
-
lines.push(" const { messages } = JSON.parse(savedState);");
|
|
1205
|
-
lines.push(" widgetConfig.initialMessages = messages || [];");
|
|
1206
|
-
lines.push(" } catch (e) {");
|
|
1207
|
-
lines.push(" console.error('Failed to load saved state:', e);");
|
|
1208
|
-
lines.push(" }");
|
|
1209
|
-
lines.push(" }");
|
|
1210
|
-
lines.push("");
|
|
1211
|
-
lines.push(" // Initialize widget with DOM context");
|
|
1212
|
-
lines.push(" const handle = agentWidget.initAgentWidget({");
|
|
1213
|
-
lines.push(" target: 'body',");
|
|
1214
|
-
lines.push(" useShadowDom: false,");
|
|
1215
|
-
lines.push(" config: widgetConfig");
|
|
1216
|
-
lines.push(" });");
|
|
1217
|
-
lines.push("");
|
|
1218
|
-
lines.push(" // Save state on message events");
|
|
1219
|
-
lines.push(" window.addEventListener('vanilla-agent:message', (event) => {");
|
|
1220
|
-
lines.push(" const session = handle.getSession?.();");
|
|
1221
|
-
lines.push(" if (session) {");
|
|
1222
|
-
lines.push(" localStorage.setItem(STORAGE_KEY, JSON.stringify({");
|
|
1223
|
-
lines.push(" messages: session.messages,");
|
|
1224
|
-
lines.push(" timestamp: new Date().toISOString()");
|
|
1225
|
-
lines.push(" }));");
|
|
1226
|
-
lines.push(" }");
|
|
1227
|
-
lines.push(" });");
|
|
1228
|
-
lines.push("");
|
|
1229
|
-
lines.push(" // Clear state on clear chat");
|
|
1230
|
-
lines.push(" window.addEventListener('vanilla-agent:clear-chat', () => {");
|
|
1231
|
-
lines.push(" localStorage.removeItem(STORAGE_KEY);");
|
|
1232
|
-
lines.push(" localStorage.removeItem(PROCESSED_ACTIONS_KEY);");
|
|
1233
|
-
lines.push(" });");
|
|
1234
|
-
lines.push(" }");
|
|
1235
|
-
lines.push("");
|
|
1236
|
-
lines.push(" // Initialize when DOM is ready");
|
|
1237
|
-
lines.push(" if (document.readyState === 'loading') {");
|
|
1238
|
-
lines.push(" document.addEventListener('DOMContentLoaded', init);");
|
|
1239
|
-
lines.push(" } else {");
|
|
1240
|
-
lines.push(" init();");
|
|
1241
|
-
lines.push(" }");
|
|
1242
|
-
lines.push(" })();");
|
|
1243
|
-
lines.push("</script>");
|
|
1244
|
-
|
|
1245
1345
|
return lines.join("\n");
|
|
1246
1346
|
}
|