Skip to content

Commit acfa5dc

Browse files
changes
1 parent 069d4a8 commit acfa5dc

File tree

9 files changed

+174
-31
lines changed

9 files changed

+174
-31
lines changed

src/agentlib/agent.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class Agent {
223223
toolResults.push({
224224
role: "tool",
225225
tool_call_id: toolResult.tool_call_id,
226-
content: toolResult.content,
226+
content: toolResult.content?.trim() ? toolResult.content : "Tool executed successfully.",
227227

228228
});
229229
if (toolResult.userMessage) {
@@ -285,6 +285,8 @@ class Agent {
285285

286286
try {
287287
let systemPrompt = await this.systemPrompt.toPromptText();
288+
289+
//TODO: append remix prompt from user
288290
const aiMessages: Message[] = [
289291
{ role: "system", content: systemPrompt },
290292
...apiConversationHistory,
@@ -370,7 +372,7 @@ class Agent {
370372
return {
371373
role: "tool",
372374
tool_call_id,
373-
content,
375+
content: content === "" ? "tool call success" : (Array.isArray(content) ? content[1] : content),
374376
userMessage
375377
};
376378
}

src/agentlib/llmoutputhandler.ts

Lines changed: 144 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,42 @@ class LLMOutputHandler {
3636
* @param codebolt - Optional codebolt API instance
3737
*/
3838
constructor(llmResponse: any, codebolt?: CodeboltAPI) {
39+
// Validate llmResponse structure
40+
if (!llmResponse) {
41+
throw new Error("LLM response is null or undefined");
42+
}
43+
44+
if (!llmResponse.completion) {
45+
throw new Error("LLM response completion is missing");
46+
}
47+
48+
if (!llmResponse.completion.choices || !Array.isArray(llmResponse.completion.choices)) {
49+
throw new Error("LLM response choices array is missing or invalid");
50+
}
51+
3952
this.llmResponse = llmResponse;
4053
this.codebolt = codebolt;
4154

4255
// Check if any message has tool_calls, if none do, mark as completed
4356
let hasToolCalls = false;
44-
this.llmResponse.completion.choices.forEach((message: any) => {
45-
if (message.message?.tool_calls && message.message.tool_calls.length > 0) {
46-
hasToolCalls = true;
47-
}
48-
});
57+
try {
58+
this.llmResponse.completion.choices.forEach((message: any) => {
59+
if (message.message?.tool_calls && message.message.tool_calls.length > 0) {
60+
hasToolCalls = true;
61+
}
62+
});
63+
} catch (error) {
64+
console.error("Error checking for tool calls:", error);
65+
hasToolCalls = false;
66+
}
4967

5068
// If no messages have tool_calls, mark as completed
5169
if (!hasToolCalls) {
52-
this.sendMessageToUser();
70+
try {
71+
this.sendMessageToUser();
72+
} catch (error) {
73+
console.error("Error sending message to user:", error);
74+
}
5375
this.completed = true;
5476
}
5577
}
@@ -119,11 +141,32 @@ class LLMOutputHandler {
119141
*/
120142
async runTools(): Promise<ToolResult[]> {
121143
try {
144+
// Validate llmResponse structure
145+
if (!this.llmResponse || !this.llmResponse.completion) {
146+
throw new Error("Invalid LLM response structure");
147+
}
148+
149+
if (!this.llmResponse.completion.choices || !Array.isArray(this.llmResponse.completion.choices)) {
150+
throw new Error("LLM response choices array is missing or invalid");
151+
}
152+
153+
if (this.llmResponse.completion.choices.length === 0) {
154+
console.warn("No choices found in LLM response");
155+
return this.toolResults;
156+
}
157+
122158
let toolResults: ToolResult[] = [];
123159
let taskCompletedBlock: any;
124160
let userRejectedToolUse = false;
125161
console.log("Calling run tool: ", JSON.stringify (this.llmResponse.completion));
162+
126163
const contentBlock = this.llmResponse.completion.choices[0];
164+
165+
// Validate contentBlock structure
166+
if (!contentBlock || !contentBlock.message) {
167+
console.warn("Invalid content block structure");
168+
return this.toolResults;
169+
}
127170

128171
if (contentBlock.message?.tool_calls) {
129172
for (const tool of contentBlock.message.tool_calls) {
@@ -208,7 +251,7 @@ class LLMOutputHandler {
208251

209252
this.toolResults.push({
210253
role: "tool",
211-
tool_call_id: tool.id,
254+
tool_call_id: tool?.id || "unknown",
212255
content: String(error),
213256

214257
});
@@ -218,16 +261,40 @@ class LLMOutputHandler {
218261
}
219262

220263
if (taskCompletedBlock) {
264+
let taskArgs = {};
265+
try {
266+
// Validate taskCompletedBlock structure
267+
if (!taskCompletedBlock.function) {
268+
throw new Error("Task completed block function is missing");
269+
}
270+
271+
if (!taskCompletedBlock.function.name) {
272+
throw new Error("Task completed block function name is missing");
273+
}
274+
275+
// Parse arguments safely
276+
const argumentsString = taskCompletedBlock.function.arguments || "{}";
277+
if (typeof argumentsString !== 'string') {
278+
throw new Error("Task completed block arguments must be a string");
279+
}
280+
281+
taskArgs = JSON.parse(argumentsString);
282+
} catch (parseError) {
283+
const errorMessage = parseError instanceof Error ? parseError.message : 'Unknown parsing error';
284+
console.error("Failed to parse taskCompletedBlock arguments:", errorMessage);
285+
taskArgs = {};
286+
}
287+
221288
let [_, result] = await this.executeTool(
222289
taskCompletedBlock.function.name,
223-
JSON.parse(taskCompletedBlock.function.arguments || "{}")
290+
taskArgs
224291
);
225292

226293
if (result === "") {
227294
this.completed = true;
228295
result = "The user is satisfied with the result.";
229296
}
230-
let toolResult = this.getToolResult(taskCompletedBlock.id, result)
297+
let toolResult = this.getToolResult(taskCompletedBlock?.id || "unknown", result)
231298
this.toolResults.push({
232299
role: "tool",
233300
tool_call_id: toolResult.tool_call_id,
@@ -262,7 +329,17 @@ class LLMOutputHandler {
262329
}
263330
return this.toolResults
264331
} catch (error) {
265-
return this.toolResults
332+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
333+
console.error(`Error in runTools: ${errorMessage}`, error);
334+
335+
// Add error information to tool results for debugging
336+
this.toolResults.push({
337+
role: "tool",
338+
tool_call_id: "error",
339+
content: `Error executing tools: ${errorMessage}`
340+
});
341+
342+
return this.toolResults;
266343
}
267344
}
268345

@@ -298,11 +375,46 @@ class LLMOutputHandler {
298375
* @returns ToolDetails object with name, input, and ID
299376
*/
300377
private getToolDetail(tool: any): ToolDetails {
301-
return {
302-
toolName: tool.function.name,
303-
toolInput: JSON.parse(tool.function.arguments || "{}"),
304-
toolUseId: tool.id
305-
};
378+
try {
379+
// Validate tool object
380+
if (!tool) {
381+
throw new Error("Tool object is null or undefined");
382+
}
383+
384+
// Validate tool.function
385+
if (!tool.function) {
386+
throw new Error("Tool function is null or undefined");
387+
}
388+
389+
// Validate tool.function.name
390+
if (!tool.function.name || typeof tool.function.name !== 'string') {
391+
throw new Error("Tool function name is missing or invalid");
392+
}
393+
394+
// Validate tool.id
395+
if (!tool.id || typeof tool.id !== 'string') {
396+
throw new Error("Tool ID is missing or invalid");
397+
}
398+
399+
// Parse tool arguments safely
400+
let toolInput: any = {};
401+
if (tool.function.arguments) {
402+
try {
403+
toolInput = JSON.parse(tool.function.arguments);
404+
} catch (parseError) {
405+
throw new Error(`Failed to parse tool arguments: ${parseError instanceof Error ? parseError.message : 'Invalid JSON'}`);
406+
}
407+
}
408+
409+
return {
410+
toolName: tool.function.name,
411+
toolInput: toolInput,
412+
toolUseId: tool.id
413+
};
414+
} catch (error) {
415+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
416+
throw new Error(`Failed to extract tool details: ${errorMessage}`);
417+
}
306418
}
307419

308420
/**
@@ -341,15 +453,25 @@ class LLMOutputHandler {
341453
let userMessage = undefined;
342454

343455
try {
344-
const parsed = JSON.parse(content);
345-
console.log("Parsed Content: ", parsed);
346-
347-
if (parsed.payload && parsed.payload.content) {
348-
content = `The browser action has been executed. The screenshot have been captured for your analysis. The tool response is provided in the next user message`;
349-
userMessage = parsed.payload.content;
456+
// Validate content before parsing
457+
if (typeof content !== 'string') {
458+
throw new Error("Content must be a string");
459+
}
460+
461+
// Only attempt to parse if content looks like JSON
462+
if (content.trim().startsWith('{') || content.trim().startsWith('[')) {
463+
const parsed = JSON.parse(content);
464+
console.log("Parsed Content: ", parsed);
465+
466+
if (parsed && typeof parsed === 'object' && parsed.payload && parsed.payload.content) {
467+
content = `The browser action has been executed. The screenshot have been captured for your analysis. The tool response is provided in the next user message`;
468+
userMessage = parsed.payload.content;
469+
}
350470
}
351471
} catch (error) {
352-
// Content is not JSON, use as-is
472+
const errorMessage = error instanceof Error ? error.message : 'Unknown JSON parsing error';
473+
console.warn(`Failed to parse tool result content as JSON: ${errorMessage}. Using content as-is.`);
474+
// Content is not valid JSON, use as-is
353475
}
354476

355477
return {

src/agentlib/promptbuilder.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -713,9 +713,12 @@ class InitialPromptBuilder {
713713
* @returns The PromptBuilder instance for chaining
714714
*/
715715
addContext(context: string): this {
716-
if (context.trim()) {
717-
this.promptParts.push(`[Context]\n${context}`);
718-
}
716+
const userMessage: ConversationEntry = {
717+
role: "user",
718+
content: context
719+
};
720+
721+
this.conversationHistory.push(userMessage);
719722
return this;
720723
}
721724

@@ -747,6 +750,7 @@ class InitialPromptBuilder {
747750
messages: this.buildOpenAIMessages(),
748751
tools: this.getTools(),
749752
full: true,
753+
max_tokens:8192,
750754
tool_choice: "auto" as const,
751755
};
752756
}

src/agentlib/systemprompt.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ class SystemPrompt {
3535
throw new Error('Invalid YAML structure');
3636
}
3737

38-
if (!data[this.key]?.prompt) {
38+
if ( !data[this.key]) {
3939
throw new Error(`Prompt not found for key: ${this.key}`);
4040
}
4141

42-
return data[this.key].prompt;
42+
const promptData = data[this.key];
43+
return typeof promptData === 'string' ? promptData : promptData.prompt;
4344
} catch (error) {
4445
console.error(`SystemPrompt Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
4546
throw error; // Re-throw to allow caller handling

src/agentlib/taskInstruction.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,8 @@ class TaskInstruction {
6464
throw error;
6565
}
6666
}
67+
68+
69+
6770
}
6871
export { TaskInstruction };

src/agentlib/usermessage.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class UserMessage {
5454
async toPrompt(
5555
bAttachFiles: boolean = true,
5656
bAttachImages: boolean = true,
57-
bAttachEnvironment: boolean = true
57+
bAttachEnvironment: boolean = true,
58+
supportRemix:boolean=true
5859
): Promise<UserMessageContent[]> {
5960
if (bAttachFiles) {
6061
if (this.promptOverride) {
@@ -83,6 +84,11 @@ class UserMessage {
8384
}
8485
}
8586

87+
if(supportRemix){
88+
if(this.message.remixPrompt)
89+
this.userMessages.push({type:"text",text:this.message.remixPrompt})
90+
}
91+
8692
return this.userMessages;
8793
}
8894

@@ -135,6 +141,8 @@ class UserMessage {
135141
}`;
136142
return `<environment_details>\n${details.trim()}\n</environment_details>`;
137143
}
144+
145+
138146
}
139147

140148
export { UserMessage };

src/core/Codebolt.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ class Codebolt {
132132
},
133133
messageId: response.message.messageId,
134134
threadId: response.message.threadId,
135-
selection: response.message.selection
135+
selection: response.message.selection,
136+
remixPrompt:response.message.remixPrompt
136137
};
137138

138139
const result = await handler(userMessage);

src/types/InternalTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ export interface Message {
635635
mentionedMCPs: { toolbox: string, toolName: string }[];
636636
/** List of agents mentioned in the message */
637637
mentionedAgents: any[];
638+
remixPrompt?:string
638639
}
639640

640641
/**

src/types/libFunctionTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export interface UserMessage {
205205
threadId: string;
206206
/** Any text selection in the editor */
207207
selection?: any;
208+
remixPrompt?:string
208209
}
209210

210211
/**

0 commit comments

Comments
 (0)