feat(tools): added thinking tool, hiddenFromSidebar param (#230)

* add thinking tool and block

* add hiddenFromSidebar for blocks that we want to be accessible to agents but hidden as standalone blocks
This commit is contained in:
Waleed Latif
2025-04-06 13:24:53 -07:00
committed by GitHub
parent 47ad2bae85
commit d97ecead5d
9 changed files with 134 additions and 48 deletions

View File

@@ -19,7 +19,8 @@ export function Toolbar() {
const filteredBlocks = !searchQuery.trim() ? getBlocksByCategory(activeTab) : getAllBlocks()
return filteredBlocks.filter((block) => {
if (block.type === 'starter') return false
if (block.type === 'starter' || block.hiddenFromSidebar) return false
return (
!searchQuery.trim() ||
block.name.toLowerCase().includes(searchQuery.toLowerCase()) ||

View File

@@ -0,0 +1,52 @@
import { BrainIcon } from '@/components/icons'
import { ToolResponse } from '@/tools/types'
import { BlockConfig } from '../types'
interface ThinkingToolResponse extends ToolResponse {
output: {
acknowledgedThought: string
}
}
export const ThinkingBlock: BlockConfig<ThinkingToolResponse> = {
type: 'thinking',
name: 'Thinking',
description: 'Forces model to outline its thought process.',
longDescription:
'Adds a step where the model explicitly outlines its thought process before proceeding. This can improve reasoning quality by encouraging step-by-step analysis.',
category: 'tools',
bgColor: '#181C1E',
icon: BrainIcon,
hiddenFromSidebar: true,
subBlocks: [
{
id: 'thought',
title: 'Thought Process / Instruction',
type: 'long-input',
layout: 'full',
placeholder: 'Describe the step-by-step thinking process here...',
hidden: true,
},
],
inputs: {
thought: {
type: 'string',
required: true,
description: 'The detailed thought process or instruction for the model.',
},
},
outputs: {
response: {
type: {
acknowledgedThought: 'string',
},
},
},
tools: {
access: ['thinking_tool'],
},
}

View File

@@ -8,7 +8,6 @@ import { GoogleDocsBlock } from './blocks/docs'
import { GoogleDriveBlock } from './blocks/drive'
import { EvaluatorBlock } from './blocks/evaluator'
import { ExaBlock } from './blocks/exa'
import { MistralParseBlock } from './blocks/mistral-parse'
import { FileBlock } from './blocks/file'
import { FirecrawlBlock } from './blocks/firecrawl'
import { FunctionBlock } from './blocks/function'
@@ -17,6 +16,7 @@ import { GmailBlock } from './blocks/gmail'
// import { GuestyBlock } from './blocks/guesty'
import { ImageGeneratorBlock } from './blocks/image-generator'
import { JinaBlock } from './blocks/jina'
import { MistralParseBlock } from './blocks/mistral-parse'
import { NotionBlock } from './blocks/notion'
import { OpenAIBlock } from './blocks/openai'
import { PerplexityBlock } from './blocks/perplexity'
@@ -29,6 +29,7 @@ import { SlackBlock } from './blocks/slack'
import { StarterBlock } from './blocks/starter'
import { SupabaseBlock } from './blocks/supabase'
import { TavilyBlock } from './blocks/tavily'
import { ThinkingBlock } from './blocks/thinking'
import { TranslateBlock } from './blocks/translate'
import { TwilioSMSBlock } from './blocks/twilio'
import { TypeformBlock } from './blocks/typeform'
@@ -77,6 +78,7 @@ export {
TwilioSMSBlock,
ImageGeneratorBlock,
TypeformBlock,
ThinkingBlock,
}
// Registry of all block configurations, alphabetically sorted
@@ -88,7 +90,6 @@ const blocks: Record<string, BlockConfig> = {
confluence: ConfluenceBlock,
evaluator: EvaluatorBlock,
exa: ExaBlock,
mistral_parse: MistralParseBlock,
firecrawl: FirecrawlBlock,
file: FileBlock,
function: FunctionBlock,
@@ -100,6 +101,7 @@ const blocks: Record<string, BlockConfig> = {
// guesty: GuestyBlock,
image_generator: ImageGeneratorBlock,
jina: JinaBlock,
mistral_parse: MistralParseBlock,
notion: NotionBlock,
openai: OpenAIBlock,
perplexity: PerplexityBlock,
@@ -111,6 +113,7 @@ const blocks: Record<string, BlockConfig> = {
starter: StarterBlock,
supabase: SupabaseBlock,
tavily: TavilyBlock,
thinking: ThinkingBlock,
translate: TranslateBlock,
twilio_sms: TwilioSMSBlock,
typeform: TypeformBlock,

View File

@@ -152,6 +152,7 @@ export interface BlockConfig<T extends ToolResponse = ToolResponse> {
}
}
}
hiddenFromSidebar?: boolean
}
// Output configuration rules

View File

@@ -1359,48 +1359,6 @@ export const CrunchbaseIcon = (props: SVGProps<SVGSVGElement>) => (
</svg>
)
export function BrainIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M20.0553 16.4443C18.7145 16.4443 17.4286 16.977 16.4805 17.9251C15.5324 18.8732 14.9998 20.1591 14.9998 21.4999M14.9998 21.4999V22.9443M14.9998 21.4999C14.9998 20.1591 14.4671 18.8732 13.519 17.9251C12.5709 16.977 11.285 16.4443 9.94423 16.4443M14.9998 22.9443C14.9998 24.2852 15.5324 25.5711 16.4805 26.5192C17.4286 27.4673 18.7145 27.9999 20.0553 27.9999C21.3962 27.9999 22.6821 27.4673 23.6302 26.5192C24.5783 25.5711 25.1109 24.2852 25.1109 22.9443V20.3443M14.9998 22.9443C14.9998 24.2852 14.4671 25.5711 13.519 26.5192C12.5709 27.4673 11.285 27.9999 9.94423 27.9999C8.60341 27.9999 7.31751 27.4673 6.36941 26.5192C5.42131 25.5711 4.88867 24.2852 4.88867 22.9443V20.3443"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M22.9449 20.7779C24.2857 20.7779 25.5716 20.2452 26.5197 19.2971C27.4678 18.349 28.0004 17.0631 28.0004 15.7223C28.0004 14.3815 27.4678 13.0956 26.5197 12.1475C25.5716 11.1994 24.2857 10.6667 22.9449 10.6667H22.2227"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M25.1111 11.1V7.05556C25.1111 5.71474 24.5785 4.42884 23.6304 3.48074C22.6823 2.53264 21.3964 2 20.0556 2C18.7147 2 17.4288 2.53264 16.4807 3.48074C15.5326 4.42884 14.9998 5.71474 14.9998 7.05556V21.5"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.88867 11.1V7.05556C4.88867 5.71474 5.42131 4.42884 6.36941 3.48074C7.31751 2.53264 8.60341 2 9.94423 2C11.285 2 12.5709 2.53264 13.519 3.48074C14.4671 4.42884 14.9998 5.71474 14.9998 7.05556V21.5"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export function InputIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
@@ -1866,3 +1824,19 @@ export function MistralIcon(props: SVGProps<SVGSVGElement>) {
</svg>
)
}
export function BrainIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="currentColor">
<title>Brain</title>
<g id="Brain">
<path d="M11,5.34c-.12,1,.26.66-1,.66A7,7,0,0,0,4.85,17.75,7,7,0,0,0,2.62,28.48,12.14,12.14,0,0,0,.06,37.22C1,46.59,12.33,51.56,19.31,45A11.66,11.66,0,0,0,23,36.51V6.22C23-1.57,11.86-2.14,11,5.34Zm-.55,40.55a8.89,8.89,0,0,1-4.78-2.18l.42-.42a2.1,2.1,0,0,1,2.42-.4,1,1,0,0,0,.9-1.78c-2-1-1.24.83-2-3.11-.61-3,1.55-4.14,0-4.89-1.79-.9-2.38,3.32-2,5.28.79,4,.85,1.7-1.19,3.94a10,10,0,0,1-.13-12.5c1.51,1,4.86,2,4.86.17a1,1,0,0,0-1-1c-5.79,0-6.94-8.33-1.27-9.82C8,19.87,11,20.73,11,19a1,1,0,0,0-1-1,5,5,0,1,1,1.44-9.77C13,12,18,13,18,11a1,1,0,0,0-1-1,4,4,0,1,1,4-3.78v9.37l-1.16,1.15a3.42,3.42,0,0,1-4.29.43,1,1,0,0,0-1.38.28c-1.12,1.68,3.7,3.68,6.83.92V36.51A9.3,9.3,0,0,1,10.49,45.89Z" />
<path d="M16.21,23.79a3.14,3.14,0,0,0-4.42,0c-1,1-2-.42-3.08-1.5a1,1,0,0,0-1.42,1.42l.86.85-1.47.49A1,1,0,0,0,7.32,27L10.18,26c2.71.74,3.26-2.15,4.61-.79l2.5,2.5a1,1,0,0,0,1.42-1.42Z" />
<path d="M17,33H16a3,3,0,0,0-3,3,1,1,0,0,1-1,1H11a1,1,0,0,0,0,2h1a3,3,0,0,0,3-3,1,1,0,0,1,1-1h1A1,1,0,0,0,17,33Z" />
<path d="M45.36,28.49a7,7,0,0,0-2.21-10.74A7,7,0,0,0,38,6c-1.28,0-.93.35-1-.63A6,6,0,0,0,31,0a6.13,6.13,0,0,0-6,6.22V36.51C25,42.89,30.26,48.4,36.82,48A12,12,0,0,0,45.36,28.49Zm-1.65,13.8A4.92,4.92,0,0,0,42,41c.55-2.79,1.21-4.79-.13-7.47a1,1,0,0,0-1.78.9c1,2.06.45,3.65-.07,6.25-3.33.28-1.92,2.85-.59,2.19s2.33.34,2.88.84A9.28,9.28,0,0,1,27,36.51V18.37c3.12,2.75,8,.76,6.83-.92a1,1,0,0,0-1.38-.28,3.42,3.42,0,0,1-4.29-.43L27,15.59V6.22A4,4,0,1,1,31,10a1,1,0,0,0-1,1c0,2.05,5.07,1,6.57-2.78A5,5,0,1,1,38,18a1,1,0,0,0,0,2,7,7,0,0,0,3.27-.82C47,20.68,45.73,29,40,29a1,1,0,0,0,0,2,6.89,6.89,0,0,0,3.86-1.17C48.62,35.85,44,42.55,43.71,42.29Z" />
<path d="M41,27a1,1,0,0,0,.32-1.95l-1.47-.49.86-.85a1,1,0,0,0-1.42-1.42c-1.09,1.09-2.07,2.51-3.08,1.5a3.14,3.14,0,0,0-4.42,0l-2.5,2.5A1,1,0,0,0,30,28c.56,0,.54-.13,3.21-2.79,1.38-1.38,1.86,1.54,4.61.79C40.92,27,40.78,27,41,27Z" />
<path d="M37,37H36a1,1,0,0,1-1-1,3,3,0,0,0-3-3H31a1,1,0,0,0,0,2h1a1,1,0,0,1,1,1,3,3,0,0,0,3,3h1A1,1,0,0,0,37,37Z" />
</g>
</svg>
)
}

View File

@@ -44,10 +44,11 @@ import { sheetsReadTool, sheetsUpdateTool, sheetsWriteTool } from './sheets'
import { slackMessageTool } from './slack/message'
import { supabaseInsertTool, supabaseQueryTool } from './supabase'
import { tavilyExtractTool, tavilySearchTool } from './tavily'
import { thinkingTool } from './thinking/thinking'
import { sendSMSTool } from './twilio/send'
import { typeformFilesTool, typeformInsightsTool, typeformResponsesTool } from './typeform'
import { OAuthTokenPayload, ToolConfig, ToolResponse } from './types'
import { formatRequestParams, validateToolRequest, transformTable } from './utils'
import { formatRequestParams, transformTable, validateToolRequest } from './utils'
import { visionTool } from './vision/vision'
import { whatsappSendMessageTool } from './whatsapp'
import { xReadTool, xSearchTool, xUserTool, xWriteTool } from './x'
@@ -122,6 +123,7 @@ export const tools: Record<string, ToolConfig> = {
airtable_list_records: airtableListRecordsTool,
airtable_update_record: airtableUpdateRecordTool,
mistral_parser: mistralParserTool,
thinking_tool: thinkingTool,
}
// Get a tool by its ID
@@ -345,7 +347,7 @@ export async function executeTool(
const endTime = new Date()
const endTimeISO = endTime.toISOString()
const duration = endTime.getTime() - startTime.getTime()
// Apply post-processing if available and not skipped
if (tool.postProcess && directResult.success && !skipPostProcess) {
try {
@@ -370,7 +372,7 @@ export async function executeTool(
}
}
}
return {
...directResult,
timing: {

View File

@@ -0,0 +1,3 @@
import { thinkingTool } from './thinking'
export { thinkingTool }

View File

@@ -0,0 +1,39 @@
import { ToolConfig } from '../types'
import { ThinkingToolParams, ThinkingToolResponse } from './types'
export const thinkingTool: ToolConfig<ThinkingToolParams, ThinkingToolResponse> = {
id: 'thinking_tool',
name: 'Thinking Tool',
description:
'Processes a provided thought/instruction, making it available for subsequent steps.',
version: '1.0.0',
// Define the input parameter
params: {
thought: {
type: 'string',
required: true,
description:
'The thought process or instruction provided by the user in the Thinking Step block.',
},
},
// Use directExecution as no external HTTP call is needed
directExecution: async (params: ThinkingToolParams): Promise<ThinkingToolResponse> => {
// Simply acknowledge the thought by returning it in the output
return {
success: true,
output: {
acknowledgedThought: params.thought,
},
}
},
// Request configuration is not needed due to directExecution, but the type requires it.
// Provide minimal valid configuration.
request: {
url: '', // Not used
method: 'POST', // Not used
headers: () => ({}), // Not used
},
}

View File

@@ -0,0 +1,11 @@
import { ToolResponse } from '../types'
export interface ThinkingToolParams {
thought: string
}
export interface ThinkingToolResponse extends ToolResponse {
output: {
acknowledgedThought: string
}
}