@lobehub/lobehub 2.0.0-next.48 → 2.0.0-next.49
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/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/changelog/v1.json +12 -0
- package/locales/ar/chat.json +1 -0
- package/locales/ar/topic.json +1 -0
- package/locales/bg-BG/chat.json +1 -0
- package/locales/bg-BG/topic.json +1 -0
- package/locales/de-DE/chat.json +1 -0
- package/locales/de-DE/topic.json +1 -0
- package/locales/en-US/chat.json +1 -0
- package/locales/en-US/topic.json +1 -0
- package/locales/es-ES/chat.json +1 -0
- package/locales/es-ES/topic.json +1 -0
- package/locales/fa-IR/chat.json +1 -0
- package/locales/fa-IR/topic.json +1 -0
- package/locales/fr-FR/chat.json +1 -0
- package/locales/fr-FR/topic.json +1 -0
- package/locales/it-IT/chat.json +1 -0
- package/locales/it-IT/topic.json +1 -0
- package/locales/ja-JP/chat.json +1 -0
- package/locales/ja-JP/topic.json +1 -0
- package/locales/ko-KR/chat.json +1 -0
- package/locales/ko-KR/topic.json +1 -0
- package/locales/nl-NL/chat.json +1 -0
- package/locales/nl-NL/topic.json +1 -0
- package/locales/pl-PL/chat.json +1 -0
- package/locales/pl-PL/topic.json +1 -0
- package/locales/pt-BR/chat.json +1 -0
- package/locales/pt-BR/topic.json +1 -0
- package/locales/ru-RU/chat.json +1 -0
- package/locales/ru-RU/topic.json +1 -0
- package/locales/tr-TR/chat.json +1 -0
- package/locales/tr-TR/topic.json +1 -0
- package/locales/vi-VN/chat.json +1 -0
- package/locales/vi-VN/topic.json +1 -0
- package/locales/zh-CN/chat.json +1 -0
- package/locales/zh-CN/discover.json +1 -1
- package/locales/zh-CN/topic.json +1 -0
- package/locales/zh-TW/chat.json +1 -0
- package/locales/zh-TW/topic.json +1 -0
- package/package.json +9 -3
- package/packages/agent-runtime/src/core/InterventionChecker.ts +5 -16
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +27 -80
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +32 -13
- package/packages/agent-runtime/src/core/runtime.ts +7 -3
- package/packages/agent-runtime/src/types/event.ts +2 -1
- package/packages/agent-runtime/src/types/generalAgent.ts +1 -0
- package/packages/agent-runtime/src/types/instruction.ts +3 -2
- package/packages/agent-runtime/src/types/state.ts +3 -1
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +4 -1
- package/packages/database/src/models/message.ts +3 -0
- package/packages/obervability-otel/src/node.ts +15 -1
- package/packages/types/src/message/common/base.ts +2 -2
- package/packages/types/src/message/common/tools.ts +16 -10
- package/packages/types/src/message/ui/chat.ts +7 -1
- package/packages/types/src/tool/intervention.ts +2 -3
- package/packages/types/src/user/settings/tool.ts +15 -28
- package/renovate.json +28 -11
- package/src/app/[variants]/(main)/chat/components/topic/features/Topic/TopicListContent/TopicItem/TopicContent.tsx +1 -1
- package/src/app/[variants]/(main)/chat/session/features/SessionListContent/List/Item/Actions.tsx +1 -1
- package/src/features/Conversation/Messages/Group/GroupChildren.tsx +20 -15
- package/src/features/Conversation/Messages/Group/GroupContext.tsx +15 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/BuiltinPluginTitle.tsx +2 -4
- package/src/features/Conversation/Messages/Group/Tool/Inspector/ToolTitle.tsx +3 -5
- package/src/features/Conversation/Messages/Group/Tool/Inspector/index.tsx +19 -7
- package/src/features/Conversation/Messages/Group/Tool/Render/Arguments/index.tsx +14 -12
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ApprovalActions.tsx +143 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/KeyValueEditor.tsx +213 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ModeSelector.tsx +134 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/index.tsx +99 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/RejectedResponse.tsx +45 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +23 -1
- package/src/features/Conversation/Messages/Group/Tool/index.tsx +42 -18
- package/src/features/Conversation/Messages/Group/Tools.tsx +3 -1
- package/src/locales/default/chat.ts +22 -0
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/topic.ts +1 -0
- package/src/server/routers/lambda/message.ts +4 -1
- package/src/server/services/message/index.ts +13 -0
- package/src/services/message/index.ts +17 -2
- package/src/store/chat/agents/GeneralChatAgent.ts +141 -24
- package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +605 -0
- package/src/store/chat/agents/createAgentExecutors.ts +144 -26
- package/src/store/chat/agents/createToolEngine.ts +22 -0
- package/src/store/chat/slices/aiChat/actions/conversationControl.ts +106 -0
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +54 -26
- package/src/store/chat/slices/message/reducer.ts +2 -1
- package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +26 -1
- package/src/store/user/slices/settings/action.ts +15 -0
|
@@ -9,20 +9,22 @@ import {
|
|
|
9
9
|
GeneralAgentCallToolsBatchInstructionPayload,
|
|
10
10
|
GeneralAgentCallingToolInstructionPayload,
|
|
11
11
|
GeneralAgentConfig,
|
|
12
|
+
InterventionChecker,
|
|
12
13
|
} from '@lobechat/agent-runtime';
|
|
14
|
+
import type { ChatToolPayload, HumanInterventionConfig } from '@lobechat/types';
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* ChatAgent - The "Brain" of the chat agent
|
|
16
18
|
*
|
|
17
19
|
* This agent implements a simple but powerful decision loop:
|
|
18
20
|
* 1. user_input → call_llm (with optional RAG/Search preprocessing)
|
|
19
|
-
* 2. llm_result → check for tool_calls
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
21
|
+
* 2. llm_result → check for tool_calls and intervention requirements
|
|
22
|
+
* - Tools not requiring intervention → call_tools_batch (execute immediately)
|
|
23
|
+
* - Tools requiring intervention → request_human_approve (wait for approval)
|
|
24
|
+
* - Mixed (both types) → [call_tools_batch, request_human_approve] (execute safe ones first, then request approval)
|
|
25
|
+
* - No tool_calls → finish
|
|
22
26
|
* 3. tools_batch_result → call_llm (process tool results)
|
|
23
27
|
*
|
|
24
|
-
* Note: RAG and Search workflow preprocessing are handled externally
|
|
25
|
-
* before creating the agent runtime, keeping the agent logic simple.
|
|
26
28
|
*/
|
|
27
29
|
export class GeneralChatAgent implements Agent {
|
|
28
30
|
private config: GeneralAgentConfig;
|
|
@@ -31,6 +33,63 @@ export class GeneralChatAgent implements Agent {
|
|
|
31
33
|
this.config = config;
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Get intervention configuration for a specific tool call
|
|
38
|
+
*/
|
|
39
|
+
private getToolInterventionConfig(
|
|
40
|
+
toolCalling: ChatToolPayload,
|
|
41
|
+
state: AgentState,
|
|
42
|
+
): HumanInterventionConfig | undefined {
|
|
43
|
+
const { identifier, apiName } = toolCalling;
|
|
44
|
+
const manifest = state.toolManifestMap[identifier];
|
|
45
|
+
|
|
46
|
+
if (!manifest) return undefined;
|
|
47
|
+
|
|
48
|
+
// Find the specific API in the manifest
|
|
49
|
+
const api = manifest.api?.find((a: any) => a.name === apiName);
|
|
50
|
+
|
|
51
|
+
// API-level config takes precedence over tool-level config
|
|
52
|
+
return api?.humanIntervention ?? manifest.humanIntervention;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if tool calls need human intervention
|
|
57
|
+
* Returns [toolsNeedingIntervention, toolsToExecute]
|
|
58
|
+
*/
|
|
59
|
+
private checkInterventionNeeded(
|
|
60
|
+
toolsCalling: ChatToolPayload[],
|
|
61
|
+
state: AgentState,
|
|
62
|
+
): [ChatToolPayload[], ChatToolPayload[]] {
|
|
63
|
+
const toolsNeedingIntervention: ChatToolPayload[] = [];
|
|
64
|
+
const toolsToExecute: ChatToolPayload[] = [];
|
|
65
|
+
|
|
66
|
+
for (const toolCalling of toolsCalling) {
|
|
67
|
+
const config = this.getToolInterventionConfig(toolCalling, state);
|
|
68
|
+
|
|
69
|
+
// Parse arguments for intervention checking
|
|
70
|
+
let toolArgs: Record<string, any> = {};
|
|
71
|
+
try {
|
|
72
|
+
toolArgs = JSON.parse(toolCalling.arguments || '{}');
|
|
73
|
+
} catch {
|
|
74
|
+
// Invalid JSON, treat as empty args
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const policy = InterventionChecker.shouldIntervene({
|
|
78
|
+
config,
|
|
79
|
+
toolArgs,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (policy === 'never') {
|
|
83
|
+
toolsToExecute.push(toolCalling);
|
|
84
|
+
} else {
|
|
85
|
+
// 'require' or 'first' (when not confirmed) requires intervention
|
|
86
|
+
toolsNeedingIntervention.push(toolCalling);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return [toolsNeedingIntervention, toolsToExecute];
|
|
91
|
+
}
|
|
92
|
+
|
|
34
93
|
async runner(
|
|
35
94
|
context: AgentRuntimeContext,
|
|
36
95
|
state: AgentState,
|
|
@@ -55,26 +114,47 @@ export class GeneralChatAgent implements Agent {
|
|
|
55
114
|
context.payload as GeneralAgentCallLLMResultPayload;
|
|
56
115
|
|
|
57
116
|
if (hasToolsCalling && toolsCalling && toolsCalling.length > 0) {
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
117
|
+
// Check which tools need human intervention
|
|
118
|
+
const [toolsNeedingIntervention, toolsToExecute] = this.checkInterventionNeeded(
|
|
119
|
+
toolsCalling,
|
|
120
|
+
state,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const instructions: AgentInstruction[] = [];
|
|
124
|
+
|
|
125
|
+
// Execute tools that don't need intervention first
|
|
126
|
+
// These will run immediately before any approval requests
|
|
127
|
+
if (toolsToExecute.length > 0) {
|
|
128
|
+
if (toolsToExecute.length > 1) {
|
|
129
|
+
instructions.push({
|
|
130
|
+
payload: {
|
|
131
|
+
parentMessageId,
|
|
132
|
+
toolsCalling: toolsToExecute,
|
|
133
|
+
} as GeneralAgentCallToolsBatchInstructionPayload,
|
|
134
|
+
type: 'call_tools_batch',
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
instructions.push({
|
|
138
|
+
payload: {
|
|
139
|
+
parentMessageId,
|
|
140
|
+
toolCalling: toolsToExecute[0],
|
|
141
|
+
} as GeneralAgentCallingToolInstructionPayload,
|
|
142
|
+
type: 'call_tool',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Request approval for tools that need intervention
|
|
148
|
+
// Runtime will execute this after safe tools and pause with status='waiting_for_human'
|
|
149
|
+
if (toolsNeedingIntervention.length > 0) {
|
|
150
|
+
instructions.push({
|
|
151
|
+
pendingToolsCalling: toolsNeedingIntervention,
|
|
152
|
+
reason: 'human_intervention_required',
|
|
153
|
+
type: 'request_human_approve',
|
|
154
|
+
});
|
|
77
155
|
}
|
|
156
|
+
|
|
157
|
+
return instructions;
|
|
78
158
|
}
|
|
79
159
|
|
|
80
160
|
// No tool calls, conversation is complete
|
|
@@ -88,6 +168,24 @@ export class GeneralChatAgent implements Agent {
|
|
|
88
168
|
case 'tool_result': {
|
|
89
169
|
const { parentMessageId } = context.payload as GeneralAgentCallToolResultPayload;
|
|
90
170
|
|
|
171
|
+
// Check if there are still pending tool messages waiting for approval
|
|
172
|
+
const pendingToolMessages = state.messages.filter(
|
|
173
|
+
(m: any) => m.role === 'tool' && m.pluginIntervention?.status === 'pending',
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// If there are pending tools, wait for human approval
|
|
177
|
+
if (pendingToolMessages.length > 0) {
|
|
178
|
+
const pendingTools = pendingToolMessages.map((m: any) => m.plugin).filter(Boolean);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
pendingToolsCalling: pendingTools,
|
|
182
|
+
reason: 'Some tools still pending approval',
|
|
183
|
+
skipCreateToolMessage: true,
|
|
184
|
+
type: 'request_human_approve',
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// No pending tools, continue to call LLM with tool results
|
|
91
189
|
return {
|
|
92
190
|
payload: {
|
|
93
191
|
messages: state.messages,
|
|
@@ -102,6 +200,25 @@ export class GeneralChatAgent implements Agent {
|
|
|
102
200
|
|
|
103
201
|
case 'tools_batch_result': {
|
|
104
202
|
const { parentMessageId } = context.payload as GeneralAgentCallToolResultPayload;
|
|
203
|
+
|
|
204
|
+
// Check if there are still pending tool messages waiting for approval
|
|
205
|
+
const pendingToolMessages = state.messages.filter(
|
|
206
|
+
(m: any) => m.role === 'tool' && m.pluginIntervention?.status === 'pending',
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// If there are pending tools, wait for human approval
|
|
210
|
+
if (pendingToolMessages.length > 0) {
|
|
211
|
+
const pendingTools = pendingToolMessages.map((m: any) => m.plugin).filter(Boolean);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
pendingToolsCalling: pendingTools,
|
|
215
|
+
reason: 'Some tools still pending approval',
|
|
216
|
+
skipCreateToolMessage: true,
|
|
217
|
+
type: 'request_human_approve',
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// No pending tools, continue to call LLM with tool results
|
|
105
222
|
return {
|
|
106
223
|
payload: {
|
|
107
224
|
messages: state.messages,
|