mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ 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:
@@ -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(),
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
51
src/server/utils/truncateToolResult.ts
Normal file
51
src/server/utils/truncateToolResult.ts
Normal 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),
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user