diff --git a/application/api/user/base.py b/application/api/user/base.py
index d4f70aa6..920af776 100644
--- a/application/api/user/base.py
+++ b/application/api/user/base.py
@@ -152,7 +152,9 @@ def resolve_tool_details(tool_ids):
{
"id": str(tool["_id"]),
"name": tool.get("name", ""),
- "display_name": tool.get("displayName", tool.get("name", "")),
+ "display_name": tool.get("customName")
+ or tool.get("displayName")
+ or tool.get("name", ""),
}
for tool in tools
]
diff --git a/frontend/src/agents/NewAgent.tsx b/frontend/src/agents/NewAgent.tsx
index af77f6a9..c9a5e55d 100644
--- a/frontend/src/agents/NewAgent.tsx
+++ b/frontend/src/agents/NewAgent.tsx
@@ -28,6 +28,7 @@ import {
import PromptsModal from '../preferences/PromptsModal';
import Prompts from '../settings/Prompts';
import { UserToolType } from '../settings/types';
+import { getToolDisplayName } from '../utils/toolUtils';
import AgentPreview from './AgentPreview';
import { Agent, ToolSummary } from './types';
import WorkflowBuilder from './workflow/WorkflowBuilder';
@@ -428,8 +429,9 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
const data = await response.json();
const tools: OptionType[] = data.tools.map((tool: UserToolType) => ({
id: tool.id,
- label: tool.customName ? tool.customName : tool.displayName,
+ label: getToolDisplayName(tool),
icon: `/toolIcons/tool_${tool.name}.svg`,
+ name: tool.name,
}));
setUserTools(tools);
};
@@ -956,7 +958,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
>
{selectedTools.length > 0
? selectedTools
- .map((tool) => tool.display_name || tool.name)
+ .map((tool) => getToolDisplayName(tool))
.filter(Boolean)
.join(', ')
: t('agents.form.placeholders.selectTools')}
@@ -973,7 +975,10 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
.filter((tool) => newSelectedIds.has(tool.id))
.map((tool) => ({
id: String(tool.id),
- name: tool.label,
+ name:
+ typeof tool.name === 'string'
+ ? tool.name
+ : tool.label,
display_name: tool.label,
})),
)
diff --git a/frontend/src/agents/SharedAgentCard.tsx b/frontend/src/agents/SharedAgentCard.tsx
index a2b02c87..412750fa 100644
--- a/frontend/src/agents/SharedAgentCard.tsx
+++ b/frontend/src/agents/SharedAgentCard.tsx
@@ -1,4 +1,5 @@
import AgentImage from '../components/AgentImage';
+import { getToolDisplayName } from '../utils/toolUtils';
import { Agent } from './types';
export default function SharedAgentCard({ agent }: { agent: Agent }) {
@@ -64,10 +65,10 @@ export default function SharedAgentCard({ agent }: { agent: Agent }) {
>
{' '}
- {tool.name}
+ {getToolDisplayName(tool)}
))}
diff --git a/frontend/src/agents/workflow/WorkflowBuilder.tsx b/frontend/src/agents/workflow/WorkflowBuilder.tsx
index b1b5faf6..12c9a070 100644
--- a/frontend/src/agents/workflow/WorkflowBuilder.tsx
+++ b/frontend/src/agents/workflow/WorkflowBuilder.tsx
@@ -55,6 +55,7 @@ import AgentDetailsModal from '../../modals/AgentDetailsModal';
import ConfirmationModal from '../../modals/ConfirmationModal';
import { ActiveState } from '../../models/misc';
import { selectToken } from '../../preferences/preferenceSlice';
+import { getToolDisplayName } from '../../utils/toolUtils';
import { Agent } from '../types';
import { ConditionCase, WorkflowNode } from '../types/workflow';
import MobileBlocker from './components/MobileBlocker';
@@ -92,6 +93,7 @@ interface UserTool {
id: string;
name: string;
displayName: string;
+ customName?: string;
}
function validateJsonSchemaConfig(schema: unknown): string | null {
@@ -1887,7 +1889,7 @@ function WorkflowBuilderInner() {
({
value: tool.id,
- label: tool.displayName,
+ label: getToolDisplayName(tool),
}))}
selected={
selectedNode.data.config?.tools || []
diff --git a/frontend/src/utils/toolUtils.ts b/frontend/src/utils/toolUtils.ts
new file mode 100644
index 00000000..e97b3429
--- /dev/null
+++ b/frontend/src/utils/toolUtils.ts
@@ -0,0 +1,17 @@
+type ToolLabelSource = {
+ customName?: string | null;
+ displayName?: string | null;
+ display_name?: string | null;
+ name?: string | null;
+};
+
+const isNonEmptyString = (value: unknown): value is string =>
+ typeof value === 'string' && value.trim().length > 0;
+
+export function getToolDisplayName(tool: ToolLabelSource): string {
+ if (isNonEmptyString(tool.customName)) return tool.customName.trim();
+ if (isNonEmptyString(tool.displayName)) return tool.displayName.trim();
+ if (isNonEmptyString(tool.display_name)) return tool.display_name.trim();
+ if (isNonEmptyString(tool.name)) return tool.name.trim();
+ return '';
+}
diff --git a/tests/api/user/test_base.py b/tests/api/user/test_base.py
index 0190ac46..d0843750 100644
--- a/tests/api/user/test_base.py
+++ b/tests/api/user/test_base.py
@@ -150,6 +150,26 @@ class TestResolveToolDetails:
assert result[0]["display_name"] == "test_tool"
+ def test_prefers_custom_name_when_present(self, mock_mongo_db):
+ from application.api.user.base import resolve_tool_details
+ from application.core.settings import settings
+
+ user_tools = mock_mongo_db[settings.MONGO_DB_NAME]["user_tools"]
+ tool_id = ObjectId()
+
+ user_tools.insert_one(
+ {
+ "_id": tool_id,
+ "name": "calculator",
+ "displayName": "Calculator Tool",
+ "customName": "Math Wizard",
+ }
+ )
+
+ result = resolve_tool_details([str(tool_id)])
+
+ assert result[0]["display_name"] == "Math Wizard"
+
def test_empty_tool_ids_list(self, mock_mongo_db):
from application.api.user.base import resolve_tool_details