refactor: look up block name from API instead of LLM input

Addresses review feedback from ntindle:
- Remove block_name parameter from run_block tool (no longer required from LLM)
- Frontend now fetches blocks via useGetV1ListAvailableBlocks hook
- Creates memoized Map<blockId, blockName> for efficient lookup
- Falls back to block_id if name lookup fails

This approach:
- Doesn't increase LLM context requirements
- Reduces chance of LLM messing up the name
- Uses existing generated types/hooks
- Only fetches blocks when run_block tool is used (enabled: toolName === 'run_block')
- Caches result for 5 minutes (staleTime)
This commit is contained in:
Bentlybro
2026-02-09 10:52:40 +00:00
parent e419f9202d
commit 5b4d5d2f74
5 changed files with 34 additions and 24 deletions

View File

@@ -178,8 +178,8 @@ class FindBlockTool(BaseTool):
message=(
f"Found {len(blocks)} block(s) matching '{query}'. "
"To execute a block, use run_block with the block's "
"'id' and 'name' fields and provide 'input_data' "
"matching the block's input_schema."
"'id' field and provide 'input_data' matching the "
"block's input_schema."
),
blocks=blocks,
count=len(blocks),

View File

@@ -353,9 +353,8 @@ class BlockListResponse(ToolResponseBase):
usage_hint: str = Field(
default=(
"To execute a block, call run_block with block_id set to "
"the block's 'id' field, block_name set to the block's 'name' "
"field, and input_data containing the required fields from "
"input_schema."
"the block's 'id' field and input_data containing the required "
"fields from input_schema."
)
)

View File

@@ -58,14 +58,6 @@ class RunBlockTool(BaseTool):
"NEVER guess this - always get it from find_block first."
),
},
"block_name": {
"type": "string",
"description": (
"The block's human-readable 'name' field from "
"find_block results. Include this for better user "
"experience."
),
},
"input_data": {
"type": "object",
"description": (

View File

@@ -1,6 +1,9 @@
import { Text } from "@/components/atoms/Text/Text";
import { cn } from "@/lib/utils";
import type { ToolArguments } from "@/types/chat";
import type { Block } from "@/lib/autogpt-server-api/types";
import { useGetV1ListAvailableBlocks } from "@/app/api/__generated__/endpoints/blocks/blocks";
import { useMemo } from "react";
import { AIChatBubble } from "../AIChatBubble/AIChatBubble";
import {
formatToolArguments,
@@ -22,8 +25,23 @@ export function ToolCallMessage({
isStreaming = false,
className,
}: ToolCallMessageProps) {
// Fetch blocks only when needed for run_block tool
const { data: blocksResponse } = useGetV1ListAvailableBlocks({
query: {
enabled: toolName === "run_block",
staleTime: 5 * 60 * 1000, // Cache for 5 minutes
},
});
// Create a memoized map of block IDs to names
const blocksById = useMemo(() => {
if (!blocksResponse?.data) return undefined;
const blocks = blocksResponse.data as Block[];
return new Map(blocks.map((block) => [block.id, block.name]));
}, [blocksResponse?.data]);
const actionPhrase = getToolActionPhrase(toolName);
const argumentsText = formatToolArguments(toolName, toolArguments);
const argumentsText = formatToolArguments(toolName, toolArguments, blocksById);
const displayText = `${actionPhrase}${argumentsText}`;
const IconComponent = getToolIcon(toolName);

View File

@@ -62,11 +62,13 @@ export function getToolActionPhrase(toolName: string): string {
*
* @param toolName - The tool name
* @param args - The tool arguments
* @param blocksById - Optional map of block IDs to block names for lookup
* @returns Formatted user-friendly text to append to action phrase
*/
export function formatToolArguments(
toolName: string,
args: ToolArguments | undefined,
blocksById?: Map<string, string>,
): string {
if (!args || Object.keys(args).length === 0) {
return "";
@@ -109,17 +111,16 @@ export function formatToolArguments(
break;
case "run_block":
// Prefer block_name if provided, otherwise fall back to block_id
if (args.block_name) {
// Beautify and remove redundant "Block" suffix (same pattern as blocks menu)
const displayName = beautifyString(args.block_name as string).replace(
/ Block$/,
"",
);
return ` "${displayName}"`;
}
// Look up block name from blocksById map, fall back to block_id
if (args.block_id) {
return ` "${args.block_id as string}"`;
const blockId = args.block_id as string;
const blockName = blocksById?.get(blockId);
if (blockName) {
// Beautify and remove redundant "Block" suffix (same pattern as blocks menu)
const displayName = beautifyString(blockName).replace(/ Block$/, "");
return ` "${displayName}"`;
}
return ` "${blockId}"`;
}
break;