Skip to content

Commit 063120a

Browse files
authored
Merge pull request #1779 from ModelEngine-Group/xyc/agent_generate_bugfix
2 parents 09be0c1 + b3b77f9 commit 063120a

File tree

4 files changed

+260
-46
lines changed

4 files changed

+260
-46
lines changed

frontend/app/[locale]/agents/components/AgentSetupOrchestrator.tsx

Lines changed: 153 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ import {
1818
searchToolConfig,
1919
updateToolConfig,
2020
} from "@/services/agentConfigService";
21-
import { Agent, AgentSetupOrchestratorProps, Tool } from "@/types/agentConfig";
21+
import {
22+
Agent,
23+
AgentSetupOrchestratorProps,
24+
Tool,
25+
ToolParam,
26+
} from "@/types/agentConfig";
2227
import log from "@/lib/logger";
2328

2429
import SubAgentPool from "./agent/SubAgentPool";
@@ -90,6 +95,9 @@ export default function AgentSetupOrchestrator({
9095
const [enabledToolIds, setEnabledToolIds] = useState<number[]>([]);
9196
const [isLoadingTools, setIsLoadingTools] = useState(false);
9297
const [isImporting, setIsImporting] = useState(false);
98+
const [toolConfigDrafts, setToolConfigDrafts] = useState<
99+
Record<string, ToolParam[]>
100+
>({});
93101
// Use generation state passed from parent component, not local state
94102

95103
// Delete confirmation popup status
@@ -146,6 +154,19 @@ export default function AgentSetupOrchestrator({
146154
[]
147155
);
148156

157+
const numericMainAgentId =
158+
mainAgentId !== null &&
159+
mainAgentId !== undefined &&
160+
String(mainAgentId).trim() !== ""
161+
? Number(mainAgentId)
162+
: null;
163+
const hasPersistedMainAgentId =
164+
typeof numericMainAgentId === "number" &&
165+
!Number.isNaN(numericMainAgentId) &&
166+
numericMainAgentId > 0;
167+
const isDraftCreationSession =
168+
isCreatingNewAgent && !hasPersistedMainAgentId && !isEditingAgent;
169+
149170
// Add a flag to track if it has been initialized to avoid duplicate calls
150171
const hasInitialized = useRef(false);
151172
// Baseline snapshot for change detection
@@ -256,6 +277,12 @@ export default function AgentSetupOrchestrator({
256277
}
257278
}, [isEditingAgent, editingAgent]);
258279

280+
useEffect(() => {
281+
if (!isDraftCreationSession) {
282+
setToolConfigDrafts({});
283+
}
284+
}, [isDraftCreationSession]);
285+
259286
// Initialize baseline when entering create mode so draft changes don't attach to previous agent
260287
useEffect(() => {
261288
if (isCreatingNewAgent && !isEditingAgent) {
@@ -478,6 +505,36 @@ export default function AgentSetupOrchestrator({
478505
[hasUnsavedChanges]
479506
);
480507

508+
const handleToolConfigDraftSave = useCallback(
509+
(updatedTool: Tool) => {
510+
if (!isDraftCreationSession) {
511+
return;
512+
}
513+
setToolConfigDrafts((prev) => ({
514+
...prev,
515+
[updatedTool.id]:
516+
updatedTool.initParams?.map((param) => ({ ...param })) || [],
517+
}));
518+
setSelectedTools((prev: Tool[]) => {
519+
if (!prev || prev.length === 0) {
520+
return prev;
521+
}
522+
const index = prev.findIndex((tool) => tool.id === updatedTool.id);
523+
if (index === -1) {
524+
return prev;
525+
}
526+
const next = [...prev];
527+
next[index] = {
528+
...updatedTool,
529+
initParams:
530+
updatedTool.initParams?.map((param) => ({ ...param })) || [],
531+
};
532+
return next;
533+
});
534+
},
535+
[isDraftCreationSession, setSelectedTools]
536+
);
537+
481538
// Function to directly update enabledAgentIds
482539
const handleUpdateEnabledAgentIds = (newEnabledAgentIds: number[]) => {
483540
setEnabledAgentIds(newEnabledAgentIds);
@@ -512,21 +569,46 @@ export default function AgentSetupOrchestrator({
512569
}
513570
}, [isCreatingNewAgent, isEditingAgent, mainAgentId]);
514571

572+
const applyDraftParamsToTool = useCallback(
573+
(tool: Tool): Tool => {
574+
if (!isDraftCreationSession) {
575+
return tool;
576+
}
577+
const draft = toolConfigDrafts[tool.id];
578+
if (!draft || draft.length === 0) {
579+
return tool;
580+
}
581+
return {
582+
...tool,
583+
initParams: draft.map((param) => ({ ...param })),
584+
};
585+
},
586+
[isDraftCreationSession, toolConfigDrafts]
587+
);
588+
515589
// Listen for changes in the tool status, update the selected tool
516590
useEffect(() => {
517591
if (!tools || isLoadingTools) return;
518592
// Allow empty enabledToolIds array (it's valid when no tools are selected)
519593
if (enabledToolIds === undefined || enabledToolIds === null) return;
520594

521595
// Filter out unavailable tools (is_available === false) to prevent deleted MCP tools from showing
522-
const enabledTools = tools.filter(
523-
(tool) =>
524-
enabledToolIds.includes(Number(tool.id)) &&
525-
tool.is_available !== false
526-
);
596+
const enabledTools = tools
597+
.filter(
598+
(tool) =>
599+
enabledToolIds.includes(Number(tool.id)) &&
600+
tool.is_available !== false
601+
)
602+
.map((tool) => applyDraftParamsToTool(tool));
527603

528604
setSelectedTools(enabledTools);
529-
}, [tools, enabledToolIds, isLoadingTools]);
605+
}, [
606+
tools,
607+
enabledToolIds,
608+
isLoadingTools,
609+
applyDraftParamsToTool,
610+
setSelectedTools,
611+
]);
530612

531613
// Auto-unselect knowledge_base_search if embedding is not configured
532614
useEffect(() => {
@@ -913,6 +995,61 @@ export default function AgentSetupOrchestrator({
913995
};
914996

915997
// Handle the creation of a new Agent
998+
const persistDraftToolConfigs = useCallback(
999+
async (agentId: number, toolIdsToEnable: number[]) => {
1000+
if (!toolIdsToEnable || toolIdsToEnable.length === 0) {
1001+
return;
1002+
}
1003+
1004+
const payloads = toolIdsToEnable
1005+
.map((toolId) => {
1006+
const toolIdStr = String(toolId);
1007+
const draftParams = toolConfigDrafts[toolIdStr];
1008+
const baseTool =
1009+
selectedTools.find((tool) => Number(tool.id) === toolId) ||
1010+
tools.find((tool) => Number(tool.id) === toolId);
1011+
const paramsSource =
1012+
(draftParams && draftParams.length > 0
1013+
? draftParams
1014+
: baseTool?.initParams) || [];
1015+
if (!paramsSource || paramsSource.length === 0) {
1016+
return null;
1017+
}
1018+
const params = paramsSource.reduce((acc, param) => {
1019+
acc[param.name] = param.value;
1020+
return acc;
1021+
}, {} as Record<string, any>);
1022+
return {
1023+
toolId,
1024+
params,
1025+
};
1026+
})
1027+
.filter(Boolean) as Array<{
1028+
toolId: number;
1029+
params: Record<string, any>;
1030+
}>;
1031+
1032+
if (payloads.length === 0) {
1033+
return;
1034+
}
1035+
1036+
let persistError = false;
1037+
for (const payload of payloads) {
1038+
try {
1039+
await updateToolConfig(payload.toolId, agentId, payload.params, true);
1040+
} catch (error) {
1041+
persistError = true;
1042+
log.error("Failed to persist tool configuration for new agent:", error);
1043+
}
1044+
}
1045+
1046+
if (persistError) {
1047+
message.error(t("toolConfig.message.saveError"));
1048+
}
1049+
},
1050+
[toolConfigDrafts, selectedTools, tools, message, t]
1051+
);
1052+
9161053
const handleSaveNewAgent = async (
9171054
name: string,
9181055
description: string,
@@ -987,6 +1124,13 @@ export default function AgentSetupOrchestrator({
9871124
}
9881125

9891126
if (result.success) {
1127+
if (!isEditingAgent && result.data?.agent_id) {
1128+
await persistDraftToolConfigs(
1129+
Number(result.data.agent_id),
1130+
deduplicatedToolIds
1131+
);
1132+
setToolConfigDrafts({});
1133+
}
9901134
// If created, set new mainAgentId for subsequent operations
9911135
if (!isEditingAgent && result.data?.agent_id) {
9921136
setMainAgentId(String(result.data.agent_id));
@@ -1723,6 +1867,8 @@ export default function AgentSetupOrchestrator({
17231867
isGeneratingAgent={isGeneratingAgent}
17241868
isEmbeddingConfigured={isEmbeddingConfigured}
17251869
agentUnavailableReasons={agentUnavailableReasons}
1870+
onToolConfigSave={handleToolConfigDraftSave}
1871+
toolConfigDrafts={toolConfigDrafts}
17261872
/>
17271873
</div>
17281874
</div>

frontend/app/[locale]/agents/components/tool/ToolConfigModal.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ export default function ToolConfigModal({
6363
const { windowWidth, mainModalTop, mainModalRight } =
6464
useModalPosition(isOpen);
6565

66+
const normalizedAgentId =
67+
typeof mainAgentId === "number" && !Number.isNaN(mainAgentId)
68+
? mainAgentId
69+
: null;
70+
const canPersistToolConfig =
71+
typeof normalizedAgentId === "number" && normalizedAgentId > 0;
72+
6673
// load tool config
6774
useEffect(() => {
6875
const buildDefaultParams = () =>
@@ -78,14 +85,17 @@ export default function ToolConfigModal({
7885
}
7986

8087
// In creation mode we do not have an agent ID yet, so use the tool's default params.
81-
if (!mainAgentId) {
88+
if (!normalizedAgentId) {
8289
setCurrentParams(buildDefaultParams());
8390
return;
8491
}
8592

8693
setIsLoading(true);
8794
try {
88-
const result = await searchToolConfig(parseInt(tool.id), mainAgentId);
95+
const result = await searchToolConfig(
96+
parseInt(tool.id),
97+
normalizedAgentId
98+
);
8999
if (result.success) {
90100
if (result.data?.params) {
91101
const savedParams = tool.initParams.map((param) => {
@@ -117,7 +127,7 @@ export default function ToolConfigModal({
117127
} else {
118128
setCurrentParams([]);
119129
}
120-
}, [isOpen, tool, mainAgentId, t, message]);
130+
}, [isOpen, tool, normalizedAgentId, t, message]);
121131

122132
// check required fields
123133
const checkRequiredFields = () => {
@@ -190,12 +200,21 @@ export default function ToolConfigModal({
190200
return acc;
191201
}, {} as Record<string, any>);
192202

203+
if (!canPersistToolConfig) {
204+
message.success(t("toolConfig.message.saveSuccess"));
205+
onSave({
206+
...tool,
207+
initParams: currentParams,
208+
});
209+
return;
210+
}
211+
193212
// decide enabled status based on whether the tool is in selectedTools
194213
const isEnabled = selectedTools.some((t) => t.id === tool.id);
195214

196215
const result = await updateToolConfig(
197216
parseInt(tool.id),
198-
mainAgentId,
217+
normalizedAgentId,
199218
params,
200219
isEnabled
201220
);

0 commit comments

Comments
 (0)