mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
🐛 fix: fixed compressed group message & open the switch config to control compression config enabled (#11901)
* fix: fixed the compressed cause the parentid not found problem * feat: add the compressionConfig config as switch * fix: slove the onboarding modelSelect Crash error * fix: rollback the modelSelectChange
This commit is contained in:
@@ -446,6 +446,8 @@
|
||||
"settingImage.defaultCount.desc": "Set the default number of images generated when creating a new task in the image generation panel.",
|
||||
"settingImage.defaultCount.label": "Default Image Count",
|
||||
"settingImage.defaultCount.title": "AI Art",
|
||||
"settingModel.enableContextCompression.desc": "Automatically compress historical messages into summaries when conversation exceeds 64,000 tokens, saving 60-80% token usage",
|
||||
"settingModel.enableContextCompression.title": "Enable Auto Context Compression",
|
||||
"settingModel.enableMaxTokens.title": "Enable Max Tokens Limit",
|
||||
"settingModel.enableReasoningEffort.title": "Enable Reasoning Effort Adjustment",
|
||||
"settingModel.frequencyPenalty.desc": "The higher the value, the more diverse and rich the vocabulary; the lower the value, the simpler and more straightforward the language.",
|
||||
|
||||
@@ -446,6 +446,8 @@
|
||||
"settingImage.defaultCount.desc": "设置图像生成面板在创建新任务时的默认图片数量。",
|
||||
"settingImage.defaultCount.label": "默认图片数量",
|
||||
"settingImage.defaultCount.title": "AI 绘画设置",
|
||||
"settingModel.enableContextCompression.desc": "当对话消息超过 64,000 tokens 时,自动将历史消息压缩为摘要,节省 60-80% 的 token 用量",
|
||||
"settingModel.enableContextCompression.title": "开启自动上下文压缩",
|
||||
"settingModel.enableMaxTokens.title": "开启单次回复限制",
|
||||
"settingModel.enableReasoningEffort.title": "开启推理强度调整",
|
||||
"settingModel.frequencyPenalty.desc": "值越大,用词越丰富多样;值越低,用词更朴实简单",
|
||||
|
||||
@@ -328,7 +328,7 @@
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-html": "^16.0.1",
|
||||
"remove-markdown": "^0.6.3",
|
||||
"resend": "^6.8.0",
|
||||
"resend": "6.8.0",
|
||||
"resolve-accept-language": "^3.1.15",
|
||||
"rtl-detect": "^1.1.2",
|
||||
"semver": "^7.7.3",
|
||||
|
||||
@@ -283,21 +283,25 @@ export class GeneralChatAgent implements Agent {
|
||||
switch (context.phase) {
|
||||
case 'init':
|
||||
case 'user_input': {
|
||||
// Check if context compression is needed before calling LLM
|
||||
const compressionCheck = shouldCompress(state.messages, {
|
||||
maxWindowToken: this.config.compressionConfig?.maxWindowToken,
|
||||
});
|
||||
// Check if context compression is enabled and needed before calling LLM
|
||||
const compressionEnabled = this.config.compressionConfig?.enabled ?? true; // Default to enabled
|
||||
|
||||
if (compressionCheck.needsCompression) {
|
||||
// Context exceeds threshold, compress ALL messages into a single summary
|
||||
return {
|
||||
payload: {
|
||||
currentTokenCount: compressionCheck.currentTokenCount,
|
||||
existingSummary: this.findExistingSummary(state.messages),
|
||||
messages: state.messages,
|
||||
},
|
||||
type: 'compress_context',
|
||||
} as AgentInstructionCompressContext;
|
||||
if (compressionEnabled) {
|
||||
const compressionCheck = shouldCompress(state.messages, {
|
||||
maxWindowToken: this.config.compressionConfig?.maxWindowToken,
|
||||
});
|
||||
|
||||
if (compressionCheck.needsCompression) {
|
||||
// Context exceeds threshold, compress ALL messages into a single summary
|
||||
return {
|
||||
payload: {
|
||||
currentTokenCount: compressionCheck.currentTokenCount,
|
||||
existingSummary: this.findExistingSummary(state.messages),
|
||||
messages: state.messages,
|
||||
},
|
||||
type: 'compress_context',
|
||||
} as AgentInstructionCompressContext;
|
||||
}
|
||||
}
|
||||
|
||||
// User input received, call LLM to generate response
|
||||
|
||||
@@ -69,16 +69,15 @@ export interface GeneralAgentConfig {
|
||||
};
|
||||
/**
|
||||
* Context compression configuration
|
||||
* Note: Compression checking is always enabled to prevent context overflow.
|
||||
* When triggered, ALL messages are compressed into a single MessageGroup summary.
|
||||
* When enabled and triggered, ALL messages are compressed into a single MessageGroup summary.
|
||||
*/
|
||||
compressionConfig?: {
|
||||
/** Whether context compression is enabled (default: true) */
|
||||
enabled?: boolean;
|
||||
/** Model's max context window token count (default: 128k) */
|
||||
maxWindowToken?: number;
|
||||
};
|
||||
modelRuntimeConfig?: {
|
||||
model: string;
|
||||
provider: string;
|
||||
/**
|
||||
* Compression model configuration
|
||||
* Used for context compression tasks
|
||||
@@ -87,6 +86,8 @@ export interface GeneralAgentConfig {
|
||||
model: string;
|
||||
provider: string;
|
||||
};
|
||||
model: string;
|
||||
provider: string;
|
||||
};
|
||||
operationId: string;
|
||||
userId?: string;
|
||||
|
||||
@@ -320,7 +320,23 @@ const Controls = memo<ControlsProps>(({ setUpdating }) => {
|
||||
: []),
|
||||
];
|
||||
|
||||
const allItems = [...baseItems, ...maxTokensItems];
|
||||
// Context Compression items
|
||||
const contextCompressionItems: FormItemProps[] = [
|
||||
{
|
||||
children: <Switch />,
|
||||
label: (
|
||||
<Flexbox align={'center'} className={styles.label} gap={8} horizontal>
|
||||
{t('settingModel.enableContextCompression.title')}
|
||||
<InfoTooltip title={t('settingModel.enableContextCompression.desc')} />
|
||||
</Flexbox>
|
||||
),
|
||||
name: ['chatConfig', 'enableContextCompression'],
|
||||
tag: 'compression',
|
||||
valuePropName: 'checked',
|
||||
},
|
||||
];
|
||||
|
||||
const allItems = [...baseItems, ...maxTokensItems, ...contextCompressionItems];
|
||||
|
||||
return (
|
||||
<Form
|
||||
|
||||
@@ -501,6 +501,9 @@ export default {
|
||||
'Set the default number of images generated when creating a new task in the image generation panel.',
|
||||
'settingImage.defaultCount.label': 'Default Image Count',
|
||||
'settingImage.defaultCount.title': 'AI Art',
|
||||
'settingModel.enableContextCompression.desc':
|
||||
'Automatically compress historical messages into summaries when conversation exceeds 64,000 tokens, saving 60-80% token usage',
|
||||
'settingModel.enableContextCompression.title': 'Enable Auto Context Compression',
|
||||
'settingModel.enableMaxTokens.title': 'Enable Max Tokens Limit',
|
||||
'settingModel.enableReasoningEffort.title': 'Enable Reasoning Effort Adjustment',
|
||||
'settingModel.frequencyPenalty.desc':
|
||||
|
||||
@@ -126,8 +126,7 @@ export class AgentRuntimeService {
|
||||
*/
|
||||
private stepCallbacks: Map<string, StepLifecycleCallbacks> = new Map();
|
||||
private get baseURL() {
|
||||
const baseUrl =
|
||||
process.env.AGENT_RUNTIME_BASE_URL || appEnv.APP_URL || 'http://localhost:3010';
|
||||
const baseUrl = process.env.AGENT_RUNTIME_BASE_URL || appEnv.APP_URL || 'http://localhost:3010';
|
||||
|
||||
return urlJoin(baseUrl, '/api/agent');
|
||||
}
|
||||
@@ -840,6 +839,9 @@ export class AgentRuntimeService {
|
||||
// Create Durable Agent instance
|
||||
const agent = new GeneralChatAgent({
|
||||
agentConfig: metadata?.agentConfig,
|
||||
compressionConfig: {
|
||||
enabled: metadata?.agentConfig?.chatConfig?.enableContextCompression ?? true,
|
||||
},
|
||||
modelRuntimeConfig: metadata?.modelRuntimeConfig,
|
||||
operationId,
|
||||
userId: metadata?.userId,
|
||||
|
||||
@@ -702,6 +702,9 @@ export const streamingExecutor: StateCreator<
|
||||
|
||||
const agent = new GeneralChatAgent({
|
||||
agentConfig: { maxSteps: 1000 },
|
||||
compressionConfig: {
|
||||
enabled: agentConfigData.chatConfig?.enableContextCompression ?? true, // Default to enabled
|
||||
},
|
||||
operationId: `${messageKey}/${params.parentMessageId}`,
|
||||
modelRuntimeConfig,
|
||||
});
|
||||
|
||||
@@ -833,5 +833,26 @@ describe('displayMessageSelectors', () => {
|
||||
const result = displayMessageSelectors.findLastMessageId('msg-1')(state as ChatStore);
|
||||
expect(result).toBe('tool-result-id');
|
||||
});
|
||||
|
||||
it('should return lastMessageId for compressedGroup instead of group id', () => {
|
||||
const compressedGroupMessage = {
|
||||
id: 'mg_123456',
|
||||
role: 'compressedGroup',
|
||||
content: 'Compressed summary',
|
||||
lastMessageId: 'msg-999',
|
||||
compressedMessages: [],
|
||||
pinnedMessages: [],
|
||||
} as unknown as UIChatMessage;
|
||||
|
||||
const state: Partial<ChatStore> = {
|
||||
activeAgentId: 'test-id',
|
||||
messagesMap: {
|
||||
[messageMapKey({ agentId: 'test-id' })]: [compressedGroupMessage],
|
||||
},
|
||||
};
|
||||
|
||||
const result = displayMessageSelectors.findLastMessageId('mg_123456')(state as ChatStore);
|
||||
expect(result).toBe('msg-999');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -247,7 +247,7 @@ const findLastBlockId = (block: AssistantContentBlock | undefined): string | und
|
||||
|
||||
/**
|
||||
* Recursively finds the last message ID in a message tree
|
||||
* Priority: children > tools > self
|
||||
* Priority: children > tools > compressedGroup.lastMessageId > self
|
||||
*/
|
||||
const findLastMessageIdRecursive = (node: UIChatMessage | undefined): string | undefined => {
|
||||
if (!node) return undefined;
|
||||
@@ -264,7 +264,12 @@ const findLastMessageIdRecursive = (node: UIChatMessage | undefined): string | u
|
||||
return lastTool?.result_msg_id;
|
||||
}
|
||||
|
||||
// Priority 3: Return self ID
|
||||
// Priority 3: For compressedGroup, return lastMessageId instead of group ID
|
||||
if (node.role === 'compressedGroup' && 'lastMessageId' in node) {
|
||||
return (node as any).lastMessageId;
|
||||
}
|
||||
|
||||
// Priority 4: Return self ID
|
||||
return node.id;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user