mirror of https://github.com/buster-so/buster.git
Merge pull request #580 from buster-so/devin/BUS-1468-1753084167
feat: implement idle tool for agent system (BUS-1468)
This commit is contained in:
commit
43f88dd3a4
|
@ -0,0 +1,99 @@
|
|||
import { createTool } from '@mastra/core/tools';
|
||||
import { wrapTraced } from 'braintrust';
|
||||
import { z } from 'zod';
|
||||
|
||||
// Input/Output schemas
|
||||
const idleInputSchema = z.object({
|
||||
final_response: z
|
||||
.string()
|
||||
.min(1, 'Final response is required')
|
||||
.describe(
|
||||
"The final response message to the user. **MUST** be formatted in Markdown. Use bullet points or other appropriate Markdown formatting. Do not include headers. Do not use the '•' bullet character. Do not include markdown tables."
|
||||
),
|
||||
});
|
||||
|
||||
export type IdleToolExecuteInput = z.infer<typeof idleInputSchema>;
|
||||
|
||||
/**
|
||||
* Optimistic parsing function for streaming idle tool arguments
|
||||
* Extracts the final_response field as it's being built incrementally
|
||||
*/
|
||||
export function parseStreamingArgs(
|
||||
accumulatedText: string
|
||||
): Partial<z.infer<typeof idleInputSchema>> | null {
|
||||
// Validate input type
|
||||
if (typeof accumulatedText !== 'string') {
|
||||
throw new Error(`parseStreamingArgs expects string input, got ${typeof accumulatedText}`);
|
||||
}
|
||||
|
||||
try {
|
||||
// First try to parse as complete JSON
|
||||
const parsed = JSON.parse(accumulatedText);
|
||||
return {
|
||||
final_response: parsed.final_response || undefined,
|
||||
};
|
||||
} catch (error) {
|
||||
// Only catch JSON parse errors - let other errors bubble up
|
||||
if (error instanceof SyntaxError) {
|
||||
// JSON parsing failed - try regex extraction for partial content
|
||||
// Handle both complete and incomplete strings, accounting for escaped quotes
|
||||
const match = accumulatedText.match(/"final_response"\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
||||
if (match && match[1] !== undefined) {
|
||||
// Unescape the string
|
||||
const unescaped = match[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
return {
|
||||
final_response: unescaped,
|
||||
};
|
||||
}
|
||||
|
||||
// Try to extract partial string that's still being built (incomplete quote)
|
||||
const partialMatch = accumulatedText.match(/"final_response"\s*:\s*"((?:[^"\\]|\\.*)*)/);
|
||||
if (partialMatch && partialMatch[1] !== undefined) {
|
||||
// Unescape the partial string
|
||||
const unescaped = partialMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
return {
|
||||
final_response: unescaped,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
// Unexpected error - re-throw with context
|
||||
throw new Error(
|
||||
`Unexpected error in parseStreamingArgs: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const idleOutputSchema = z.object({
|
||||
success: z.boolean().describe('Whether the operation was successful'),
|
||||
});
|
||||
|
||||
type IdleOutput = z.infer<typeof idleOutputSchema>;
|
||||
|
||||
async function processIdle(_input: IdleToolExecuteInput): Promise<IdleOutput> {
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
const executeIdle = wrapTraced(
|
||||
async (input: IdleToolExecuteInput): Promise<z.infer<typeof idleOutputSchema>> => {
|
||||
return await processIdle(input);
|
||||
},
|
||||
{ name: 'idle-tool' }
|
||||
);
|
||||
|
||||
// Export the tool
|
||||
export const idleTool = createTool({
|
||||
id: 'idle',
|
||||
description:
|
||||
"Marks all remaining unfinished tasks as complete, sends a final response to the user, and enters an idle state. Use this when current work is finished but the agent should remain available for future tasks. This must be in markdown format and not use the '•' bullet character.",
|
||||
inputSchema: idleInputSchema,
|
||||
outputSchema: idleOutputSchema,
|
||||
execute: async ({ context }) => {
|
||||
return await executeIdle(context as IdleToolExecuteInput);
|
||||
},
|
||||
});
|
||||
|
||||
export default idleTool;
|
|
@ -1,4 +1,5 @@
|
|||
export { doneTool } from './communication-tools/done-tool';
|
||||
export { idleTool } from './communication-tools/idle-tool';
|
||||
export { respondWithoutAnalysis } from './communication-tools/respond-without-analysis';
|
||||
export { submitThoughts } from './communication-tools/submit-thoughts-tool';
|
||||
export { messageUserClarifyingQuestion } from './communication-tools/message-user-clarifying-question';
|
||||
|
|
Loading…
Reference in New Issue