Files
lobehub/packages/context-engine/src/engine/messages/MessagesEngine.ts
Shinji-Li 4a47ea0d2f feat: update gtd tools( use editor & update metadata ) (#11029)
* feat: use lobehub editor to modify gtd plan

* merge origin/dev

* feat: show todo in doc portal

* feat: use the todoProcess in docs portal

* feat: add gtd context engine inject
2025-12-29 20:20:11 +08:00

315 lines
10 KiB
TypeScript

/* eslint-disable sort-keys-fix/sort-keys-fix */
import debug from 'debug';
import type { OpenAIChatMessage } from '@/types/index';
import { ContextEngine } from '../../pipeline';
import {
AgentCouncilFlattenProcessor,
GroupMessageFlattenProcessor,
GroupMessageSenderProcessor,
HistoryTruncateProcessor,
InputTemplateProcessor,
MessageCleanupProcessor,
MessageContentProcessor,
PlaceholderVariablesProcessor,
SupervisorRoleRestoreProcessor,
TaskMessageProcessor,
ToolCallProcessor,
ToolMessageReorder,
} from '../../processors';
import {
AgentBuilderContextInjector,
GroupAgentBuilderContextInjector,
GroupContextInjector,
GTDPlanInjector,
GTDTodoInjector,
HistorySummaryProvider,
KnowledgeInjector,
PageEditorContextInjector,
SystemRoleInjector,
ToolSystemRoleProvider,
UserMemoryInjector,
} from '../../providers';
import type { ContextProcessor } from '../../types';
import { ToolNameResolver } from '../tools';
import type { MessagesEngineParams, MessagesEngineResult } from './types';
const log = debug('context-engine:MessagesEngine');
/**
* MessagesEngine - High-level message processing engine
*
* This is a convenience wrapper around ContextEngine that provides
* a pre-configured pipeline for common message processing scenarios.
* It can be used by both frontend and backend through dependency injection.
*
* @example
* ```typescript
* const engine = new MessagesEngine({
* messages,
* model: 'gpt-4',
* provider: 'openai',
* systemRole: 'You are a helpful assistant',
* capabilities: {
* isCanUseFC: (m, p) => true,
* isCanUseVision: (m, p) => true,
* },
* });
*
* const result = await engine.process();
* console.log(result.messages);
* ```
*/
export class MessagesEngine {
private params: MessagesEngineParams;
private toolNameResolver: ToolNameResolver;
constructor(params: MessagesEngineParams) {
this.params = params;
this.toolNameResolver = new ToolNameResolver();
}
/**
* Process messages and return OpenAI-compatible format
*/
async process(): Promise<MessagesEngineResult> {
const pipeline = this.buildPipeline();
const result = await pipeline.process({ messages: this.params.messages });
return {
messages: result.messages as OpenAIChatMessage[],
metadata: result.metadata,
stats: result.stats,
};
}
/**
* Process messages and return only the messages array
* This is a convenience method for simpler use cases
*/
async processMessages(): Promise<OpenAIChatMessage[]> {
const result = await this.process();
return result.messages;
}
/**
* Build the processing pipeline based on configuration
*/
private buildPipeline(): ContextEngine {
const processors = this.buildProcessors();
log(`Built pipeline with ${processors.length} processors`);
return new ContextEngine({ pipeline: processors });
}
/**
* Build the list of processors based on configuration
*/
private buildProcessors(): ContextProcessor[] {
const {
model,
provider,
systemRole,
inputTemplate,
enableHistoryCount,
historyCount,
historySummary,
formatHistorySummary,
knowledge,
toolsConfig,
capabilities,
variableGenerators,
fileContext,
agentBuilderContext,
groupAgentBuilderContext,
agentGroup,
gtd,
userMemory,
initialContext,
stepContext,
pageContentContext,
} = this.params;
const isAgentBuilderEnabled = !!agentBuilderContext;
const isGroupAgentBuilderEnabled = !!groupAgentBuilderContext;
const isAgentGroupEnabled = agentGroup?.agentMap && Object.keys(agentGroup.agentMap).length > 0;
const isGroupContextEnabled =
isAgentGroupEnabled || !!agentGroup?.currentAgentId || !!agentGroup?.members;
const isUserMemoryEnabled = userMemory?.enabled && userMemory?.memories;
// Page editor is enabled if either direct pageContentContext or initialContext.pageEditor is provided
const isPageEditorEnabled = !!pageContentContext || !!initialContext?.pageEditor;
// GTD is enabled if gtd.enabled is true and either plan or todos is provided
const isGTDPlanEnabled = gtd?.enabled && gtd?.plan;
const isGTDTodoEnabled = gtd?.enabled && gtd?.todos;
return [
// =============================================
// Phase 1: History Management
// =============================================
// 1. History truncation (MUST be first, before any message injection)
new HistoryTruncateProcessor({
enableHistoryCount,
historyCount,
}),
// =============================================
// Phase 2: System Role Injection
// =============================================
// 2. System role injection (agent's system role)
new SystemRoleInjector({ systemRole }),
// 3. Group context injection (agent identity and group info for multi-agent chat)
new GroupContextInjector({
currentAgentId: agentGroup?.currentAgentId,
currentAgentName: agentGroup?.currentAgentName,
currentAgentRole: agentGroup?.currentAgentRole,
enabled: isGroupContextEnabled,
groupTitle: agentGroup?.groupTitle,
members: agentGroup?.members,
systemPrompt: agentGroup?.systemPrompt,
}),
// =============================================
// Phase 2.5: First User Message Context Injection
// These providers inject content before the first user message
// Order matters: first executed = first in content
// =============================================
// 4. User memory injection (conditionally added, injected first)
...(isUserMemoryEnabled ? [new UserMemoryInjector(userMemory)] : []),
// 4.5. GTD Plan injection (conditionally added, after user memory, before knowledge)
...(isGTDPlanEnabled
? [new GTDPlanInjector({ enabled: true, plan: gtd.plan })]
: []),
// 5. Knowledge injection (full content for agent files + metadata for knowledge bases)
new KnowledgeInjector({
fileContents: knowledge?.fileContents,
knowledgeBases: knowledge?.knowledgeBases,
}),
// =============================================
// Phase 2.6: Additional System Context
// =============================================
// 6. Agent Builder context injection (current agent config/meta for editing)
new AgentBuilderContextInjector({
enabled: isAgentBuilderEnabled,
agentContext: agentBuilderContext,
}),
// 7. Group Agent Builder context injection (current group config/members for editing)
new GroupAgentBuilderContextInjector({
enabled: isGroupAgentBuilderEnabled,
groupContext: groupAgentBuilderContext,
}),
// 8. Tool system role injection (conditionally added)
...(toolsConfig?.manifests && toolsConfig.manifests.length > 0
? [
new ToolSystemRoleProvider({
isCanUseFC: capabilities?.isCanUseFC || (() => true),
manifests: toolsConfig.manifests,
model,
provider,
}),
]
: []),
// 9. History summary injection
new HistorySummaryProvider({
formatHistorySummary,
historySummary,
}),
// 10. Page Editor context injection
new PageEditorContextInjector({
enabled: isPageEditorEnabled,
// Use direct pageContentContext if provided (server-side), otherwise build from initialContext + stepContext (frontend)
pageContentContext: pageContentContext
? pageContentContext
: initialContext?.pageEditor
? {
markdown: initialContext.pageEditor.markdown,
metadata: {
charCount: initialContext.pageEditor.metadata.charCount,
lineCount: initialContext.pageEditor.metadata.lineCount,
title: initialContext.pageEditor.metadata.title,
},
// Use latest XML from stepContext if available, otherwise fallback to initial XML
xml: stepContext?.stepPageEditor?.xml || initialContext.pageEditor.xml,
}
: undefined,
}),
// 10.5. GTD Todo injection (conditionally added, at end of last user message)
...(isGTDTodoEnabled
? [new GTDTodoInjector({ enabled: true, todos: gtd.todos })]
: []),
// =============================================
// Phase 3: Message Transformation
// =============================================
// 11. Input template processing
new InputTemplateProcessor({ inputTemplate }),
// 11. Placeholder variables processing
new PlaceholderVariablesProcessor({
variableGenerators: variableGenerators || {},
}),
// 12. AgentCouncil message flatten (convert role=agentCouncil to standard assistant + tool messages)
new AgentCouncilFlattenProcessor(),
// 13. Group message flatten (convert role=assistantGroup to standard assistant + tool messages)
new GroupMessageFlattenProcessor(),
// 14. Task message processing (convert role=task to assistant with instruction + content)
new TaskMessageProcessor(),
// 15. Supervisor role restore (convert role=supervisor back to role=assistant for model)
new SupervisorRoleRestoreProcessor(),
// 16. Group message sender identity injection (for multi-agent chat)
...(isAgentGroupEnabled
? [
new GroupMessageSenderProcessor({
agentMap: agentGroup.agentMap!,
}),
]
: []),
// =============================================
// Phase 4: Content Processing
// =============================================
// 17. Message content processing (image encoding, etc.)
new MessageContentProcessor({
fileContext: fileContext || { enabled: true, includeFileUrl: true },
isCanUseVideo: capabilities?.isCanUseVideo || (() => false),
isCanUseVision: capabilities?.isCanUseVision || (() => true),
model,
provider,
}),
// 18. Tool call processing
new ToolCallProcessor({
genToolCallingName: this.toolNameResolver.generate.bind(this.toolNameResolver),
isCanUseFC: capabilities?.isCanUseFC || (() => true),
model,
provider,
}),
// 19. Tool message reordering
new ToolMessageReorder(),
// 20. Message cleanup (final step, keep only necessary fields)
new MessageCleanupProcessor(),
];
}
}