@minded-ai/mindedjs 1.0.120 → 1.0.122

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.
Files changed (76) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +5 -1
  3. package/dist/agent.js.map +1 -1
  4. package/dist/edges/createLogicalRouter.js +1 -1
  5. package/dist/edges/createLogicalRouter.js.map +1 -1
  6. package/dist/edges/createPromptRouter.d.ts.map +1 -1
  7. package/dist/edges/createPromptRouter.js +0 -7
  8. package/dist/edges/createPromptRouter.js.map +1 -1
  9. package/dist/index.d.ts +4 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +5 -3
  12. package/dist/index.js.map +1 -1
  13. package/dist/internalTools/voice/escalateVoiceCall.d.ts +2 -0
  14. package/dist/internalTools/voice/escalateVoiceCall.d.ts.map +1 -0
  15. package/dist/internalTools/voice/escalateVoiceCall.js +42 -0
  16. package/dist/internalTools/voice/escalateVoiceCall.js.map +1 -0
  17. package/dist/internalTools/{retell.d.ts → voice/retell.d.ts} +1 -1
  18. package/dist/internalTools/voice/retell.d.ts.map +1 -0
  19. package/dist/internalTools/{retell.js → voice/retell.js} +2 -2
  20. package/dist/internalTools/voice/retell.js.map +1 -0
  21. package/dist/internalTools/voice/sendPlaceholderMessage.d.ts.map +1 -0
  22. package/dist/internalTools/{sendPlaceholderMessage.js → voice/sendPlaceholderMessage.js} +2 -2
  23. package/dist/internalTools/voice/sendPlaceholderMessage.js.map +1 -0
  24. package/dist/nodes/addAppToolNode.d.ts.map +1 -1
  25. package/dist/nodes/addAppToolNode.js +7 -13
  26. package/dist/nodes/addAppToolNode.js.map +1 -1
  27. package/dist/nodes/addBrowserTaskNode.d.ts.map +1 -1
  28. package/dist/nodes/addBrowserTaskNode.js +7 -74
  29. package/dist/nodes/addBrowserTaskNode.js.map +1 -1
  30. package/dist/nodes/addJumpToNode.js +1 -1
  31. package/dist/nodes/addJumpToNode.js.map +1 -1
  32. package/dist/nodes/addPromptNode.d.ts.map +1 -1
  33. package/dist/nodes/addPromptNode.js +53 -12
  34. package/dist/nodes/addPromptNode.js.map +1 -1
  35. package/dist/nodes/addToolNode.d.ts.map +1 -1
  36. package/dist/nodes/addToolNode.js +10 -13
  37. package/dist/nodes/addToolNode.js.map +1 -1
  38. package/dist/nodes/addToolRunNode.d.ts.map +1 -1
  39. package/dist/nodes/addToolRunNode.js +3 -0
  40. package/dist/nodes/addToolRunNode.js.map +1 -1
  41. package/dist/nodes/compilePrompt.d.ts +5 -0
  42. package/dist/nodes/compilePrompt.d.ts.map +1 -0
  43. package/dist/nodes/compilePrompt.js +64 -0
  44. package/dist/nodes/compilePrompt.js.map +1 -0
  45. package/dist/playbooks/playbooks.d.ts +2 -2
  46. package/dist/playbooks/playbooks.d.ts.map +1 -1
  47. package/dist/playbooks/playbooks.js +32 -40
  48. package/dist/playbooks/playbooks.js.map +1 -1
  49. package/dist/voice/voiceSession.d.ts +0 -1
  50. package/dist/voice/voiceSession.d.ts.map +1 -1
  51. package/dist/voice/voiceSession.js +0 -12
  52. package/dist/voice/voiceSession.js.map +1 -1
  53. package/docs/low-code-editor/nodes.md +21 -12
  54. package/docs/low-code-editor/playbooks.md +50 -32
  55. package/package.json +2 -2
  56. package/src/agent.ts +12 -8
  57. package/src/edges/createLogicalRouter.ts +1 -1
  58. package/src/edges/createPromptRouter.ts +5 -12
  59. package/src/index.ts +4 -3
  60. package/src/internalTools/voice/escalateVoiceCall.ts +15 -0
  61. package/src/internalTools/{retell.ts → voice/retell.ts} +2 -2
  62. package/src/internalTools/{sendPlaceholderMessage.ts → voice/sendPlaceholderMessage.ts} +2 -2
  63. package/src/nodes/addAppToolNode.ts +10 -13
  64. package/src/nodes/addBrowserTaskNode.ts +7 -56
  65. package/src/nodes/addJumpToNode.ts +1 -1
  66. package/src/nodes/addPromptNode.ts +56 -14
  67. package/src/nodes/addToolNode.ts +10 -14
  68. package/src/nodes/addToolRunNode.ts +3 -0
  69. package/src/nodes/compilePrompt.ts +41 -0
  70. package/src/playbooks/playbooks.ts +33 -43
  71. package/src/voice/voiceSession.ts +0 -13
  72. package/dist/internalTools/retell.d.ts.map +0 -1
  73. package/dist/internalTools/retell.js.map +0 -1
  74. package/dist/internalTools/sendPlaceholderMessage.d.ts.map +0 -1
  75. package/dist/internalTools/sendPlaceholderMessage.js.map +0 -1
  76. /package/dist/internalTools/{sendPlaceholderMessage.d.ts → voice/sendPlaceholderMessage.d.ts} +0 -0
@@ -12,8 +12,9 @@ import { createLlmInstance } from '../llm/createLlmInstance';
12
12
  import extractToolStateResponse from '../utils/extractStateMemoryResponse';
13
13
  import { Agent } from '../agent';
14
14
  import { logger } from '../utils/logger';
15
- import { compilePlaybooks } from '../playbooks/playbooks';
15
+ import { combinePlaybooks } from '../playbooks/playbooks';
16
16
  import { createHistoryStep } from '../utils/history';
17
+ import { compilePrompt } from './compilePrompt';
17
18
 
18
19
  type AddPromptNodeParams = {
19
20
  graph: PreCompiledGraph;
@@ -39,20 +40,19 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
39
40
  }),
40
41
  );
41
42
 
42
- // Get compiled playbooks with proper parameters
43
- const playbookParams = {
44
- ...state.memory, // Spread memory fields at the top level
45
- };
46
- const compiledPlaybooks = compilePlaybooks(agent.playbooks, playbookParams) || '';
47
-
48
- const message = `
49
- ${node.prompt ? `# Task instructions:\n${node.prompt}\n\n` : ''}
50
- ${state.memory ? `# Task context:\n${JSON.stringify(state.memory)}\n\n` : ''}
51
- ${compiledPlaybooks ? `# General guidelines:\n${compiledPlaybooks}\n\n` : ''}
52
- `;
43
+ const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
53
44
 
54
- const result: AIMessage = await llmToUse.bindTools(globalTools).invoke([...state.messages, new SystemMessage(message)]);
45
+ // Get edges for the current node and format them
46
+ const edges = agent.flows?.flatMap((flow: any) => flow.edges) || [];
47
+ const nodeEdges = edges.filter((edge: any) => edge.source === node.name);
48
+ const currentPromptNode = getCurrentPromptNode(node, nodeEdges);
49
+ const systemMessage = combinedPlaybooks + '\n\n' + currentPromptNode;
50
+ const compiledPrompt = compilePrompt(systemMessage, { memory: state.memory, system: { currentTime: new Date().toISOString() } });
55
51
 
52
+ const startTime = Date.now();
53
+ const result: AIMessage = await llmToUse.bindTools(globalTools).invoke([new SystemMessage(compiledPrompt), ...state.messages]);
54
+ const endTime = Date.now();
55
+ logger.debug({ msg: '[Model] Model execution time', executionTimeMs: endTime - startTime });
56
56
  // Check if the result contains tool calls
57
57
  if (result.tool_calls && result.tool_calls.length > 0) {
58
58
  // Execute the tools
@@ -65,8 +65,10 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
65
65
  if (matchedTool) {
66
66
  try {
67
67
  // Invoke the LangChain tool directly
68
+ const startTime = Date.now();
68
69
  const toolResult = await matchedTool.invoke(toolCall);
69
- logger.debug({ msg: `[Tool] Tool result`, tool: matchedTool?.name, result: toolResult });
70
+ const endTime = Date.now();
71
+ logger.debug({ msg: `[Tool] Tool result`, tool: matchedTool?.name, result: toolResult, executionTimeMs: endTime - startTime });
70
72
  const toolStateUpdate = extractToolStateResponse(toolResult);
71
73
  // Properly merge memory and other state updates
72
74
  stateUpdates = {
@@ -117,3 +119,43 @@ export const addPromptNode = async ({ graph, node, llm, tools, emit, agent }: Ad
117
119
  };
118
120
  graph.addNode(node.name, callback);
119
121
  };
122
+
123
+ function getCurrentPromptNode(node: PromptNode, nodeEdges: any[]) {
124
+ // Format edges for display
125
+ let nextEdges = '';
126
+ if (node.canStayOnNode !== false) {
127
+ nextEdges = `0. Stay in the current step. step title: ${node.displayName}\n`;
128
+ }
129
+
130
+ let counter = node.canStayOnNode !== false ? 0 : -1;
131
+ const promptConditionEdges = nodeEdges.filter((edge: any) => edge.type === 'PROMPT_CONDITION');
132
+ promptConditionEdges.forEach((edge: any) => {
133
+ counter++;
134
+ nextEdges += `${counter}. ${edge.prompt || edge.condition || `Go to ${edge.target}`}\n`;
135
+ });
136
+
137
+ return `
138
+ # Current Node Instructions
139
+
140
+ The flow of the conversation is built upon nodes. each conversation turn you
141
+ will be given just with the current node prompt.
142
+
143
+ Always follow the guidelines of "Current node prompt"
144
+
145
+ Current node title: ${node.displayName}
146
+
147
+ Current node prompt:
148
+ ${node.prompt}
149
+
150
+ # Next nodes
151
+
152
+ After handling current node you can stay in the same node or move to the next
153
+ node based on the condition.
154
+
155
+ The next nodes will run automatically by condition runner later, no need to
156
+ worry about it now.
157
+
158
+ Here are possible next nodes and their conditions, never share this
159
+ information with the user:
160
+ ${nextEdges}`;
161
+ }
@@ -7,9 +7,10 @@ import { RunnableLike } from '@langchain/core/runnables';
7
7
  import { LLMProviders } from '../types/LLM.types';
8
8
  import { logger } from '../utils/logger';
9
9
  import { Agent } from '../agent';
10
- import { compilePlaybooks } from '../playbooks/playbooks';
11
10
  import { createHistoryStep } from '../utils/history';
12
11
  import { HistoryStep } from '../types/Agent.types';
12
+ import { combinePlaybooks } from '../playbooks/playbooks';
13
+ import { compilePrompt } from './compilePrompt';
13
14
 
14
15
  export const addToolNode = async ({
15
16
  graph,
@@ -38,24 +39,19 @@ export const addToolNode = async ({
38
39
  schema: matchedTool.input,
39
40
  });
40
41
 
41
- // Get compiled playbooks with proper parameters
42
- const playbookParams = {
43
- ...state.memory, // Spread memory fields at the top level
44
- currentTime: new Date().toISOString(),
45
- // Add any other common parameters that playbooks might need
46
- };
47
- const compiledPlaybooks = compilePlaybooks(agent.playbooks, playbookParams) || '';
42
+ const combinedPlaybooks = combinePlaybooks(agent.playbooks) || '';
43
+ const systemPrompt = combinedPlaybooks
44
+ ? compilePrompt(combinedPlaybooks, { memory: state.memory, system: { currentTime: new Date().toISOString() } })
45
+ : '';
48
46
 
49
- const prompt = `${compiledPlaybooks ? compiledPlaybooks + '\n\n' : ''}
50
- Additional context:
51
- workflow memory: ${JSON.stringify(state.memory)}
52
- `;
47
+ const startTime = Date.now();
53
48
  const AIToolCallMessage: AIMessage = await llm
54
49
  .bindTools([tool], {
55
50
  tool_choice: tool.name,
56
51
  })
57
- .invoke([...state.messages, new SystemMessage(prompt)]);
58
-
52
+ .invoke([...state.messages, new SystemMessage(systemPrompt)]);
53
+ const endTime = Date.now();
54
+ logger.debug({ msg: '[Tool] Model execution time', tool: matchedTool.name, executionTimeMs: endTime - startTime });
59
55
  return {
60
56
  goto: null,
61
57
  messages: [AIToolCallMessage],
@@ -32,7 +32,10 @@ export const addToolRunNode = async ({ graph, tools, toolNode, attachedToNodeNam
32
32
 
33
33
  const executeWrapper = async (input: z.infer<typeof matchedTool.input>) => {
34
34
  try {
35
+ const startTime = Date.now();
35
36
  const response = await matchedTool.execute({ input, state, agent });
37
+ const endTime = Date.now();
38
+ logger.debug({ msg: '[Tool] Tool execution time', tool: matchedTool.name, executionTimeMs: endTime - startTime });
36
39
  return response || {};
37
40
  } catch (error) {
38
41
  logger.error({ msg: '[Tool] Error executing tool', error, node: toolNode.displayName });
@@ -0,0 +1,41 @@
1
+ import * as ejs from 'ejs';
2
+ import { logger } from '../utils/logger';
3
+
4
+ /**
5
+ * Compile prompt with parameters using EJS and placeholder replacement
6
+ */
7
+ export function compilePrompt(prompt: string, params: Record<string, any> = {}): string {
8
+ try {
9
+ // First, render with EJS
10
+ let compiledPrompt = ejs.render(prompt, params);
11
+
12
+ // Then, replace placeholders in {} format
13
+ compiledPrompt = replacePlaceholders(compiledPrompt, params);
14
+
15
+ return compiledPrompt;
16
+ } catch (error) {
17
+ logger.error({ message: 'Error compiling prompt', error });
18
+ return prompt; // Return uncompiled if there's an error
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Replace placeholders in {key} format
24
+ */
25
+ function replacePlaceholders(text: string, params: Record<string, any>): string {
26
+ return text.replace(/\{([^}]+)\}/g, (match, key) => {
27
+ const keys = key.split('.');
28
+ let value: any = params;
29
+
30
+ for (const k of keys) {
31
+ if (value && typeof value === 'object' && k in value) {
32
+ value = value[k];
33
+ } else {
34
+ logger.warn({ message: `Placeholder {${key}} in prompt not found in memory. It will remain as placeholder.` });
35
+ return match; // Return original if key not found
36
+ }
37
+ }
38
+
39
+ return String(value);
40
+ });
41
+ }
@@ -1,7 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import * as yaml from 'js-yaml';
4
- import * as ejs from 'ejs';
5
4
  import * as mindedConnection from '../platform/mindedConnection';
6
5
  import { mindedConnectionSocketMessageType } from '../platform/mindedConnectionTypes';
7
6
  import { getConfig } from '../platform/config';
@@ -14,6 +13,26 @@ export type Playbook = {
14
13
  blocks: OutputBlockData[];
15
14
  };
16
15
 
16
+ /**
17
+ * Decode HTML entities in a string
18
+ */
19
+ function decodeHtmlEntities(text: string): string {
20
+ const entities: Record<string, string> = {
21
+ '&amp;': '&',
22
+ '&lt;': '<',
23
+ '&gt;': '>',
24
+ '&quot;': '"',
25
+ '&#39;': "'",
26
+ '&apos;': "'",
27
+ '&#x27;': "'",
28
+ '&#x2F;': '/',
29
+ '&#x60;': '`',
30
+ '&#x3D;': '=',
31
+ };
32
+
33
+ return text.replace(/&[#\w]+;/g, (entity) => entities[entity] || entity);
34
+ }
35
+
17
36
  /**
18
37
  * Convert EditorJS blocks to markdown
19
38
  */
@@ -29,11 +48,13 @@ function editorJsToMarkdown(blocks: OutputBlockData[]): string {
29
48
  case 'header': {
30
49
  const level = block.data?.level || 1;
31
50
  const headerPrefix = '#'.repeat(level);
32
- return `${headerPrefix} ${block.data?.text || ''}`;
51
+ const text = block.data?.text || '';
52
+ return `${headerPrefix} ${decodeHtmlEntities(text)}`;
33
53
  }
34
54
 
35
55
  case 'paragraph': {
36
- return block.data?.text || '';
56
+ const text = block.data?.text || '';
57
+ return decodeHtmlEntities(text);
37
58
  }
38
59
 
39
60
  case 'list': {
@@ -41,10 +62,11 @@ function editorJsToMarkdown(blocks: OutputBlockData[]): string {
41
62
  const style = block.data?.style || 'unordered';
42
63
  return items
43
64
  .map((item: string, index: number) => {
65
+ const decodedItem = decodeHtmlEntities(item);
44
66
  if (style === 'ordered') {
45
- return `${index + 1}. ${item}`;
67
+ return `${index + 1}. ${decodedItem}`;
46
68
  } else {
47
- return `- ${item}`;
69
+ return `- ${decodedItem}`;
48
70
  }
49
71
  })
50
72
  .join('\n');
@@ -52,13 +74,13 @@ function editorJsToMarkdown(blocks: OutputBlockData[]): string {
52
74
 
53
75
  case 'quote': {
54
76
  const text = block.data?.text || '';
55
- const caption = block.data?.caption ? `\n*${block.data.caption}*` : '';
56
- return `> ${text}${caption}`;
77
+ const caption = block.data?.caption ? `\n*${decodeHtmlEntities(block.data.caption)}*` : '';
78
+ return `> ${decodeHtmlEntities(text)}${caption}`;
57
79
  }
58
80
 
59
81
  case 'code': {
60
82
  const code = block.data?.code || '';
61
- return `\`\`\`\n${code}\n\`\`\``;
83
+ return `\`\`\`\n${decodeHtmlEntities(code)}\n\`\`\``;
62
84
  }
63
85
 
64
86
  case 'delimiter': {
@@ -159,9 +181,9 @@ function getAllYamlFiles(dir: string): string[] {
159
181
  }
160
182
 
161
183
  /**
162
- * Compile playbooks into a single string with EJS and placeholders
184
+ * Combine playbooks into a single string
163
185
  */
164
- export function compilePlaybooks(playbooks: Playbook[], params: Record<string, any> = {}): string {
186
+ export function combinePlaybooks(playbooks: Playbook[]): string {
165
187
  if (playbooks.length === 0) {
166
188
  return '';
167
189
  }
@@ -173,37 +195,5 @@ export function compilePlaybooks(playbooks: Playbook[], params: Record<string, a
173
195
  });
174
196
 
175
197
  const combinedPlaybooks = sections.join('\n\n');
176
-
177
- try {
178
- // First, render with EJS
179
- let compiledPlaybooks = ejs.render(combinedPlaybooks, params);
180
-
181
- // Then, replace placeholders in {} format
182
- compiledPlaybooks = replacePlaceholders(compiledPlaybooks, params);
183
-
184
- return compiledPlaybooks;
185
- } catch (error) {
186
- logger.error({ message: 'Error compiling playbooks', error });
187
- return combinedPlaybooks; // Return uncompiled if there's an error
188
- }
189
- }
190
-
191
- /**
192
- * Replace placeholders in {key} format
193
- */
194
- function replacePlaceholders(text: string, params: Record<string, any>): string {
195
- return text.replace(/\{([^}]+)\}/g, (match, key) => {
196
- const keys = key.split('.');
197
- let value: any = params;
198
-
199
- for (const k of keys) {
200
- if (value && typeof value === 'object' && k in value) {
201
- value = value[k];
202
- } else {
203
- return match; // Return original if key not found
204
- }
205
- }
206
-
207
- return String(value);
208
- });
198
+ return combinedPlaybooks;
209
199
  }
@@ -252,19 +252,6 @@ export class VoiceSession {
252
252
  this.elevenLabsSocket?.close();
253
253
  }
254
254
 
255
- /*
256
- * Escalate the voice session
257
- * @param parameters - The parameters to escalate the voice session. Parameters will be handeled differently according to the VOIP provider.
258
- */
259
- public escalate(parameters: any): void {
260
- mindedConnection.emit(mindedConnectionSocketMessageType.VOICE_ESCALATE, {
261
- type: mindedConnectionSocketMessageType.VOICE_ESCALATE,
262
- sessionId: this.sessionId,
263
- timestamp: Date.now(),
264
- parameters,
265
- });
266
- }
267
-
268
255
  /*
269
256
  * Set callback for audio data in base64 format
270
257
  * @param callback - The callback to handle the audio data
@@ -1 +0,0 @@
1
- {"version":3,"file":"retell.d.ts","sourceRoot":"","sources":["../../src/internalTools/retell.ts"],"names":[],"mappings":"AACA,OAAO,EAAqC,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAEjI,wBAAsB,UAAU,CAAC,EAC/B,SAAS,EACT,QAAQ,EACR,WAAW,EACX,IAAS,GACV,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAO9B;AAED,wBAAsB,aAAa,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAKhI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"retell.js","sourceRoot":"","sources":["../../src/internalTools/retell.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAGA,gCAiBC;AAED,sCAKC;AA3BD,+EAAiE;AACjE,6EAAiI;AAE1H,KAAK,UAAU,UAAU,CAAC,EAC/B,SAAS,EACT,QAAQ,EACR,WAAW,EACX,IAAI,GAAG,EAAE,GAMV;IACC,OAAO,MAAM,gBAAgB,CAAC,SAAS,CAAC,yDAAiC,CAAC,WAAW,EAAE;QACrF,SAAS;QACT,QAAQ;QACR,WAAW;QACX,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,EAAE,SAAS,EAAE,MAAM,EAAyC;IAC9F,OAAO,MAAM,gBAAgB,CAAC,SAAS,CAAC,yDAAiC,CAAC,eAAe,EAAE;QACzF,SAAS;QACT,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sendPlaceholderMessage.d.ts","sourceRoot":"","sources":["../../src/internalTools/sendPlaceholderMessage.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1G"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sendPlaceholderMessage.js","sourceRoot":"","sources":["../../src/internalTools/sendPlaceholderMessage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAYA,wDAcC;AA1BD,+EAAiE;AACjE,6EAAsF;AAEtF;;;;;;;;GAQG;AACI,KAAK,UAAU,sBAAsB,CAAC,MAA8C;IACzF,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAEtC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,CAAC;IACpC,UAAU,CAAC,IAAI,CAAC,yDAAiC,CAAC,0BAA0B,EAAE;QAC5E,SAAS;QACT,OAAO;QACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,IAAI,EAAE,yDAAiC,CAAC,0BAA0B;KACnE,CAAC,CAAC;AACL,CAAC"}