@lobehub/lobehub 2.0.0-next.31 → 2.0.0-next.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/test.yml +1 -0
- package/CHANGELOG.md +58 -0
- package/apps/desktop/package.json +1 -1
- package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +23 -2
- package/changelog/v1.json +21 -0
- package/docker-compose/local/.env.example +3 -0
- package/docs/self-hosting/server-database/docker-compose.mdx +29 -0
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +29 -0
- package/package.json +1 -1
- package/packages/const/src/hotkeys.ts +3 -3
- package/packages/const/src/models.ts +2 -2
- package/packages/const/src/utils/merge.ts +3 -3
- package/packages/conversation-flow/package.json +13 -0
- package/packages/conversation-flow/src/__tests__/fixtures/index.ts +48 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/assistant-chain-with-followup.json +56 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/assistant-with-tools.json +144 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/active-index-1.json +131 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-branch.json +96 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-user-branch.json +123 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/conversation.json +128 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/index.ts +14 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/nested.json +179 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/compare/index.ts +8 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/compare/simple.json +85 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/compare/with-tools.json +169 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/complex-scenario.json +107 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/index.ts +14 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/linear-conversation.json +59 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistant-chain-with-followup.json +135 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistant-with-tools.json +340 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/active-index-1.json +242 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-branch.json +208 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-user-branch.json +254 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/conversation.json +260 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/index.ts +14 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/nested.json +389 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/compare/index.ts +8 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/compare/simple.json +224 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/compare/with-tools.json +418 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/complex-scenario.json +239 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/linear-conversation.json +138 -0
- package/packages/conversation-flow/src/__tests__/parse.test.ts +97 -0
- package/packages/conversation-flow/src/index.ts +17 -0
- package/packages/conversation-flow/src/indexing.ts +58 -0
- package/packages/conversation-flow/src/parse.ts +53 -0
- package/packages/conversation-flow/src/structuring.ts +38 -0
- package/packages/conversation-flow/src/transformation/BranchResolver.ts +66 -0
- package/packages/conversation-flow/src/transformation/ContextTreeBuilder.ts +292 -0
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +421 -0
- package/packages/conversation-flow/src/transformation/MessageCollector.ts +166 -0
- package/packages/conversation-flow/src/transformation/MessageTransformer.ts +177 -0
- package/packages/conversation-flow/src/transformation/__tests__/BranchResolver.test.ts +151 -0
- package/packages/conversation-flow/src/transformation/__tests__/ContextTreeBuilder.test.ts +385 -0
- package/packages/conversation-flow/src/transformation/__tests__/FlatListBuilder.test.ts +511 -0
- package/packages/conversation-flow/src/transformation/__tests__/MessageCollector.test.ts +220 -0
- package/packages/conversation-flow/src/transformation/__tests__/MessageTransformer.test.ts +287 -0
- package/packages/conversation-flow/src/transformation/index.ts +78 -0
- package/packages/conversation-flow/src/types/contextTree.ts +65 -0
- package/packages/conversation-flow/src/types/flatMessageList.ts +66 -0
- package/packages/conversation-flow/src/types/shared.ts +63 -0
- package/packages/conversation-flow/src/types.ts +36 -0
- package/packages/conversation-flow/vitest.config.mts +10 -0
- package/packages/types/src/message/common/metadata.ts +5 -1
- package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/index.tsx +3 -4
- package/src/envs/__tests__/app.test.ts +47 -13
- package/src/envs/app.ts +6 -0
- package/src/server/modules/S3/index.test.ts +379 -0
- package/src/server/routers/async/__tests__/caller.test.ts +333 -0
- package/src/server/routers/async/caller.ts +2 -1
- package/src/server/routers/lambda/__tests__/integration/message.integration.test.ts +57 -57
- package/src/server/routers/lambda/message.ts +2 -2
- package/src/server/services/message/__tests__/index.test.ts +4 -4
- package/src/server/services/message/index.ts +1 -1
- package/src/services/message/index.ts +2 -3
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +8 -8
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +8 -8
- package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +1 -1
- package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +1 -1
- package/src/store/chat/slices/message/action.test.ts +7 -7
- package/src/store/chat/slices/message/action.ts +2 -2
- package/src/store/chat/slices/plugin/action.test.ts +7 -7
- package/src/store/chat/slices/plugin/action.ts +1 -1
- package/packages/context-engine/ARCHITECTURE.md +0 -425
|
@@ -131,7 +131,7 @@ describe('generateAIChatV2 actions', () => {
|
|
|
131
131
|
await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
-
expect(messageService.
|
|
134
|
+
expect(messageService.createMessage).not.toHaveBeenCalled();
|
|
135
135
|
expect(result.current.internal_execAgentRuntime).not.toHaveBeenCalled();
|
|
136
136
|
});
|
|
137
137
|
|
|
@@ -142,7 +142,7 @@ describe('generateAIChatV2 actions', () => {
|
|
|
142
142
|
await result.current.sendMessage({ message: TEST_CONTENT.EMPTY });
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
expect(messageService.
|
|
145
|
+
expect(messageService.createMessage).not.toHaveBeenCalled();
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
it('should not send when message is empty with empty files array', async () => {
|
|
@@ -152,7 +152,7 @@ describe('generateAIChatV2 actions', () => {
|
|
|
152
152
|
await result.current.sendMessage({ message: TEST_CONTENT.EMPTY, files: [] });
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
expect(messageService.
|
|
155
|
+
expect(messageService.createMessage).not.toHaveBeenCalled();
|
|
156
156
|
});
|
|
157
157
|
});
|
|
158
158
|
|
|
@@ -312,7 +312,7 @@ describe('generateAIChatV2 actions', () => {
|
|
|
312
312
|
});
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
-
expect(messageService.
|
|
315
|
+
expect(messageService.createMessage).toHaveBeenCalled();
|
|
316
316
|
expect(result.current.internal_execAgentRuntime).not.toHaveBeenCalled();
|
|
317
317
|
});
|
|
318
318
|
|
|
@@ -749,7 +749,7 @@ describe('generateAIChatV2 actions', () => {
|
|
|
749
749
|
|
|
750
750
|
beforeEach(() => {
|
|
751
751
|
// Reset mocks
|
|
752
|
-
vi.spyOn(messageService, '
|
|
752
|
+
vi.spyOn(messageService, 'createMessage').mockResolvedValue({
|
|
753
753
|
id: 'new-assistant-block-id',
|
|
754
754
|
messages: [] as any,
|
|
755
755
|
});
|
|
@@ -814,8 +814,8 @@ describe('generateAIChatV2 actions', () => {
|
|
|
814
814
|
}),
|
|
815
815
|
);
|
|
816
816
|
|
|
817
|
-
// Verify that
|
|
818
|
-
expect(messageService.
|
|
817
|
+
// Verify that createMessage was called with message params
|
|
818
|
+
expect(messageService.createMessage).toHaveBeenCalledWith(
|
|
819
819
|
expect.objectContaining({
|
|
820
820
|
role: 'assistant',
|
|
821
821
|
parentId: TOOL_RESULT_MSG_ID,
|
|
@@ -866,7 +866,7 @@ describe('generateAIChatV2 actions', () => {
|
|
|
866
866
|
}),
|
|
867
867
|
);
|
|
868
868
|
|
|
869
|
-
expect(messageService.
|
|
869
|
+
expect(messageService.createMessage).toHaveBeenCalledWith(
|
|
870
870
|
expect.objectContaining({
|
|
871
871
|
role: 'assistant',
|
|
872
872
|
parentId: 'non-existent-tool-result-id',
|
|
@@ -58,7 +58,7 @@ export const createMockAbortController = () => {
|
|
|
58
58
|
*/
|
|
59
59
|
export const spyOnMessageService = () => {
|
|
60
60
|
const createMessageSpy = vi
|
|
61
|
-
.spyOn(messageService, '
|
|
61
|
+
.spyOn(messageService, 'createMessage')
|
|
62
62
|
.mockResolvedValue({ id: TEST_IDS.NEW_MESSAGE_ID, messages: [] });
|
|
63
63
|
const updateMessageSpy = vi
|
|
64
64
|
.spyOn(messageService, 'updateMessage')
|
|
@@ -25,7 +25,7 @@ vi.mock('@/services/message', () => ({
|
|
|
25
25
|
removeMessage: vi.fn(),
|
|
26
26
|
removeMessagesByAssistant: vi.fn(),
|
|
27
27
|
removeMessages: vi.fn(() => Promise.resolve()),
|
|
28
|
-
|
|
28
|
+
createMessage: vi.fn(() => Promise.resolve({ id: 'new-message-id', messages: [] })),
|
|
29
29
|
updateMessage: vi.fn(),
|
|
30
30
|
removeAllMessages: vi.fn(() => Promise.resolve()),
|
|
31
31
|
},
|
|
@@ -71,7 +71,7 @@ describe('chatMessage actions', () => {
|
|
|
71
71
|
await result.current.addAIMessage();
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
expect(messageService.
|
|
74
|
+
expect(messageService.createMessage).not.toHaveBeenCalled();
|
|
75
75
|
expect(updateInputMessageSpy).not.toHaveBeenCalled();
|
|
76
76
|
});
|
|
77
77
|
|
|
@@ -84,7 +84,7 @@ describe('chatMessage actions', () => {
|
|
|
84
84
|
await result.current.addAIMessage();
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
expect(messageService.
|
|
87
|
+
expect(messageService.createMessage).toHaveBeenCalledWith({
|
|
88
88
|
content: inputMessage,
|
|
89
89
|
role: 'assistant',
|
|
90
90
|
sessionId: mockState.activeId,
|
|
@@ -113,7 +113,7 @@ describe('chatMessage actions', () => {
|
|
|
113
113
|
await result.current.addUserMessage({ message: 'test message' });
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
expect(messageService.
|
|
116
|
+
expect(messageService.createMessage).not.toHaveBeenCalled();
|
|
117
117
|
expect(updateInputMessageSpy).not.toHaveBeenCalled();
|
|
118
118
|
});
|
|
119
119
|
|
|
@@ -130,7 +130,7 @@ describe('chatMessage actions', () => {
|
|
|
130
130
|
await result.current.addUserMessage({ message, fileList });
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
-
expect(messageService.
|
|
133
|
+
expect(messageService.createMessage).toHaveBeenCalledWith({
|
|
134
134
|
content: message,
|
|
135
135
|
files: fileList,
|
|
136
136
|
role: 'user',
|
|
@@ -154,7 +154,7 @@ describe('chatMessage actions', () => {
|
|
|
154
154
|
await result.current.addUserMessage({ message });
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
expect(messageService.
|
|
157
|
+
expect(messageService.createMessage).toHaveBeenCalledWith({
|
|
158
158
|
content: message,
|
|
159
159
|
files: undefined,
|
|
160
160
|
role: 'user',
|
|
@@ -184,7 +184,7 @@ describe('chatMessage actions', () => {
|
|
|
184
184
|
await result.current.addUserMessage({ message });
|
|
185
185
|
});
|
|
186
186
|
|
|
187
|
-
expect(messageService.
|
|
187
|
+
expect(messageService.createMessage).toHaveBeenCalledWith({
|
|
188
188
|
content: message,
|
|
189
189
|
files: undefined,
|
|
190
190
|
role: 'user',
|
|
@@ -519,10 +519,10 @@ export const chatMessage: StateCreator<
|
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
try {
|
|
522
|
-
const result = await messageService.
|
|
522
|
+
const result = await messageService.createMessage(message);
|
|
523
523
|
|
|
524
524
|
if (!context?.skipRefresh) {
|
|
525
|
-
// Use the messages returned from
|
|
525
|
+
// Use the messages returned from createMessage (already grouped)
|
|
526
526
|
replaceMessages(result.messages);
|
|
527
527
|
}
|
|
528
528
|
|
|
@@ -26,7 +26,7 @@ vi.mock('@/services/message', () => ({
|
|
|
26
26
|
updateMessageError: vi.fn(),
|
|
27
27
|
updateMessagePluginState: vi.fn(),
|
|
28
28
|
updateMessagePluginArguments: vi.fn(),
|
|
29
|
-
|
|
29
|
+
createMessage: vi.fn(),
|
|
30
30
|
},
|
|
31
31
|
}));
|
|
32
32
|
|
|
@@ -565,8 +565,8 @@ describe('ChatPluginAction', () => {
|
|
|
565
565
|
describe('createAssistantMessageByPlugin', () => {
|
|
566
566
|
it('should create an assistant message and replace messages', async () => {
|
|
567
567
|
const mockMessages = [{ id: 'msg-1', content: 'test' }] as any;
|
|
568
|
-
// 模拟 messageService.
|
|
569
|
-
(messageService.
|
|
568
|
+
// 模拟 messageService.createMessage 方法的实现
|
|
569
|
+
(messageService.createMessage as Mock).mockResolvedValue({
|
|
570
570
|
id: 'new-message-id',
|
|
571
571
|
messages: mockMessages,
|
|
572
572
|
});
|
|
@@ -588,8 +588,8 @@ describe('ChatPluginAction', () => {
|
|
|
588
588
|
await result.current.createAssistantMessageByPlugin(content, parentId);
|
|
589
589
|
});
|
|
590
590
|
|
|
591
|
-
// 验证 messageService.
|
|
592
|
-
expect(messageService.
|
|
591
|
+
// 验证 messageService.createMessage 是否被带有正确参数调用
|
|
592
|
+
expect(messageService.createMessage).toHaveBeenCalledWith({
|
|
593
593
|
content,
|
|
594
594
|
parentId,
|
|
595
595
|
role: 'assistant',
|
|
@@ -604,7 +604,7 @@ describe('ChatPluginAction', () => {
|
|
|
604
604
|
it('should handle errors when message creation fails', async () => {
|
|
605
605
|
// 模拟 messageService.create 方法,使其抛出错误
|
|
606
606
|
const errorMessage = 'Failed to create message';
|
|
607
|
-
(messageService.
|
|
607
|
+
(messageService.createMessage as Mock).mockRejectedValue(new Error(errorMessage));
|
|
608
608
|
|
|
609
609
|
// 设置初始状态并模拟 refreshMessages 方法
|
|
610
610
|
const initialState = {
|
|
@@ -626,7 +626,7 @@ describe('ChatPluginAction', () => {
|
|
|
626
626
|
});
|
|
627
627
|
|
|
628
628
|
// 验证 messageService.create 是否被带有正确参数调用
|
|
629
|
-
expect(messageService.
|
|
629
|
+
expect(messageService.createMessage).toHaveBeenCalledWith({
|
|
630
630
|
content,
|
|
631
631
|
parentId,
|
|
632
632
|
role: 'assistant',
|
|
@@ -98,7 +98,7 @@ export const chatPlugin: StateCreator<
|
|
|
98
98
|
topicId: get().activeTopicId, // if there is activeTopicId,then add it to topicId
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
-
const result = await messageService.
|
|
101
|
+
const result = await messageService.createMessage(newMessage);
|
|
102
102
|
get().replaceMessages(result.messages);
|
|
103
103
|
},
|
|
104
104
|
|
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
# Context Engine 架构设计
|
|
2
|
-
|
|
3
|
-
## 概述
|
|
4
|
-
|
|
5
|
-
Context Engine 是一个灵活的消息处理管道系统,用于在 AI 对话中动态管理和处理上下文信息。它提供了一种可扩展的方式来注入、转换和验证消息流。
|
|
6
|
-
|
|
7
|
-
## 核心概念
|
|
8
|
-
|
|
9
|
-
### 1. 处理器(Processor)
|
|
10
|
-
|
|
11
|
-
处理器是 Context Engine 的基本单元,负责对消息进行特定的处理操作。
|
|
12
|
-
|
|
13
|
-
#### 处理器分类
|
|
14
|
-
|
|
15
|
-
根据功能职责,处理器分为以下几类:
|
|
16
|
-
|
|
17
|
-
1. **注入器(Injector)**
|
|
18
|
-
- 职责:向消息流中添加新的上下文信息
|
|
19
|
-
- 示例:SystemRoleInjector、HistoryInjector、RAGContextInjector
|
|
20
|
-
|
|
21
|
-
2. **转换器(Transformer)**
|
|
22
|
-
- 职责:修改现有消息的内容或结构
|
|
23
|
-
- 示例:MessageRoleTransformer、ImageContentProcessor
|
|
24
|
-
|
|
25
|
-
3. **截断器(Truncator)**
|
|
26
|
-
- 职责:根据特定规则裁剪消息内容
|
|
27
|
-
- 示例:HistoryTruncator、TokenBasedTruncator
|
|
28
|
-
|
|
29
|
-
4. **验证器(Validator)**
|
|
30
|
-
- 职责:验证消息是否符合特定要求
|
|
31
|
-
- 示例:ModelCapabilityValidator
|
|
32
|
-
|
|
33
|
-
5. **重排器(Reorderer)**
|
|
34
|
-
- 职责:调整消息的顺序
|
|
35
|
-
- 示例:ToolMessageReorder
|
|
36
|
-
|
|
37
|
-
### 2. 管道(Pipeline)
|
|
38
|
-
|
|
39
|
-
管道是一系列处理器的有序组合,消息流经管道时会被逐个处理器处理。
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
interface Pipeline {
|
|
43
|
-
// 添加处理器到管道
|
|
44
|
-
add(processor: BaseProcessor): Pipeline;
|
|
45
|
-
|
|
46
|
-
// 执行管道处理
|
|
47
|
-
execute(context: ProcessorContext): Promise<ProcessorContext>;
|
|
48
|
-
|
|
49
|
-
// 获取管道中的所有处理器
|
|
50
|
-
getProcessors(): BaseProcessor[];
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 3. 上下文(Context)
|
|
55
|
-
|
|
56
|
-
上下文包含了处理器需要的所有信息:
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
interface ProcessorContext {
|
|
60
|
-
messages: Message[]; // 消息列表
|
|
61
|
-
metadata?: ProcessorMetadata; // 元数据
|
|
62
|
-
variables?: Record<string, any>; // 变量
|
|
63
|
-
abortSignal?: AbortSignal; // 中止信号
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## 架构设计
|
|
68
|
-
|
|
69
|
-
### 类层次结构
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
BaseProcessor (抽象基类)
|
|
73
|
-
├── BaseInjector (注入器基类)
|
|
74
|
-
│ ├── SystemRoleInjector
|
|
75
|
-
│ ├── HistoryInjector
|
|
76
|
-
│ ├── RAGContextInjector
|
|
77
|
-
│ └── ...
|
|
78
|
-
├── BaseTransformer (转换器基类)
|
|
79
|
-
│ ├── MessageRoleTransformer
|
|
80
|
-
│ └── ImageContentProcessor
|
|
81
|
-
├── BaseTruncator (截断器基类)
|
|
82
|
-
│ ├── HistoryTruncator
|
|
83
|
-
│ └── TokenBasedTruncator
|
|
84
|
-
├── BaseValidator (验证器基类)
|
|
85
|
-
│ └── ModelCapabilityValidator
|
|
86
|
-
└── BaseReorderer (重排器基类)
|
|
87
|
-
└── ToolMessageReorder
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 核心接口设计
|
|
91
|
-
|
|
92
|
-
#### BaseProcessor
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
abstract class BaseProcessor {
|
|
96
|
-
// 处理器类型
|
|
97
|
-
abstract readonly type: ProcessorType;
|
|
98
|
-
|
|
99
|
-
// 处理器名称
|
|
100
|
-
abstract readonly name: string;
|
|
101
|
-
|
|
102
|
-
// 主处理方法
|
|
103
|
-
async process(context: ProcessorContext): Promise<ProcessorContext> {
|
|
104
|
-
// 1. 前置验证
|
|
105
|
-
this.validateInput(context);
|
|
106
|
-
|
|
107
|
-
// 2. 执行处理
|
|
108
|
-
const result = await this.doProcess(context);
|
|
109
|
-
|
|
110
|
-
// 3. 后置验证
|
|
111
|
-
this.validateOutput(result);
|
|
112
|
-
|
|
113
|
-
return result;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 子类实现的核心处理逻辑
|
|
117
|
-
protected abstract doProcess(context: ProcessorContext): Promise<ProcessorContext>;
|
|
118
|
-
|
|
119
|
-
// 输入验证(可选覆盖)
|
|
120
|
-
protected validateInput(context: ProcessorContext): void {}
|
|
121
|
-
|
|
122
|
-
// 输出验证(可选覆盖)
|
|
123
|
-
protected validateOutput(context: ProcessorContext): void {}
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
#### BaseInjector
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
abstract class BaseInjector extends BaseProcessor {
|
|
131
|
-
readonly type = ProcessorType.Injector;
|
|
132
|
-
|
|
133
|
-
protected async doProcess(context: ProcessorContext): Promise<ProcessorContext> {
|
|
134
|
-
// 1. 判断是否需要注入
|
|
135
|
-
if (!this.shouldInject(context)) {
|
|
136
|
-
return context;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// 2. 构建注入内容
|
|
140
|
-
const content = await this.buildContent(context);
|
|
141
|
-
|
|
142
|
-
// 3. 创建消息
|
|
143
|
-
const message = this.createMessage(content, context);
|
|
144
|
-
|
|
145
|
-
// 4. 确定注入位置
|
|
146
|
-
const position = this.getInjectionPosition(context);
|
|
147
|
-
|
|
148
|
-
// 5. 执行注入
|
|
149
|
-
return this.inject(context, message, position);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 子类需要实现的方法
|
|
153
|
-
protected abstract shouldInject(context: ProcessorContext): boolean;
|
|
154
|
-
protected abstract buildContent(context: ProcessorContext): Promise<string>;
|
|
155
|
-
|
|
156
|
-
// 可选覆盖的方法
|
|
157
|
-
protected getInjectionPosition(context: ProcessorContext): number {
|
|
158
|
-
return 0; // 默认注入到开头
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
protected createMessage(content: string, context: ProcessorContext): Message {
|
|
162
|
-
return {
|
|
163
|
-
role: 'system',
|
|
164
|
-
content,
|
|
165
|
-
metadata: { injectedBy: this.name }
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## 使用方式
|
|
172
|
-
|
|
173
|
-
### 1. 创建自定义处理器
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
// 创建一个自定义注入器
|
|
177
|
-
class CustomContextInjector extends BaseInjector {
|
|
178
|
-
readonly name = 'custom-context-injector';
|
|
179
|
-
|
|
180
|
-
protected shouldInject(context: ProcessorContext): boolean {
|
|
181
|
-
// 判断逻辑
|
|
182
|
-
return !context.messages.some(msg =>
|
|
183
|
-
msg.metadata?.injectedBy === this.name
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
protected async buildContent(context: ProcessorContext): Promise<string> {
|
|
188
|
-
// 构建内容逻辑
|
|
189
|
-
return `Custom context: ${context.variables?.customValue}`;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### 2. 构建处理管道
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
// 使用工厂模式创建管道
|
|
198
|
-
const pipeline = createPipeline()
|
|
199
|
-
.add(new SystemRoleInjector())
|
|
200
|
-
.add(new HistoryInjector({ maxMessages: 10 }))
|
|
201
|
-
.add(new CustomContextInjector())
|
|
202
|
-
.add(new MessageRoleTransformer())
|
|
203
|
-
.add(new TokenBasedTruncator({ maxTokens: 4000 }))
|
|
204
|
-
.add(new ModelCapabilityValidator());
|
|
205
|
-
|
|
206
|
-
// 执行管道
|
|
207
|
-
const result = await pipeline.execute({
|
|
208
|
-
messages: initialMessages,
|
|
209
|
-
variables: { customValue: 'test' },
|
|
210
|
-
metadata: { model: 'gpt-4' }
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### 3. 条件处理
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
// 基于条件的管道构建
|
|
218
|
-
const pipeline = createPipeline();
|
|
219
|
-
|
|
220
|
-
if (config.enableRAG) {
|
|
221
|
-
pipeline.add(new RAGContextInjector());
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (config.enableSearch) {
|
|
225
|
-
pipeline.add(new SearchContextInjector());
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// 始终添加的处理器
|
|
229
|
-
pipeline
|
|
230
|
-
.add(new HistoryTruncator())
|
|
231
|
-
.add(new ModelCapabilityValidator());
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### 4. 错误处理
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
try {
|
|
238
|
-
const result = await pipeline.execute(context);
|
|
239
|
-
} catch (error) {
|
|
240
|
-
if (error instanceof ProcessorError) {
|
|
241
|
-
console.error(`Processor ${error.processorName} failed:`, error.message);
|
|
242
|
-
} else if (error instanceof PipelineError) {
|
|
243
|
-
console.error('Pipeline execution failed:', error.message);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
## 配置管理
|
|
249
|
-
|
|
250
|
-
### 处理器配置
|
|
251
|
-
|
|
252
|
-
每个处理器可以接受特定的配置选项:
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
interface ProcessorConfig {
|
|
256
|
-
// 通用配置
|
|
257
|
-
enabled?: boolean;
|
|
258
|
-
priority?: number;
|
|
259
|
-
|
|
260
|
-
// 处理器特定配置
|
|
261
|
-
[key: string]: any;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 示例:历史注入器配置
|
|
265
|
-
interface HistoryInjectorConfig extends ProcessorConfig {
|
|
266
|
-
maxMessages?: number;
|
|
267
|
-
includeSystemMessages?: boolean;
|
|
268
|
-
preserveTools?: boolean;
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### 管道配置
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
interface PipelineConfig {
|
|
276
|
-
processors: Array<{
|
|
277
|
-
type: string;
|
|
278
|
-
config?: ProcessorConfig;
|
|
279
|
-
}>;
|
|
280
|
-
|
|
281
|
-
// 全局配置
|
|
282
|
-
abortOnError?: boolean;
|
|
283
|
-
timeout?: number;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// 从配置创建管道
|
|
287
|
-
const pipeline = createPipelineFromConfig({
|
|
288
|
-
processors: [
|
|
289
|
-
{ type: 'system-role', config: { enabled: true } },
|
|
290
|
-
{ type: 'history', config: { maxMessages: 20 } },
|
|
291
|
-
{ type: 'rag', config: { threshold: 0.7 } }
|
|
292
|
-
],
|
|
293
|
-
abortOnError: false,
|
|
294
|
-
timeout: 30000
|
|
295
|
-
});
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
## 最佳实践
|
|
299
|
-
|
|
300
|
-
### 1. 单一职责原则
|
|
301
|
-
每个处理器应该只负责一种特定的处理任务。
|
|
302
|
-
|
|
303
|
-
### 2. 可配置性
|
|
304
|
-
处理器应该通过配置参数来控制行为,而不是硬编码。
|
|
305
|
-
|
|
306
|
-
### 3. 错误处理
|
|
307
|
-
- 使用具体的错误类型
|
|
308
|
-
- 提供有意义的错误信息
|
|
309
|
-
- 考虑错误恢复策略
|
|
310
|
-
|
|
311
|
-
### 4. 性能优化
|
|
312
|
-
- 避免不必要的消息复制
|
|
313
|
-
- 使用流式处理处理大量数据
|
|
314
|
-
- 实现适当的缓存机制
|
|
315
|
-
|
|
316
|
-
### 5. 测试
|
|
317
|
-
- 为每个处理器编写单元测试
|
|
318
|
-
- 测试处理器组合的集成测试
|
|
319
|
-
- 边界条件和错误场景测试
|
|
320
|
-
|
|
321
|
-
## 扩展机制
|
|
322
|
-
|
|
323
|
-
### 1. 自定义处理器类型
|
|
324
|
-
|
|
325
|
-
```typescript
|
|
326
|
-
// 定义新的处理器类型
|
|
327
|
-
enum CustomProcessorType {
|
|
328
|
-
Analyzer = 'analyzer',
|
|
329
|
-
Enhancer = 'enhancer'
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// 创建对应的基类
|
|
333
|
-
abstract class BaseAnalyzer extends BaseProcessor {
|
|
334
|
-
readonly type = CustomProcessorType.Analyzer;
|
|
335
|
-
|
|
336
|
-
// 分析器特定的方法
|
|
337
|
-
protected abstract analyze(messages: Message[]): AnalysisResult;
|
|
338
|
-
}
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### 2. 处理器组合
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
// 创建复合处理器
|
|
345
|
-
class CompositeProcessor extends BaseProcessor {
|
|
346
|
-
constructor(private processors: BaseProcessor[]) {
|
|
347
|
-
super();
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
protected async doProcess(context: ProcessorContext): Promise<ProcessorContext> {
|
|
351
|
-
let result = context;
|
|
352
|
-
for (const processor of this.processors) {
|
|
353
|
-
result = await processor.process(result);
|
|
354
|
-
}
|
|
355
|
-
return result;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
### 3. 插件系统
|
|
361
|
-
|
|
362
|
-
```typescript
|
|
363
|
-
interface ProcessorPlugin {
|
|
364
|
-
name: string;
|
|
365
|
-
version: string;
|
|
366
|
-
processors: ProcessorDefinition[];
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// 注册插件
|
|
370
|
-
registry.registerPlugin({
|
|
371
|
-
name: 'custom-processors',
|
|
372
|
-
version: '1.0.0',
|
|
373
|
-
processors: [
|
|
374
|
-
{ type: 'custom-injector', factory: () => new CustomInjector() },
|
|
375
|
-
{ type: 'custom-validator', factory: () => new CustomValidator() }
|
|
376
|
-
]
|
|
377
|
-
});
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
## 迁移指南
|
|
381
|
-
|
|
382
|
-
### 从当前架构迁移
|
|
383
|
-
|
|
384
|
-
1. **BaseProvider 迁移到 BaseInjector**
|
|
385
|
-
```typescript
|
|
386
|
-
// 旧代码
|
|
387
|
-
class MyProvider extends BaseProvider {
|
|
388
|
-
doProcess(context) {
|
|
389
|
-
// 实现
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// 新代码
|
|
394
|
-
class MyInjector extends BaseInjector {
|
|
395
|
-
shouldInject(context) {
|
|
396
|
-
// 判断逻辑
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
buildContent(context) {
|
|
400
|
-
// 构建内容
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
2. **处理器分类**
|
|
406
|
-
- 将现有处理器按功能分类
|
|
407
|
-
- 继承对应的基类
|
|
408
|
-
- 实现必要的抽象方法
|
|
409
|
-
|
|
410
|
-
3. **配置迁移**
|
|
411
|
-
- 统一配置格式
|
|
412
|
-
- 支持向后兼容
|
|
413
|
-
- 提供迁移工具
|
|
414
|
-
|
|
415
|
-
## 总结
|
|
416
|
-
|
|
417
|
-
新的 Context Engine 架构提供了:
|
|
418
|
-
|
|
419
|
-
1. **清晰的分层结构**:基于功能的处理器分类
|
|
420
|
-
2. **灵活的扩展机制**:易于添加新的处理器类型
|
|
421
|
-
3. **强大的组合能力**:通过管道组合实现复杂功能
|
|
422
|
-
4. **完善的错误处理**:细粒度的错误类型和恢复策略
|
|
423
|
-
5. **优秀的可测试性**:模块化设计便于单元测试
|
|
424
|
-
|
|
425
|
-
这种设计使得 Context Engine 更加模块化、可维护和可扩展,能够更好地满足不同场景下的上下文处理需求。
|