@lobehub/lobehub 2.0.0-next.335 → 2.0.0-next.336
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/changelog/v1.json +12 -0
- package/package.json +1 -1
- package/packages/builtin-tool-group-management/src/manifest.ts +54 -53
- package/packages/builtin-tool-group-management/src/systemRole.ts +43 -111
- package/packages/context-engine/src/engine/tools/ToolArgumentsRepairer.ts +129 -0
- package/packages/context-engine/src/engine/tools/__tests__/ToolArgumentsRepairer.test.ts +186 -0
- package/packages/context-engine/src/engine/tools/index.ts +3 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/index.ts +2 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/with-assistant-group.json +156 -0
- package/packages/conversation-flow/src/__tests__/parse.test.ts +22 -0
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +88 -11
- package/packages/types/src/openai/chat.ts +0 -4
- package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +5 -1
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +8 -8
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +142 -15
- package/src/app/[variants]/(main)/community/(detail)/user/features/useUserDetail.ts +45 -20
- package/src/server/routers/lambda/market/agentGroup.ts +179 -1
- package/src/server/services/discover/index.ts +4 -0
- package/src/services/chat/chat.test.ts +109 -104
- package/src/services/chat/index.ts +13 -32
- package/src/services/chat/mecha/agentConfigResolver.test.ts +113 -0
- package/src/services/chat/mecha/agentConfigResolver.ts +15 -5
- package/src/services/marketApi.ts +14 -0
- package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/testExecutor.ts +13 -0
- package/src/store/chat/agents/createAgentExecutors.ts +13 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +5 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/fixtures.ts +14 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +131 -7
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +61 -62
- package/src/store/chat/slices/plugin/action.test.ts +71 -0
- package/src/store/chat/slices/plugin/actions/internals.ts +14 -5
|
@@ -28,7 +28,7 @@ import { type StateCreator } from 'zustand/vanilla';
|
|
|
28
28
|
|
|
29
29
|
import { createAgentToolsEngine } from '@/helpers/toolEngineering';
|
|
30
30
|
import { chatService } from '@/services/chat';
|
|
31
|
-
import { resolveAgentConfig } from '@/services/chat/mecha';
|
|
31
|
+
import { type ResolvedAgentConfig, resolveAgentConfig } from '@/services/chat/mecha';
|
|
32
32
|
import { messageService } from '@/services/message';
|
|
33
33
|
import { createAgentExecutors } from '@/store/chat/agents/createAgentExecutors';
|
|
34
34
|
import { type ChatStore } from '@/store/chat/store';
|
|
@@ -72,9 +72,15 @@ export interface StreamingExecutorAction {
|
|
|
72
72
|
* Used to get Agent config (model, provider, plugins) instead of agentId
|
|
73
73
|
*/
|
|
74
74
|
subAgentId?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Whether this is a sub-task execution (disables lobe-gtd tools to prevent nested sub-tasks)
|
|
77
|
+
*/
|
|
78
|
+
isSubTask?: boolean;
|
|
75
79
|
}) => {
|
|
76
80
|
state: AgentState;
|
|
77
81
|
context: AgentRuntimeContext;
|
|
82
|
+
/** Resolved agent config with isSubTask filtering applied */
|
|
83
|
+
agentConfig: ResolvedAgentConfig;
|
|
78
84
|
};
|
|
79
85
|
/**
|
|
80
86
|
* Retrieves an AI-generated chat message from the backend service with streaming
|
|
@@ -85,7 +91,8 @@ export interface StreamingExecutorAction {
|
|
|
85
91
|
model: string;
|
|
86
92
|
provider: string;
|
|
87
93
|
operationId?: string;
|
|
88
|
-
|
|
94
|
+
/** Pre-resolved agent config (from internal_createAgentState) with isSubTask filtering applied */
|
|
95
|
+
agentConfig: ResolvedAgentConfig;
|
|
89
96
|
traceId?: string;
|
|
90
97
|
/** Initial context for page editor (captured at operation start) */
|
|
91
98
|
initialContext?: RuntimeInitialContext;
|
|
@@ -132,6 +139,10 @@ export interface StreamingExecutorAction {
|
|
|
132
139
|
*/
|
|
133
140
|
parentOperationId?: string;
|
|
134
141
|
skipCreateFirstMessage?: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Whether this is a sub-task execution (disables lobe-gtd tools to prevent nested sub-tasks)
|
|
144
|
+
*/
|
|
145
|
+
isSubTask?: boolean;
|
|
135
146
|
}) => Promise<{ cost?: Cost; usage?: Usage } | void>;
|
|
136
147
|
}
|
|
137
148
|
|
|
@@ -151,6 +162,7 @@ export const streamingExecutor: StateCreator<
|
|
|
151
162
|
initialContext,
|
|
152
163
|
operationId,
|
|
153
164
|
subAgentId: paramSubAgentId,
|
|
165
|
+
isSubTask,
|
|
154
166
|
}) => {
|
|
155
167
|
// Use provided agentId/topicId or fallback to global state
|
|
156
168
|
const { activeAgentId, activeTopicId } = get();
|
|
@@ -169,11 +181,16 @@ export const streamingExecutor: StateCreator<
|
|
|
169
181
|
|
|
170
182
|
// Resolve agent config with builtin agent runtime config merged
|
|
171
183
|
// This ensures runtime plugins (e.g., 'lobe-agent-builder' for Agent Builder) are included
|
|
172
|
-
|
|
184
|
+
// isSubTask is passed to filter out lobe-gtd tools to prevent nested sub-task creation
|
|
185
|
+
const agentConfig = resolveAgentConfig({
|
|
173
186
|
agentId: effectiveAgentId || '',
|
|
174
187
|
groupId, // Pass groupId for supervisor detection
|
|
188
|
+
isSubTask, // Filter out lobe-gtd in sub-task context
|
|
175
189
|
scope, // Pass scope from operation context
|
|
176
190
|
});
|
|
191
|
+
const { agentConfig: agentConfigData, plugins: pluginIds } = agentConfig;
|
|
192
|
+
|
|
193
|
+
log('[internal_createAgentState] resolved plugins=%o, isSubTask=%s', pluginIds, isSubTask);
|
|
177
194
|
|
|
178
195
|
// Get tools manifest map
|
|
179
196
|
const toolsEngine = createAgentToolsEngine({
|
|
@@ -260,7 +277,7 @@ export const streamingExecutor: StateCreator<
|
|
|
260
277
|
initialContext: runtimeInitialContext,
|
|
261
278
|
};
|
|
262
279
|
|
|
263
|
-
return { state, context };
|
|
280
|
+
return { state, context, agentConfig };
|
|
264
281
|
},
|
|
265
282
|
|
|
266
283
|
internal_fetchAIChatMessage: async ({
|
|
@@ -333,23 +350,10 @@ export const streamingExecutor: StateCreator<
|
|
|
333
350
|
// Create base context for child operations and message queries
|
|
334
351
|
const fetchContext = { agentId, topicId, threadId, groupId, scope };
|
|
335
352
|
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
// Resolve agent config with params adjusted based on chatConfig
|
|
342
|
-
// If agentConfig is passed in, use it directly (it's already resolved)
|
|
343
|
-
// Otherwise, resolve from mecha layer which handles:
|
|
344
|
-
// - Builtin agent runtime config merging
|
|
345
|
-
// - max_tokens/reasoning_effort based on chatConfig settings
|
|
346
|
-
const resolved = resolveAgentConfig({
|
|
347
|
-
agentId: effectiveAgentId,
|
|
348
|
-
groupId, // Pass groupId for supervisor detection
|
|
349
|
-
scope, // scope is already available from line 329
|
|
350
|
-
});
|
|
351
|
-
const finalAgentConfig = agentConfig || resolved.agentConfig;
|
|
352
|
-
const chatConfig = resolved.chatConfig;
|
|
353
|
+
// Use pre-resolved agent config (from internal_createAgentState)
|
|
354
|
+
// This ensures isSubTask filtering and other runtime modifications are preserved
|
|
355
|
+
const { agentConfig: agentConfigData, chatConfig, plugins: pluginIds } = agentConfig;
|
|
356
|
+
log('[internal_fetchAIChatMessage] using pre-resolved config, plugins=%o', pluginIds);
|
|
353
357
|
|
|
354
358
|
let finalUsage: ModelUsage | undefined;
|
|
355
359
|
let finalToolCalls: MessageToolCall[] | undefined;
|
|
@@ -437,18 +441,18 @@ export const streamingExecutor: StateCreator<
|
|
|
437
441
|
await chatService.createAssistantMessageStream({
|
|
438
442
|
abortController,
|
|
439
443
|
params: {
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
// In normal chat: agentId for the main agent
|
|
443
|
-
agentId: effectiveAgentId || undefined,
|
|
444
|
+
// agentId is used for context, not for config resolution (config is pre-resolved)
|
|
445
|
+
agentId: agentId || undefined,
|
|
444
446
|
groupId,
|
|
445
447
|
messages,
|
|
446
448
|
model,
|
|
447
449
|
provider,
|
|
450
|
+
// Pass pre-resolved config to avoid duplicate resolveAgentConfig calls
|
|
451
|
+
// This ensures isSubTask filtering and other runtime modifications are preserved
|
|
452
|
+
resolvedAgentConfig: agentConfig,
|
|
448
453
|
scope, // Pass scope to chat service for page-agent injection
|
|
449
|
-
topicId, // Pass topicId for GTD context injection
|
|
450
|
-
...
|
|
451
|
-
plugins: finalAgentConfig.plugins,
|
|
454
|
+
topicId: topicId ?? undefined, // Pass topicId for GTD context injection
|
|
455
|
+
...agentConfigData.params,
|
|
452
456
|
},
|
|
453
457
|
historySummary: historySummary?.content,
|
|
454
458
|
// Pass page editor context from agent runtime
|
|
@@ -544,7 +548,13 @@ export const streamingExecutor: StateCreator<
|
|
|
544
548
|
},
|
|
545
549
|
|
|
546
550
|
internal_execAgentRuntime: async (params) => {
|
|
547
|
-
const {
|
|
551
|
+
const {
|
|
552
|
+
messages: originalMessages,
|
|
553
|
+
parentMessageId,
|
|
554
|
+
parentMessageType,
|
|
555
|
+
context,
|
|
556
|
+
isSubTask,
|
|
557
|
+
} = params;
|
|
548
558
|
|
|
549
559
|
// Extract values from context
|
|
550
560
|
const { agentId, topicId, threadId, subAgentId, groupId } = context;
|
|
@@ -593,30 +603,32 @@ export const streamingExecutor: StateCreator<
|
|
|
593
603
|
// Create a new array to avoid modifying the original messages
|
|
594
604
|
let messages = [...originalMessages];
|
|
595
605
|
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
const {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
606
|
+
// ===========================================
|
|
607
|
+
// Step 1: Create Agent State (resolves config once)
|
|
608
|
+
// ===========================================
|
|
609
|
+
// agentConfig contains isSubTask filtering and is passed to callLLM executor
|
|
610
|
+
const {
|
|
611
|
+
state: initialAgentState,
|
|
612
|
+
context: initialAgentContext,
|
|
613
|
+
agentConfig,
|
|
614
|
+
} = get().internal_createAgentState({
|
|
615
|
+
messages,
|
|
616
|
+
parentMessageId: params.parentMessageId,
|
|
617
|
+
agentId,
|
|
618
|
+
topicId,
|
|
619
|
+
threadId: threadId ?? undefined,
|
|
620
|
+
initialState: params.initialState,
|
|
621
|
+
initialContext: params.initialContext,
|
|
622
|
+
operationId,
|
|
623
|
+
subAgentId, // Pass subAgentId for agent config retrieval
|
|
624
|
+
isSubTask, // Pass isSubTask to filter out lobe-gtd tools in sub-task context
|
|
604
625
|
});
|
|
605
626
|
|
|
606
|
-
// Use
|
|
627
|
+
// Use model/provider from resolved agentConfig
|
|
628
|
+
const { agentConfig: agentConfigData } = agentConfig;
|
|
607
629
|
const model = agentConfigData.model;
|
|
608
630
|
const provider = agentConfigData.provider;
|
|
609
631
|
|
|
610
|
-
// ===========================================
|
|
611
|
-
// Step 1: Knowledge Base Tool Integration
|
|
612
|
-
// ===========================================
|
|
613
|
-
// RAG retrieval is now handled by the Knowledge Base Tool
|
|
614
|
-
// The AI will decide when to call searchKnowledgeBase and readKnowledge tools
|
|
615
|
-
// based on the conversation context and available knowledge bases
|
|
616
|
-
|
|
617
|
-
// TODO: Implement selected files full-text injection if needed
|
|
618
|
-
// User-selected files should be handled differently from knowledge base files
|
|
619
|
-
|
|
620
632
|
// ===========================================
|
|
621
633
|
// Step 2: Create and Execute Agent Runtime
|
|
622
634
|
// ===========================================
|
|
@@ -633,6 +645,7 @@ export const streamingExecutor: StateCreator<
|
|
|
633
645
|
|
|
634
646
|
const runtime = new AgentRuntime(agent, {
|
|
635
647
|
executors: createAgentExecutors({
|
|
648
|
+
agentConfig, // Pass pre-resolved config to callLLM executor
|
|
636
649
|
get,
|
|
637
650
|
messageKey,
|
|
638
651
|
operationId,
|
|
@@ -650,20 +663,6 @@ export const streamingExecutor: StateCreator<
|
|
|
650
663
|
operationId,
|
|
651
664
|
});
|
|
652
665
|
|
|
653
|
-
// Create agent state and context with user intervention config
|
|
654
|
-
const { state: initialAgentState, context: initialAgentContext } =
|
|
655
|
-
get().internal_createAgentState({
|
|
656
|
-
messages,
|
|
657
|
-
parentMessageId: params.parentMessageId,
|
|
658
|
-
agentId,
|
|
659
|
-
topicId,
|
|
660
|
-
threadId: threadId ?? undefined,
|
|
661
|
-
initialState: params.initialState,
|
|
662
|
-
initialContext: params.initialContext,
|
|
663
|
-
operationId,
|
|
664
|
-
subAgentId, // Pass subAgentId for agent config retrieval
|
|
665
|
-
});
|
|
666
|
-
|
|
667
666
|
let state = initialAgentState;
|
|
668
667
|
let nextContext = initialAgentContext;
|
|
669
668
|
|
|
@@ -1060,6 +1060,77 @@ describe('ChatPluginAction', () => {
|
|
|
1060
1060
|
|
|
1061
1061
|
expect(transformed[0].apiName).toBe(longApiName);
|
|
1062
1062
|
});
|
|
1063
|
+
|
|
1064
|
+
it('should repair malformed JSON arguments with escaped string issue', () => {
|
|
1065
|
+
// This is the malformed data from haiku-4.5 model
|
|
1066
|
+
// The entire JSON got stuffed into the "description" field with escaped quotes
|
|
1067
|
+
const malformedArguments = JSON.stringify({
|
|
1068
|
+
description:
|
|
1069
|
+
'Synthesize all 10 batch analyses into 10 most important themes for product builders", "instruction": "You have access to 10 batch analysis files", "runInClient": true, "timeout": 120000}',
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
const toolCalls: MessageToolCall[] = [
|
|
1073
|
+
{
|
|
1074
|
+
id: 'tool1',
|
|
1075
|
+
function: {
|
|
1076
|
+
name: ['lobe-gtd', 'execTask', 'default'].join(PLUGIN_SCHEMA_SEPARATOR),
|
|
1077
|
+
arguments: malformedArguments,
|
|
1078
|
+
},
|
|
1079
|
+
type: 'function',
|
|
1080
|
+
},
|
|
1081
|
+
];
|
|
1082
|
+
|
|
1083
|
+
// Setup builtin tool manifest with schema that has required fields
|
|
1084
|
+
act(() => {
|
|
1085
|
+
useToolStore.setState({
|
|
1086
|
+
builtinTools: [
|
|
1087
|
+
{
|
|
1088
|
+
type: 'builtin',
|
|
1089
|
+
identifier: 'lobe-gtd',
|
|
1090
|
+
manifest: {
|
|
1091
|
+
identifier: 'lobe-gtd',
|
|
1092
|
+
api: [
|
|
1093
|
+
{
|
|
1094
|
+
name: 'execTask',
|
|
1095
|
+
description: 'Execute async task',
|
|
1096
|
+
parameters: {
|
|
1097
|
+
type: 'object',
|
|
1098
|
+
required: ['description', 'instruction'],
|
|
1099
|
+
properties: {
|
|
1100
|
+
description: { type: 'string' },
|
|
1101
|
+
instruction: { type: 'string' },
|
|
1102
|
+
runInClient: { type: 'boolean' },
|
|
1103
|
+
timeout: { type: 'number' },
|
|
1104
|
+
},
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
],
|
|
1108
|
+
type: 'builtin',
|
|
1109
|
+
} as any,
|
|
1110
|
+
},
|
|
1111
|
+
],
|
|
1112
|
+
});
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
const { result } = renderHook(() => useChatStore());
|
|
1116
|
+
|
|
1117
|
+
const transformed = result.current.internal_transformToolCalls(toolCalls);
|
|
1118
|
+
|
|
1119
|
+
// Parse the transformed arguments
|
|
1120
|
+
const repairedArgs = JSON.parse(transformed[0].arguments);
|
|
1121
|
+
|
|
1122
|
+
// Verify all fields are correctly extracted
|
|
1123
|
+
expect(repairedArgs).toHaveProperty('description');
|
|
1124
|
+
expect(repairedArgs).toHaveProperty('instruction');
|
|
1125
|
+
expect(repairedArgs).toHaveProperty('runInClient', true);
|
|
1126
|
+
expect(repairedArgs).toHaveProperty('timeout', 120000);
|
|
1127
|
+
|
|
1128
|
+
// Verify description is the correct short value, not the entire malformed string
|
|
1129
|
+
expect(repairedArgs.description).toBe(
|
|
1130
|
+
'Synthesize all 10 batch analyses into 10 most important themes for product builders',
|
|
1131
|
+
);
|
|
1132
|
+
expect(repairedArgs.instruction).toBe('You have access to 10 batch analysis files');
|
|
1133
|
+
});
|
|
1063
1134
|
});
|
|
1064
1135
|
|
|
1065
1136
|
describe('internal_updatePluginError', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable sort-keys-fix/sort-keys-fix, typescript-sort-keys/interface */
|
|
2
|
-
import { ToolNameResolver } from '@lobechat/context-engine';
|
|
2
|
+
import { ToolArgumentsRepairer, ToolNameResolver } from '@lobechat/context-engine';
|
|
3
3
|
import { type ChatToolPayload, type MessageToolCall } from '@lobechat/types';
|
|
4
4
|
import { type LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
|
5
5
|
import { type StateCreator } from 'zustand/vanilla';
|
|
@@ -78,9 +78,18 @@ export const pluginInternals: StateCreator<
|
|
|
78
78
|
|
|
79
79
|
// Resolve tool calls and add source field
|
|
80
80
|
const resolved = toolNameResolver.resolve(toolCalls, manifests);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
|
|
82
|
+
return resolved.map((payload) => {
|
|
83
|
+
// Parse and repair arguments if needed
|
|
84
|
+
const manifest = manifests[payload.identifier];
|
|
85
|
+
const repairer = new ToolArgumentsRepairer(manifest);
|
|
86
|
+
const repairedArgs = repairer.parse(payload.apiName, payload.arguments);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
...payload,
|
|
90
|
+
arguments: JSON.stringify(repairedArgs),
|
|
91
|
+
source: sourceMap[payload.identifier],
|
|
92
|
+
};
|
|
93
|
+
});
|
|
85
94
|
},
|
|
86
95
|
});
|