feat: group builder not set true edit data (#11861)

* feat: add the  setAgentBuilderContent tools into agent group builder to slove setEditor not work

* feat: update the system prompt

* feat: add the maxtools result call lenght in agent config
This commit is contained in:
Shinji-Li
2026-01-26 22:12:57 +08:00
committed by GitHub
parent 7ce31c1594
commit 37944e7d3d
7 changed files with 120 additions and 10 deletions

View File

@@ -87,6 +87,13 @@ export interface LobeAgentChatConfig {
searchFCModel?: WorkingModel;
urlContext?: boolean;
useModelBuiltinSearch?: boolean;
/**
* Maximum length for tool execution result content (in characters)
* This prevents context overflow when sending tool results back to LLM
* @default 6000
*/
toolResultMaxLength?: number;
}
/* eslint-enable */
@@ -130,6 +137,7 @@ export const AgentChatConfigSchema = z.object({
thinking: z.enum(['disabled', 'auto', 'enabled']).optional(),
thinkingBudget: z.number().optional(),
thinkingLevel: z.enum(['minimal', 'low', 'medium', 'high']).optional(),
toolResultMaxLength: z.number().default(6000),
urlContext: z.boolean().optional(),
useModelBuiltinSearch: z.boolean().optional(),
});

View File

@@ -471,11 +471,17 @@ export const createRuntimeExecutors = (
const chatToolPayload: ChatToolPayload = payload.toolCalling;
const toolName = `${chatToolPayload.identifier}/${chatToolPayload.apiName}`;
// Extract toolResultMaxLength from agent config
const agentConfig = state.metadata?.agentConfig;
const toolResultMaxLength = agentConfig?.chatConfig?.toolResultMaxLength;
// Execute tool using ToolExecutionService
log(`[${operationLogId}] Executing tool ${toolName} ...`);
const executionResult = await toolExecutionService.executeTool(chatToolPayload, {
serverDB: ctx.serverDB,
toolManifestMap: state.toolManifestMap,
toolResultMaxLength,
topicId: ctx.topicId,
userId: ctx.userId,
});
@@ -629,7 +635,9 @@ export const createRuntimeExecutors = (
const events: AgentEvent[] = [];
const operationLogId = `${operationId}:${stepIndex}`;
log(`[${operationLogId}][call_tools_batch] Starting batch execution for ${toolsCalling.length} tools`);
log(
`[${operationLogId}][call_tools_batch] Starting batch execution for ${toolsCalling.length} tools`,
);
// Track all tool message IDs created during execution
const toolMessageIds: string[] = [];
@@ -692,7 +700,10 @@ export const createRuntimeExecutors = (
toolMessageIds.push(toolMessage.id);
log(`[${operationLogId}] Created tool message ${toolMessage.id} for ${toolName}`);
} catch (error) {
console.error(`[${operationLogId}] Failed to create tool message for ${toolName}:`, error);
console.error(
`[${operationLogId}] Failed to create tool message for ${toolName}:`,
error,
);
}
// Collect tool result
@@ -734,7 +745,9 @@ export const createRuntimeExecutors = (
}),
);
log(`[${operationLogId}][call_tools_batch] All tools executed, created ${toolMessageIds.length} tool messages`);
log(
`[${operationLogId}][call_tools_batch] All tools executed, created ${toolMessageIds.length} tool messages`,
);
// Refresh messages from database to ensure state is in sync
const newState = structuredClone(state);
@@ -753,7 +766,9 @@ export const createRuntimeExecutors = (
tool_calls: msg.tool_calls,
}));
log(`[${operationLogId}][call_tools_batch] Refreshed ${newState.messages.length} messages from database`);
log(
`[${operationLogId}][call_tools_batch] Refreshed ${newState.messages.length} messages from database`,
);
// Get the last tool message ID as parentMessageId for next LLM call
const lastToolMessageId = toolMessageIds.at(-1);

View File

@@ -4,6 +4,10 @@ import debug from 'debug';
import { type CloudMCPParams, type ToolCallContent } from '@/libs/mcp';
import { contentBlocksToString } from '@/server/services/mcp/contentProcessor';
import {
DEFAULT_TOOL_RESULT_MAX_LENGTH,
truncateToolResult,
} from '@/server/utils/truncateToolResult';
import { DiscoverService } from '../discover';
import { type MCPService } from '../mcp';
@@ -70,8 +74,26 @@ export class ToolExecutionService {
const executionTime = Date.now() - startTime;
// Truncate result content to prevent context overflow
// Use agent-specific config if provided, otherwise use default
const truncatedContent = truncateToolResult(data.content, context.toolResultMaxLength);
// Log if content was truncated
if (truncatedContent !== data.content) {
const maxLength = context.toolResultMaxLength ?? DEFAULT_TOOL_RESULT_MAX_LENGTH;
log(
'Tool result truncated for %s:%s - original: %d chars, truncated: %d chars (limit: %d)',
identifier,
apiName,
data.content.length,
truncatedContent.length,
maxLength,
);
}
return {
...data,
content: truncatedContent,
executionTime,
};
@@ -79,10 +101,12 @@ export class ToolExecutionService {
} catch (error) {
const executionTime = Date.now() - startTime;
log('Error executing tool %s:%s: %O', identifier, apiName, error);
const errorMessage = (error as Error).message;
return {
content: (error as Error).message,
content: truncateToolResult(errorMessage),
error: {
message: (error as Error).message,
message: errorMessage,
},
executionTime,
success: false,

View File

@@ -6,6 +6,11 @@ export interface ToolExecutionContext {
/** Server database for LobeHub Skills execution */
serverDB?: LobeChatDatabase;
toolManifestMap: Record<string, LobeToolManifest>;
/**
* Maximum length for tool execution result content (in characters)
* @default 6000
*/
toolResultMaxLength?: number;
/** Topic ID for sandbox session management */
topicId?: string;
userId?: string;

View File

@@ -0,0 +1,51 @@
/**
* Shared utility for truncating tool execution results
* Used by both frontend tRPC routers and backend tool execution service
*/
/**
* Default maximum length for tool execution result content (in characters)
* This prevents context overflow when sending results back to LLM
* @default 6000 characters (~1,500 tokens for English, ~3,000 tokens for Chinese)
*/
export const DEFAULT_TOOL_RESULT_MAX_LENGTH = 6000;
/**
* Truncate tool result content if it exceeds the maximum length
* Adds a truncation notice to inform the LLM that content was cut off
*
* @param content - The tool result content to truncate
* @param maxLength - Maximum allowed length (uses default if not provided)
* @returns Truncated content with notice if needed, or original content if within limit
*/
export function truncateToolResult(content: string, maxLength?: number): string {
const limit = maxLength ?? DEFAULT_TOOL_RESULT_MAX_LENGTH;
console.log('content-limit', content, limit);
if (!content || content.length <= limit) {
return content;
}
const truncated = content.slice(0, limit);
const remainingChars = content.length - limit;
// Add truncation notice
const notice = `\n\n[Content truncated: ${remainingChars.toLocaleString()} characters omitted to prevent context overflow. Original length: ${content.length.toLocaleString()} characters]`;
return truncated + notice;
}
/**
* Truncate tool result with state object (for MCP/Cloud MCP tools)
* Truncates the content field while preserving state structure
*/
export function truncateToolResultWithState<T extends { content: string; state?: any }>(
result: T,
maxLength?: number,
): T {
return {
...result,
content: truncateToolResult(result.content, maxLength),
};
}

View File

@@ -1,4 +1,5 @@
import { type MCPToolCallResult } from '@/libs/mcp';
import { truncateToolResult } from '@/server/utils/truncateToolResult';
import { useToolStore } from '@/store/tool';
import { type ChatToolPayload } from '@/types/message';
import { safeParseJSON } from '@/utils/safeParseJSON';
@@ -51,7 +52,7 @@ export const klavisExecutor: RemoteToolExecutor = async (p) => {
const toolResult = result.data;
if (toolResult) {
return {
content: toolResult.content,
content: truncateToolResult(toolResult.content),
error: toolResult.state?.isError ? toolResult.state : undefined,
state: toolResult.state,
success: toolResult.success,
@@ -82,7 +83,9 @@ export const lobehubSkillExecutor: RemoteToolExecutor = async (p) => {
}
// Convert to MCPToolCallResult format
const content = typeof result.data === 'string' ? result.data : JSON.stringify(result.data);
const rawContent = typeof result.data === 'string' ? result.data : JSON.stringify(result.data);
const content = truncateToolResult(rawContent);
return {
content,
error: undefined,

View File

@@ -6,6 +6,7 @@ import { t } from 'i18next';
import { type StateCreator } from 'zustand/vanilla';
import { type MCPToolCallResult } from '@/libs/mcp';
import { truncateToolResult } from '@/server/utils/truncateToolResult';
import { chatService } from '@/services/chat';
import { mcpService } from '@/services/mcp';
import { messageService } from '@/services/message';
@@ -346,6 +347,9 @@ export const pluginTypes: StateCreator<
if (!data) return;
// Truncate content to prevent context overflow
const truncatedContent = truncateToolResult(data.content);
// operationId already declared above, reuse it
const context = operationId ? { operationId } : undefined;
@@ -353,14 +357,14 @@ export const pluginTypes: StateCreator<
await get().optimisticUpdateToolMessage(
id,
{
content: data.content,
content: truncatedContent,
pluginError: data.success ? undefined : data.error,
pluginState: data.success ? data.state : undefined,
},
context,
);
return data.content;
return truncatedContent;
},
internal_invokeRemoteToolPlugin: async (id, payload, executor, logPrefix) => {