genaicode 0.10.1 → 0.10.3

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 (58) hide show
  1. package/dist/ai-service/ai-studio.js +95 -82
  2. package/dist/ai-service/ai-studio.js.map +1 -1
  3. package/dist/ai-service/anthropic.js +10 -5
  4. package/dist/ai-service/anthropic.js.map +1 -1
  5. package/dist/ai-service/common-types.d.ts +2 -0
  6. package/dist/ai-service/common.js +3 -0
  7. package/dist/ai-service/common.js.map +1 -1
  8. package/dist/ai-service/openai.js +1 -1
  9. package/dist/ai-service/openai.js.map +1 -1
  10. package/dist/ai-service/vertex-ai-claude.js +7 -5
  11. package/dist/ai-service/vertex-ai-claude.js.map +1 -1
  12. package/dist/ai-service/vertex-ai.js +13 -6
  13. package/dist/ai-service/vertex-ai.js.map +1 -1
  14. package/dist/main/common/user-actions.d.ts +1 -1
  15. package/dist/main/ui/common/api-types.d.ts +25 -0
  16. package/dist/main/ui/frontend/assets/index-oL0QT7JQ.js +2015 -0
  17. package/dist/main/ui/frontend/index.html +1 -1
  18. package/dist/prompt/function-calling-validate.d.ts +2 -1
  19. package/dist/prompt/function-calling-validate.js +2 -2
  20. package/dist/prompt/function-calling-validate.js.map +1 -1
  21. package/dist/prompt/function-calling.js +2 -0
  22. package/dist/prompt/function-calling.js.map +1 -1
  23. package/dist/prompt/function-defs/ask-question.js +3 -1
  24. package/dist/prompt/function-defs/ask-question.js.map +1 -1
  25. package/dist/prompt/function-defs/compound-action-list.d.ts +7 -0
  26. package/dist/prompt/function-defs/compound-action-list.js +38 -0
  27. package/dist/prompt/function-defs/compound-action-list.js.map +1 -0
  28. package/dist/prompt/function-defs/compound-action.d.ts +2 -0
  29. package/dist/prompt/function-defs/compound-action.js +43 -0
  30. package/dist/prompt/function-defs/compound-action.js.map +1 -0
  31. package/dist/prompt/function-defs/conversation-graph.d.ts +6 -6
  32. package/dist/prompt/limits.js +1 -1
  33. package/dist/prompt/steps/step-ask-question/handlers/handle-compound-action.d.ts +20 -0
  34. package/dist/prompt/steps/step-ask-question/handlers/handle-compound-action.js +253 -0
  35. package/dist/prompt/steps/step-ask-question/handlers/handle-compound-action.js.map +1 -0
  36. package/dist/prompt/steps/step-ask-question/handlers/handle-conversation-graph.d.ts +6 -7
  37. package/dist/prompt/steps/step-ask-question/handlers/handle-conversation-graph.js +406 -178
  38. package/dist/prompt/steps/step-ask-question/handlers/handle-conversation-graph.js.map +1 -1
  39. package/dist/prompt/steps/step-ask-question/handlers/handle-explore-external-directories.js +4 -1
  40. package/dist/prompt/steps/step-ask-question/handlers/handle-explore-external-directories.js.map +1 -1
  41. package/dist/prompt/steps/step-ask-question/handlers/handle-read-external-files.js +5 -0
  42. package/dist/prompt/steps/step-ask-question/handlers/handle-read-external-files.js.map +1 -1
  43. package/dist/prompt/steps/step-ask-question/handlers/handle-request-git-context.js +2 -0
  44. package/dist/prompt/steps/step-ask-question/handlers/handle-request-git-context.js.map +1 -1
  45. package/dist/prompt/steps/step-ask-question/handlers/handle-update-file.js +8 -12
  46. package/dist/prompt/steps/step-ask-question/handlers/handle-update-file.js.map +1 -1
  47. package/dist/prompt/steps/step-ask-question/step-ask-question-handlers.js +1 -4
  48. package/dist/prompt/steps/step-ask-question/step-ask-question-handlers.js.map +1 -1
  49. package/dist/prompt/steps/step-ask-question/step-ask-question-types.d.ts +19 -1
  50. package/dist/prompt/steps/step-ask-question/step-ask-question.d.ts +2 -0
  51. package/dist/prompt/steps/step-ask-question/step-ask-question.js +2 -0
  52. package/dist/prompt/steps/step-ask-question/step-ask-question.js.map +1 -1
  53. package/dist/prompt/steps/step-validate-recover.js +3 -3
  54. package/dist/prompt/steps/step-validate-recover.js.map +1 -1
  55. package/dist/prompt/systemprompt.js +2 -0
  56. package/dist/prompt/systemprompt.js.map +1 -1
  57. package/package.json +5 -5
  58. package/dist/main/ui/frontend/assets/index-C7n3IQsE.js +0 -1896
@@ -30,13 +30,20 @@ A conversation graph is a flexible structure for managing complex interactions.
30
30
  - **Flow Control**: Edges determine how the conversation can progress
31
31
  - **Flexibility**: Support for various conversation patterns and flows
32
32
  - **Context Awareness**: Each node operates with awareness of the conversation state
33
+ - **User Interaction**: User can reject or accept some of the actions, so the graph should account for that
33
34
 
34
35
  ## Implementation Notes
35
36
 
36
37
  - Nodes should be self-contained and focused
37
38
  - Edges should have clear, evaluatable conditions
38
39
  - Any node can connect to any other node if logically appropriate
39
- - Nodes and edges must formulate a direct acyclic graph (DAG)
40
+ - Nodes and edges must formulate a graph structure, allowing for complex interactions
41
+
42
+ ## Graph Structure requirements and constraints
43
+
44
+ - The graph may contain cycles, but should be designed to avoid infinite loops
45
+ - Each node should be reachable from the entry node
46
+ - The entry node should be clearly defined and serve as the starting point for the conversation
40
47
 
41
48
  ## Technical Details
42
49
 
@@ -61,215 +68,436 @@ export const getEdgeEvaluationPrompt = (currentNode, outgoingEdges) => {
61
68
  return `We are evaluating the outgoing edges from the current node(${currentNode.id}):
62
69
 
63
70
  ${outgoingEdges.map((edge) => `- ${edge.targetNode}: ${edge.instruction}`).join('\n')}
64
-
65
- Select the correct edge, or terminate if the conversation should stop.`;
71
+
72
+ Select the correct edge, or terminate if the conversation should stop. Use the 'evaluateEdge' function.`;
66
73
  };
74
+ export const GRAPH_ANALYSIS_PROMPT_TEXT = `Please analyze the conversation graph provided by the assistant in the preceding message. Simulate diverse conversation paths mentally and identify any structural or logical problems, dead ends, unreachable nodes, missing transitions, or potential infinite loops. Explain the problems you find in detail. If no significant problems are found, state that clearly.`;
75
+ export const GRAPH_REVISION_PROMPT_TEXT = `Based on the analysis provided in the preceding message, generate a new, improved conversation graph using the 'conversationGraph' function. Ensure the new graph addresses the identified problems and better facilitates the original conversation goal.`;
67
76
  registerActionHandler('conversationGraph', handleConversationGraph);
68
77
  /**
69
- * Handles the conversationGraph action by:
70
- * 1. Generating a conversationGraph function call
71
- * 2. Extracting nodes and edges from the response
72
- * 3. Traversing the graph and executing actions
73
- * 4. Returning appropriate ActionResult
78
+ * Main handler for the conversationGraph action.
79
+ * Orchestrates confirmation, generation, analysis/revision, and traversal.
74
80
  */
75
- export async function handleConversationGraph({ askQuestionCall, prompt, options, generateContentFn, generateImageFn, waitIfPaused, }) {
81
+ export async function handleConversationGraph(props) {
82
+ const state = {
83
+ prompt: [...props.prompt], // Work on a copy
84
+ currentGraphState: null,
85
+ conversationGraphCall: null,
86
+ };
76
87
  try {
77
- const userConfirmation = await askUserForConfirmationWithAnswer('The assistant wants to perform a conversation graph. Do you want to proceed?', 'Run conversation graph', 'Decline', true, options);
78
- if (userConfirmation.answer) {
79
- putUserMessage(userConfirmation.answer);
80
- }
88
+ // 1. Confirm Execution
89
+ const userConfirmation = await _confirmGraphExecution(props.askQuestionCall, state, props.options);
81
90
  if (!userConfirmation.confirmed) {
82
- putSystemMessage('Conversation graph declined.');
83
- prompt.push({
84
- type: 'assistant',
85
- text: askQuestionCall.args?.message ?? '',
86
- }, {
87
- type: 'user',
88
- text: 'Declined conversation graph. ' + (userConfirmation.answer ? `\n\n${userConfirmation.answer}` : ''),
89
- });
90
- return {
91
- breakLoop: false,
92
- items: [],
93
- };
91
+ props.prompt.push(...state.prompt.slice(props.prompt.length)); // Update original prompt if declined
92
+ return { breakLoop: false, items: [] };
94
93
  }
95
- putSystemMessage('Generating conversation graph...');
96
- // Generate the conversationGraph function call
97
- const [conversationGraphCall] = (await generateContentFn([
98
- ...prompt,
99
- {
100
- type: 'assistant',
101
- text: askQuestionCall.args?.message ?? '',
102
- },
94
+ // 2. Generate Initial Graph
95
+ const initialGraphCall = await _generateInitialGraph(props.askQuestionCall, state, props.generateContentFn, props.options);
96
+ if (!initialGraphCall) {
97
+ props.prompt.push(...state.prompt.slice(props.prompt.length)); // Update original prompt on failure
98
+ return { breakLoop: false, items: [] };
99
+ }
100
+ // 3. Analyze and Revise Graph
101
+ const finalGraphCall = await _analyzeAndReviseGraph(state, props.generateContentFn, props.options);
102
+ if (!finalGraphCall) {
103
+ // This case implies the initial generation failed, handled in _generateInitialGraph
104
+ // If analysis/revision failed, we still proceed with the initial graph (returned by _analyzeAndReviseGraph)
105
+ // So, if finalGraphCall is null here, something went very wrong earlier.
106
+ throw new Error('Unexpected state: finalGraphCall is null after analysis/revision.');
107
+ }
108
+ state.conversationGraphCall = finalGraphCall; // Ensure state uses the final graph
109
+ // 4. Traverse Graph
110
+ const traversalResult = await _traverseGraph(state, props, userConfirmation);
111
+ // Update the original prompt with the full history from the graph execution
112
+ props.prompt.splice(0, props.prompt.length, ...state.prompt);
113
+ return traversalResult;
114
+ }
115
+ catch (error) {
116
+ // Ensure final state is marked inactive on error
117
+ if (state.currentGraphState) {
118
+ state.currentGraphState = { ...state.currentGraphState, isActive: false };
119
+ }
120
+ putSystemMessage('Error during conversation graph execution', {
121
+ error,
122
+ conversationGraphState: state.currentGraphState,
123
+ });
124
+ // Add error context to the prompt
125
+ state.prompt.push({
126
+ type: 'assistant',
127
+ text: 'An error occurred during conversation graph execution.',
128
+ }, {
129
+ type: 'user',
130
+ text: 'Lets continue the conversation.',
131
+ });
132
+ // Update the original prompt with the history including the error
133
+ props.prompt.splice(0, props.prompt.length, ...state.prompt);
134
+ return { breakLoop: false, items: [] };
135
+ }
136
+ }
137
+ // Helper: Confirm Graph Execution with User
138
+ async function _confirmGraphExecution(askQuestionCall, state, options) {
139
+ const userConfirmation = await askUserForConfirmationWithAnswer('The assistant wants to perform a conversation graph. Do you want to proceed?', 'Run conversation graph', 'Decline', true, options);
140
+ if (userConfirmation.answer) {
141
+ putUserMessage(userConfirmation.answer);
142
+ }
143
+ if (!userConfirmation.confirmed) {
144
+ putSystemMessage('Conversation graph declined.');
145
+ state.prompt.push({
146
+ type: 'assistant',
147
+ text: askQuestionCall.args?.message ?? '',
148
+ }, {
149
+ type: 'user',
150
+ text: 'Declined conversation graph. ' + (userConfirmation.answer ? `\n\n${userConfirmation.answer}` : ''),
151
+ });
152
+ }
153
+ return userConfirmation;
154
+ }
155
+ // Helper: Generate Initial Conversation Graph
156
+ async function _generateInitialGraph(askQuestionCall, state, generateContentFn, options) {
157
+ putSystemMessage('Generating conversation graph...');
158
+ const initialGraphResponse = await generateContentFn([
159
+ ...state.prompt,
160
+ {
161
+ type: 'assistant',
162
+ text: askQuestionCall.args?.message ?? '',
163
+ },
164
+ {
165
+ type: 'user',
166
+ text: CONVERSATION_GRAPH_PROMPT,
167
+ },
168
+ ], {
169
+ functionDefs: getFunctionDefs(),
170
+ requiredFunctionName: 'conversationGraph',
171
+ temperature: 0.7,
172
+ modelType: ModelType.DEFAULT,
173
+ expectedResponseType: {
174
+ text: false,
175
+ functionCall: true,
176
+ media: false,
177
+ },
178
+ }, options);
179
+ const conversationGraphCall = initialGraphResponse
180
+ .filter((item) => item.type === 'functionCall')
181
+ .map((item) => item.functionCall)[0];
182
+ if (!conversationGraphCall || !conversationGraphCall.args) {
183
+ putSystemMessage('Failed to generate initial conversation graph.');
184
+ state.prompt.push({
185
+ type: 'assistant',
186
+ text: 'I encountered an issue generating the conversation plan.',
187
+ }, {
188
+ type: 'user',
189
+ text: 'Okay, unable to generate graph.',
190
+ });
191
+ return null;
192
+ }
193
+ state.prompt.push({
194
+ type: 'assistant',
195
+ text: askQuestionCall.args?.message ?? '',
196
+ functionCalls: [conversationGraphCall],
197
+ });
198
+ state.conversationGraphCall = conversationGraphCall;
199
+ state.currentGraphState = {
200
+ nodes: conversationGraphCall.args.nodes,
201
+ edges: conversationGraphCall.args.edges,
202
+ currentNodeId: null,
203
+ isActive: false,
204
+ };
205
+ return conversationGraphCall;
206
+ }
207
+ // Helper: Analyze and Revise Graph
208
+ async function _analyzeAndReviseGraph(state, generateContentFn, options) {
209
+ if (!state.conversationGraphCall || !state.currentGraphState) {
210
+ return null; // Should not happen if called correctly
211
+ }
212
+ const initialGraphCall = state.conversationGraphCall;
213
+ putSystemMessage('Starting automatic graph analysis...', {
214
+ conversationGraphState: state.currentGraphState,
215
+ ...initialGraphCall.args,
216
+ });
217
+ const analysisPrompt = [
218
+ {
219
+ type: 'assistant',
220
+ text: CONVERSATION_GRAPH_PROMPT,
221
+ },
222
+ {
223
+ type: 'assistant',
224
+ text: 'I have prepared a conversation graph for you.',
225
+ functionCalls: [initialGraphCall],
226
+ },
227
+ {
228
+ type: 'user',
229
+ text: GRAPH_ANALYSIS_PROMPT_TEXT,
230
+ functionResponses: [
231
+ {
232
+ name: 'conversationGraph',
233
+ call_id: initialGraphCall.id,
234
+ content: '',
235
+ },
236
+ ],
237
+ },
238
+ ];
239
+ const analysisResult = await generateContentFn(analysisPrompt, {
240
+ modelType: ModelType.CHEAP,
241
+ temperature: 0.5,
242
+ expectedResponseType: { text: true, functionCall: false, media: false },
243
+ }, options);
244
+ const analysisText = analysisResult.find((part) => part.type === 'text')?.text;
245
+ if (analysisText) {
246
+ analysisPrompt.push({ type: 'assistant', text: analysisText });
247
+ putSystemMessage('Attempting to fix graph based on analysis...', {
248
+ conversationGraphState: state.currentGraphState,
249
+ analysisText,
250
+ });
251
+ const revisionPrompt = [
252
+ ...analysisPrompt,
103
253
  {
104
254
  type: 'user',
105
- text: CONVERSATION_GRAPH_PROMPT + (userConfirmation.answer ? `\n\n${userConfirmation.answer}` : ''),
255
+ text: GRAPH_REVISION_PROMPT_TEXT,
106
256
  },
107
- ], {
257
+ ];
258
+ const revisionResult = await generateContentFn(revisionPrompt, {
259
+ modelType: ModelType.DEFAULT,
260
+ temperature: 0.7,
108
261
  functionDefs: getFunctionDefs(),
109
262
  requiredFunctionName: 'conversationGraph',
110
- temperature: 0.7,
111
- modelType: ModelType.DEFAULT,
112
263
  expectedResponseType: {
113
264
  text: false,
114
265
  functionCall: true,
115
266
  media: false,
116
267
  },
117
- }, options))
268
+ }, options);
269
+ const revisedGraphCall = revisionResult
118
270
  .filter((item) => item.type === 'functionCall')
119
- .map((item) => item.functionCall);
120
- prompt.push({
121
- type: 'assistant',
122
- text: askQuestionCall.args?.message ?? '',
123
- functionCalls: [conversationGraphCall],
124
- }, {
271
+ .map((item) => item.functionCall)[0];
272
+ if (revisedGraphCall?.args?.nodes?.length) {
273
+ state.conversationGraphCall = {
274
+ ...initialGraphCall,
275
+ args: { ...initialGraphCall.args, ...revisedGraphCall.args },
276
+ };
277
+ state.currentGraphState = {
278
+ ...state.currentGraphState,
279
+ nodes: state.conversationGraphCall.args.nodes,
280
+ edges: state.conversationGraphCall.args.edges,
281
+ };
282
+ putSystemMessage('Graph revised successfully.', {
283
+ conversationGraphState: state.currentGraphState,
284
+ ...state.conversationGraphCall.args,
285
+ });
286
+ return state.conversationGraphCall;
287
+ }
288
+ else {
289
+ putSystemMessage('Failed to generate revised conversation graph, keeping original.', {
290
+ conversationGraphState: state.currentGraphState,
291
+ });
292
+ }
293
+ }
294
+ else {
295
+ putSystemMessage('LLM failed to provide analysis text. Proceeding with original graph.', {
296
+ conversationGraphState: state.currentGraphState,
297
+ });
298
+ }
299
+ return initialGraphCall; // Return original if revision failed or wasn't needed
300
+ }
301
+ // Helper: Execute Node Action
302
+ async function _executeNodeAction(currentNode, state, props) {
303
+ const nodeAskQuestionCall = {
304
+ name: 'askQuestion',
305
+ args: {
306
+ message: currentNode.instruction, // Use node instruction as message hint
307
+ actionType: currentNode.actionType,
308
+ },
309
+ };
310
+ putSystemMessage(`Executing node ${currentNode.id} (Action: ${currentNode.actionType})`, {
311
+ conversationGraphState: state.currentGraphState,
312
+ nodeDetails: currentNode,
313
+ });
314
+ // Generate a message for the assistant to say before executing the action
315
+ const [sendMessage] = (await props.generateContentFn(state.prompt, {
316
+ functionDefs: getFunctionDefs(),
317
+ requiredFunctionName: 'sendMessage',
318
+ temperature: 0.7,
319
+ modelType: ModelType.CHEAP,
320
+ expectedResponseType: {
321
+ text: false,
322
+ functionCall: true,
323
+ media: false,
324
+ },
325
+ }, props.options))
326
+ .filter((item) => item.type === 'functionCall')
327
+ .map((item) => item.functionCall);
328
+ if (sendMessage?.args?.message) {
329
+ putAssistantMessage(sendMessage.args.message, sendMessage.args);
330
+ nodeAskQuestionCall.args.message = sendMessage.args.message;
331
+ }
332
+ const currentNodeHandler = getActionHandler(currentNode.actionType);
333
+ const nodeResult = await currentNodeHandler({
334
+ ...props,
335
+ askQuestionCall: nodeAskQuestionCall,
336
+ prompt: state.prompt, // Pass the current prompt state
337
+ });
338
+ // Add results from the node handler to history
339
+ if (nodeResult.items && nodeResult.items.length > 0) {
340
+ for (const item of nodeResult.items) {
341
+ if (item?.assistant) {
342
+ state.prompt.push(item.assistant);
343
+ }
344
+ if (item?.user) {
345
+ putUserMessage(item.user.text ?? '', item.user.data, undefined, item.user.images, item.user);
346
+ state.prompt.push(item.user);
347
+ }
348
+ }
349
+ }
350
+ return nodeResult;
351
+ }
352
+ // Helper: Evaluate Next Step (Edges)
353
+ async function _evaluateNextStep(currentNode, state, generateContentFn, options) {
354
+ const outgoingEdges = state.currentGraphState.edges.filter((edge) => edge.sourceNode === currentNode.id);
355
+ if (outgoingEdges.length === 0) {
356
+ putSystemMessage(`No outgoing edges found from node ${currentNode.id}. Ending execution.`, {
357
+ conversationGraphState: { ...state.currentGraphState, isActive: false },
358
+ });
359
+ return { nextNode: null, terminate: true };
360
+ }
361
+ const edgeEvaluationResult = await generateContentFn([
362
+ ...state.prompt,
363
+ {
125
364
  type: 'user',
365
+ text: getEdgeEvaluationPrompt(currentNode, outgoingEdges),
366
+ },
367
+ ], {
368
+ functionDefs: getFunctionDefs(),
369
+ requiredFunctionName: 'evaluateEdge',
370
+ temperature: 0.2,
371
+ modelType: ModelType.CHEAP,
372
+ expectedResponseType: {
373
+ text: false,
374
+ functionCall: true,
375
+ media: false,
376
+ },
377
+ }, options);
378
+ const evaluateEdge = edgeEvaluationResult
379
+ .filter((item) => item.type === 'functionCall')
380
+ .map((item) => item.functionCall)[0];
381
+ if (!evaluateEdge?.args) {
382
+ putSystemMessage(`Failed to evaluate edges from node ${currentNode.id}. Ending execution.`, {
383
+ conversationGraphState: { ...state.currentGraphState, isActive: false },
384
+ });
385
+ return { nextNode: null, terminate: true };
386
+ }
387
+ state.prompt.push({ type: 'assistant', functionCalls: [evaluateEdge] });
388
+ state.prompt.push({
389
+ type: 'user',
390
+ functionResponses: [
391
+ {
392
+ name: 'evaluateEdge',
393
+ call_id: evaluateEdge.id,
394
+ content: JSON.stringify(evaluateEdge.args),
395
+ },
396
+ ],
397
+ text: `Edge evaluated: ${evaluateEdge.args.shouldTerminate ? 'Terminate' : (evaluateEdge.args.selectedEdge?.targetNode ?? 'Error')}`,
398
+ });
399
+ if (evaluateEdge.args.shouldTerminate || !evaluateEdge.args.selectedEdge) {
400
+ putSystemMessage('Conversation graph traversal terminated by edge evaluation.', {
401
+ conversationGraphState: { ...state.currentGraphState, isActive: false },
402
+ });
403
+ return { nextNode: null, terminate: true };
404
+ }
405
+ const nextNodeId = evaluateEdge.args.selectedEdge.targetNode;
406
+ const nextNode = state.currentGraphState.nodes.find((node) => node.id === nextNodeId);
407
+ if (!nextNode) {
408
+ putSystemMessage(`Target node ${nextNodeId} not found. Ending execution.`, {
409
+ conversationGraphState: { ...state.currentGraphState, isActive: false, currentNodeId: null },
410
+ });
411
+ return { nextNode: null, terminate: true };
412
+ }
413
+ return { nextNode, terminate: false };
414
+ }
415
+ // Helper: Traverse the Graph
416
+ async function _traverseGraph(state, props, userConfirmation) {
417
+ if (!state.conversationGraphCall?.args || !state.currentGraphState) {
418
+ throw new Error('Cannot traverse graph without a valid graph definition.');
419
+ }
420
+ const { entryNode, nodes } = state.conversationGraphCall.args;
421
+ let currentNode = nodes.find((node) => node.id === entryNode);
422
+ if (!currentNode) {
423
+ state.currentGraphState = { ...state.currentGraphState, isActive: false, currentNodeId: null };
424
+ putSystemMessage('Error occurred during conversation graph execution (entry node not found).', {
425
+ conversationGraphState: state.currentGraphState,
426
+ });
427
+ state.prompt.push({
428
+ type: 'user',
429
+ text: 'Okay, unable to start graph execution (entry node not found).',
126
430
  functionResponses: [
127
431
  {
128
432
  name: 'conversationGraph',
129
- call_id: conversationGraphCall.id,
433
+ call_id: state.conversationGraphCall.id,
130
434
  content: '',
131
435
  },
132
436
  ],
133
437
  });
134
- const { entryNode, nodes, edges } = conversationGraphCall.args;
135
- putSystemMessage('Starting conversation graph traversal.', {
136
- entryNode,
137
- nodes,
138
- edges,
139
- });
140
- // Start with the first node
141
- let currentNode = nodes.find((node) => node.id === entryNode);
142
- if (!currentNode) {
143
- putSystemMessage('Error occurred during conversation graph execution.');
144
- prompt.push({
145
- type: 'assistant',
146
- text: askQuestionCall.args?.message ?? '',
147
- }, {
148
- type: 'user',
149
- text: 'Error occurred during conversation graph execution.',
438
+ return { breakLoop: false, items: [] };
439
+ }
440
+ state.currentGraphState = { ...state.currentGraphState, currentNodeId: currentNode.id, isActive: true };
441
+ putSystemMessage('Starting conversation graph traversal.', {
442
+ conversationGraphState: state.currentGraphState,
443
+ entryNode,
444
+ nodes,
445
+ edges: state.currentGraphState.edges,
446
+ });
447
+ // Add prompt to history about user accepting the graph
448
+ state.prompt.push({
449
+ type: 'user',
450
+ text: 'I accept the conversation graph and will proceed with it.' +
451
+ (userConfirmation.answer ? `\n\n${userConfirmation.answer}` : ''), // Assuming confirmation happened before
452
+ functionResponses: [
453
+ {
454
+ name: 'conversationGraph',
455
+ call_id: state.conversationGraphCall.id,
456
+ content: '',
457
+ },
458
+ ],
459
+ });
460
+ const visitedNodes = new Set();
461
+ let iteration = 0;
462
+ const MAX_ITERATIONS = 50;
463
+ while (currentNode && iteration < MAX_ITERATIONS) {
464
+ iteration++;
465
+ visitedNodes.add(currentNode.id);
466
+ state.currentGraphState = { ...state.currentGraphState, currentNodeId: currentNode.id, isActive: true };
467
+ const nodeResult = await _executeNodeAction(currentNode, state, props);
468
+ if (nodeResult.breakLoop) {
469
+ state.currentGraphState = { ...state.currentGraphState, isActive: false };
470
+ putSystemMessage(`Node action ${currentNode.actionType} requested to break loop.`, {
471
+ conversationGraphState: state.currentGraphState,
150
472
  });
151
- return {
152
- breakLoop: false,
153
- items: [],
154
- };
473
+ return nodeResult; // Propagate breakLoop
155
474
  }
156
- // Track visited nodes to prevent cycles
157
- const visitedNodes = new Set();
158
- let iteration = 0;
159
- const MAX_ITERATIONS = 50; // Safeguard against infinite loops
160
- while (currentNode && iteration < MAX_ITERATIONS) {
161
- iteration++;
162
- visitedNodes.add(currentNode.id);
163
- // Execute the current node
164
- putSystemMessage(`Executing node ${currentNode.id}`, currentNode);
165
- const [sendMessage] = (await generateContentFn(prompt, {
166
- functionDefs: getFunctionDefs(),
167
- requiredFunctionName: 'sendMessage',
168
- temperature: 0.7,
169
- modelType: ModelType.CHEAP,
170
- expectedResponseType: {
171
- text: false,
172
- functionCall: true,
173
- media: false,
174
- },
175
- }, options))
176
- .filter((item) => item.type === 'functionCall')
177
- .map((item) => item.functionCall);
178
- if (sendMessage.args?.message) {
179
- putAssistantMessage(sendMessage.args.message, sendMessage.args);
180
- }
181
- const currentNodeHandler = getActionHandler(currentNode.actionType);
182
- const nodeResult = await currentNodeHandler({
183
- askQuestionCall: {
184
- name: 'askQuestion',
185
- args: {
186
- message: sendMessage.args?.message ?? '',
187
- actionType: currentNode.actionType,
188
- },
189
- },
190
- prompt,
191
- options,
192
- generateContentFn,
193
- generateImageFn,
194
- waitIfPaused,
195
- });
196
- const lastItem = nodeResult.items.slice(-1)[0];
197
- if (lastItem?.user?.text) {
198
- putUserMessage(lastItem.user.text, undefined, undefined, undefined, lastItem.user);
199
- }
200
- prompt.push(...nodeResult.items.map(({ assistant, user }) => [assistant, user]).flat());
201
- // Move to the next node
202
- const outgoingEdges = edges.filter((edge) => edge.sourceNode === currentNode.id);
203
- const [evaluateEdge] = (await generateContentFn([
204
- ...prompt,
205
- {
206
- type: 'user',
207
- text: getEdgeEvaluationPrompt(currentNode, outgoingEdges),
208
- },
209
- ], {
210
- functionDefs: getFunctionDefs(),
211
- requiredFunctionName: 'evaluateEdge',
212
- temperature: 0.7,
213
- modelType: ModelType.CHEAP,
214
- expectedResponseType: {
215
- text: false,
216
- functionCall: true,
217
- media: false,
218
- },
219
- }, options))
220
- .filter((item) => item.type === 'functionCall')
221
- .map((item) => item.functionCall);
222
- if (!evaluateEdge.args?.shouldTerminate) {
223
- putSystemMessage('Conversation graph traversal terminated.');
224
- break;
225
- }
226
- const outgoingEdge = outgoingEdges.find((edge) => edge.targetNode === evaluateEdge.args?.selectedEdge?.targetNode);
227
- if (!outgoingEdge) {
228
- putSystemMessage(`No valid outgoing edge found from node ${currentNode.id}.`);
229
- break;
230
- }
231
- // Find next node
232
- const nextNode = nodes.find((node) => node.id === outgoingEdge.targetNode);
233
- if (!nextNode) {
234
- putSystemMessage(`Target node ${outgoingEdge.targetNode} not found.`);
235
- break;
236
- }
237
- // Check for cycles
238
- if (visitedNodes.has(nextNode.id)) {
239
- putSystemMessage(`Cycle detected at node ${nextNode.id}. Stopping traversal.`);
240
- break;
241
- }
242
- currentNode = nextNode;
475
+ const { nextNode, terminate } = await _evaluateNextStep(currentNode, state, props.generateContentFn, props.options);
476
+ if (terminate) {
477
+ break;
243
478
  }
244
- if (iteration >= MAX_ITERATIONS) {
245
- putSystemMessage('Maximum iterations reached. Stopping traversal.');
479
+ currentNode = nextNode;
480
+ // Update state for the next iteration (will be sent at the start of the next loop)
481
+ if (currentNode) {
482
+ state.currentGraphState = { ...state.currentGraphState, currentNodeId: currentNode.id };
246
483
  }
247
- putSystemMessage('Conversation graph traversal completed.');
248
- prompt.push({
249
- type: 'assistant',
250
- text: 'Conversation graph traversal completed.',
251
- }, {
252
- type: 'user',
253
- text: 'Lets continue the conversation.',
254
- });
255
- return {
256
- breakLoop: false,
257
- items: [],
258
- };
259
484
  }
260
- catch (error) {
261
- putSystemMessage('Error during conversation graph execution', { error });
262
- prompt.push({
263
- type: 'assistant',
264
- text: 'An error occurred during conversation graph execution.', // TODO: Prompt user for message
265
- }, {
266
- type: 'user',
267
- text: 'Lets continue the conversation.', // TODO: Prompt user for message
485
+ if (iteration >= MAX_ITERATIONS) {
486
+ putSystemMessage('Maximum iterations reached. Stopping traversal.', {
487
+ conversationGraphState: { ...state.currentGraphState, isActive: false },
268
488
  });
269
- return {
270
- breakLoop: false,
271
- items: [],
272
- };
273
489
  }
490
+ state.currentGraphState = { ...state.currentGraphState, isActive: false };
491
+ putSystemMessage('Conversation graph traversal completed.', {
492
+ conversationGraphState: state.currentGraphState,
493
+ });
494
+ state.prompt.push({
495
+ type: 'assistant',
496
+ text: 'Conversation graph traversal completed.',
497
+ }, {
498
+ type: 'user',
499
+ text: 'Lets continue the conversation.',
500
+ });
501
+ return { breakLoop: false, items: [] };
274
502
  }
275
503
  //# sourceMappingURL=handle-conversation-graph.js.map