diff --git a/packages/agent/src/tools/getTools.ts b/packages/agent/src/tools/getTools.ts index c74194d..8c7a74e 100644 --- a/packages/agent/src/tools/getTools.ts +++ b/packages/agent/src/tools/getTools.ts @@ -19,6 +19,7 @@ import { shellMessageTool } from './shell/shellMessage.js'; import { shellStartTool } from './shell/shellStart.js'; import { waitTool } from './sleep/wait.js'; import { textEditorTool } from './textEditor/textEditor.js'; +import { thinkTool } from './think/think.js'; // Import these separately to avoid circular dependencies @@ -52,6 +53,7 @@ export function getTools(options?: GetToolsOptions): Tool[] { sessionMessageTool as unknown as Tool, listSessionsTool as unknown as Tool, waitTool as unknown as Tool, + thinkTool as unknown as Tool, ]; // Add agent tools based on the configured mode diff --git a/packages/agent/src/tools/think/index.ts b/packages/agent/src/tools/think/index.ts new file mode 100644 index 0000000..5def3af --- /dev/null +++ b/packages/agent/src/tools/think/index.ts @@ -0,0 +1 @@ +export * from './think.js'; diff --git a/packages/agent/src/tools/think/think.test.ts b/packages/agent/src/tools/think/think.test.ts new file mode 100644 index 0000000..42b8e97 --- /dev/null +++ b/packages/agent/src/tools/think/think.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from 'vitest'; + +import { getMockToolContext } from '../getTools.test.js'; + +import { thinkTool } from './think.js'; + +describe('thinkTool', () => { + const mockContext = getMockToolContext(); + + it('should have the correct name and description', () => { + expect(thinkTool.name).toBe('think'); + expect(thinkTool.description).toContain( + 'Use the tool to think about something', + ); + }); + + it('should return the thought that was provided', async () => { + const thought = + 'I need to consider all possible solutions before deciding on an approach.'; + const result = await thinkTool.execute({ thought }, mockContext); + + expect(result).toEqual({ thought }); + }); + + it('should accept any string as a thought', async () => { + const thoughts = [ + 'Simple thought', + 'Complex thought with multiple steps:\n1. First consider X\n2. Then Y\n3. Finally Z', + 'A question to myself: what if we tried a different approach?', + ]; + + for (const thought of thoughts) { + const result = await thinkTool.execute({ thought }, mockContext); + expect(result).toEqual({ thought }); + } + }); +}); diff --git a/packages/agent/src/tools/think/think.ts b/packages/agent/src/tools/think/think.ts new file mode 100644 index 0000000..7176c40 --- /dev/null +++ b/packages/agent/src/tools/think/think.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; + +/** + * Schema for the think tool parameters + */ +const parameters = z.object({ + thought: z.string().describe('A thought to think about.'), +}); + +/** + * Schema for the think tool returns + */ +const returns = z.object({ + thought: z.string().describe('The thought that was processed.'), +}); + +/** + * Think tool implementation + * + * This tool allows the agent to explicitly think through a complex problem + * without taking any external actions. It serves as a way to document the + * agent's reasoning process and can improve problem-solving abilities. + * + * Based on research from Anthropic showing how a simple "think" tool can + * improve Claude's problem-solving skills. + */ +export const thinkTool = { + name: 'think', + description: + 'Use the tool to think about something. It will not obtain new information or change any state, but just helps with complex reasoning.', + parameters, + returns, + execute: async ({ thought }, { logger }) => { + // Log the thought process + logger.log(`Thinking: ${thought}`); + + // Simply return the thought - no side effects + return { + thought, + }; + }, +};