genaicode 0.10.0 → 0.10.2
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/ai-service/ai-studio.js +69 -70
- package/dist/ai-service/ai-studio.js.map +1 -1
- package/dist/ai-service/common-types.d.ts +1 -0
- package/dist/ai-service/common.js +3 -0
- package/dist/ai-service/common.js.map +1 -1
- package/dist/help-docs/genaicode-help-document.d.ts +1 -1
- package/dist/help-docs/genaicode-help-document.js +1 -0
- package/dist/help-docs/genaicode-help-document.js.map +1 -1
- package/dist/main/common/user-actions.d.ts +1 -1
- package/dist/main/config-types.d.ts +1 -0
- package/dist/main/config.js +8 -1
- package/dist/main/config.js.map +1 -1
- package/dist/main/ui/common/api-types.d.ts +25 -0
- package/dist/main/ui/frontend/assets/index-DWyCD84H.js +2015 -0
- package/dist/main/ui/frontend/index.html +1 -1
- package/dist/prompt/function-calling-validate.d.ts +2 -1
- package/dist/prompt/function-calling-validate.js +2 -2
- package/dist/prompt/function-calling-validate.js.map +1 -1
- package/dist/prompt/function-calling.js +5 -2
- package/dist/prompt/function-calling.js.map +1 -1
- package/dist/prompt/function-defs/ask-question.d.ts +1 -0
- package/dist/prompt/function-defs/ask-question.js +33 -1
- package/dist/prompt/function-defs/ask-question.js.map +1 -1
- package/dist/prompt/function-defs/compound-action-list.d.ts +7 -0
- package/dist/prompt/function-defs/compound-action-list.js +38 -0
- package/dist/prompt/function-defs/compound-action-list.js.map +1 -0
- package/dist/prompt/function-defs/compound-action.d.ts +2 -0
- package/dist/prompt/function-defs/compound-action.js +43 -0
- package/dist/prompt/function-defs/compound-action.js.map +1 -0
- package/dist/prompt/function-defs/conversation-graph.d.ts +6 -6
- package/dist/prompt/limits.js +1 -1
- package/dist/prompt/steps/step-ask-question/handlers/handle-compound-action.d.ts +20 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-compound-action.js +253 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-compound-action.js.map +1 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-conversation-graph.d.ts +6 -7
- package/dist/prompt/steps/step-ask-question/handlers/handle-conversation-graph.js +406 -178
- package/dist/prompt/steps/step-ask-question/handlers/handle-conversation-graph.js.map +1 -1
- package/dist/prompt/steps/step-ask-question/handlers/handle-explore-external-directories.js +4 -1
- package/dist/prompt/steps/step-ask-question/handlers/handle-explore-external-directories.js.map +1 -1
- package/dist/prompt/steps/step-ask-question/handlers/handle-read-external-files.js +5 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-read-external-files.js.map +1 -1
- package/dist/prompt/steps/step-ask-question/handlers/handle-request-git-context.d.ts +3 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-request-git-context.js +184 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-request-git-context.js.map +1 -0
- package/dist/prompt/steps/step-ask-question/handlers/handle-update-file.js +8 -12
- package/dist/prompt/steps/step-ask-question/handlers/handle-update-file.js.map +1 -1
- package/dist/prompt/steps/step-ask-question/step-ask-question-types.d.ts +25 -1
- package/dist/prompt/steps/step-ask-question/step-ask-question.d.ts +2 -0
- package/dist/prompt/steps/step-ask-question/step-ask-question.js +2 -0
- package/dist/prompt/steps/step-ask-question/step-ask-question.js.map +1 -1
- package/dist/prompt/steps/step-validate-recover.js +3 -3
- package/dist/prompt/steps/step-validate-recover.js.map +1 -1
- package/dist/prompt/systemprompt.d.ts +1 -1
- package/dist/prompt/systemprompt.js +7 -2
- package/dist/prompt/systemprompt.js.map +1 -1
- package/package.json +4 -3
- package/dist/main/ui/frontend/assets/index-BlVGo0E6.js +0 -1902
|
@@ -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
|
|
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
|
-
*
|
|
70
|
-
*
|
|
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(
|
|
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
|
-
|
|
78
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
...prompt
|
|
99
|
-
{
|
|
100
|
-
|
|
101
|
-
|
|
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:
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
245
|
-
|
|
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
|
-
|
|
261
|
-
putSystemMessage('
|
|
262
|
-
|
|
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
|