@lowdefy/ai-utils 5.5.1 → 5.6.0
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/dist/buildAgentTools.js +34 -17
- package/package.json +3 -3
package/dist/buildAgentTools.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { createMCPClient } from '@ai-sdk/mcp';
|
|
17
17
|
import { Experimental_StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio';
|
|
18
18
|
import { ConfigError } from '@lowdefy/errors';
|
|
19
|
-
import { serializer, translate } from '@lowdefy/helpers';
|
|
19
|
+
import { getKey, isReserved, serializer, setKey, translate } from '@lowdefy/helpers';
|
|
20
20
|
import listFiles from './fileSystem/listFiles.js';
|
|
21
21
|
import readFile from './fileSystem/readFile.js';
|
|
22
22
|
import searchFiles from './fileSystem/searchFiles.js';
|
|
@@ -30,7 +30,7 @@ import RESERVED_PLATFORM_TOOL_NAMES from './reservedToolNames.js';
|
|
|
30
30
|
function cleanBuildArtifact(obj) {
|
|
31
31
|
return JSON.parse(JSON.stringify(serializer.deserialize(obj)));
|
|
32
32
|
}
|
|
33
|
-
function
|
|
33
|
+
function assertNotPlatformToolName(name, kind, i18n) {
|
|
34
34
|
if (RESERVED_PLATFORM_TOOL_NAMES.includes(name)) {
|
|
35
35
|
throw new ConfigError(translate({
|
|
36
36
|
key: 'agent.runtime.reservedToolName',
|
|
@@ -59,11 +59,20 @@ async function buildAgentTools({ agent, context, depth = 0 }) {
|
|
|
59
59
|
// Build endpoint tools
|
|
60
60
|
for (const toolConfig of agent.tools ?? []){
|
|
61
61
|
const { endpointId, confirm } = toolConfig;
|
|
62
|
-
|
|
62
|
+
assertNotPlatformToolName(endpointId, 'Endpoint tool', context.i18n);
|
|
63
|
+
// A second, disjoint list: RESERVED_PLATFORM_TOOL_NAMES are the tools Lowdefy itself registers,
|
|
64
|
+
// isReserved are the prototype-pollution keys setKey refuses. A name can pass one gate and fail
|
|
65
|
+
// the other, so both checks are needed. The build rejects reserved key names, so this only fires
|
|
66
|
+
// for a stale or hand-edited build artifact. Skip the tool rather than fail the whole agent, as
|
|
67
|
+
// the MCP name cases below do.
|
|
68
|
+
if (isReserved(endpointId)) {
|
|
69
|
+
console.warn(`Endpoint tool "${endpointId}" uses a reserved key name — skipped.`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
63
72
|
const endpointConfig = await context.getEndpointConfig({
|
|
64
73
|
endpointId
|
|
65
74
|
});
|
|
66
|
-
tools
|
|
75
|
+
setKey(tools, endpointId, tool({
|
|
67
76
|
description: endpointConfig.description,
|
|
68
77
|
inputSchema: jsonSchema(cleanBuildArtifact(endpointConfig.payloadSchema)),
|
|
69
78
|
...confirm ? {
|
|
@@ -83,7 +92,7 @@ async function buildAgentTools({ agent, context, depth = 0 }) {
|
|
|
83
92
|
}
|
|
84
93
|
return cleanBuildArtifact(result.response);
|
|
85
94
|
}
|
|
86
|
-
});
|
|
95
|
+
}));
|
|
87
96
|
}
|
|
88
97
|
// Build MCP clients and merge their tools
|
|
89
98
|
for (const mcpSource of agent.mcp ?? []){
|
|
@@ -132,18 +141,20 @@ async function buildAgentTools({ agent, context, depth = 0 }) {
|
|
|
132
141
|
console.warn(`MCP tool "${name}" from ${source.url ?? source.command} ` + `uses a reserved platform tool name — skipped.`);
|
|
133
142
|
continue;
|
|
134
143
|
}
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
// Same policy as the reserved-platform-name and collision cases above:
|
|
145
|
+
// MCP tool names are not under app control, so warn and skip.
|
|
146
|
+
if (isReserved(name)) {
|
|
147
|
+
console.warn(`MCP tool "${name}" from ${source.url ?? source.command} ` + `uses a reserved key name — skipped.`);
|
|
137
148
|
continue;
|
|
138
149
|
}
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
needsApproval: true
|
|
143
|
-
};
|
|
144
|
-
} else {
|
|
145
|
-
tools[name] = mcpTool;
|
|
150
|
+
if (getKey(tools, name)) {
|
|
151
|
+
console.warn(`MCP tool "${name}" from ${source.url ?? source.command} ` + `conflicts with endpoint tool — skipped.`);
|
|
152
|
+
continue;
|
|
146
153
|
}
|
|
154
|
+
setKey(tools, name, source.confirm ? {
|
|
155
|
+
...mcpTool,
|
|
156
|
+
needsApproval: true
|
|
157
|
+
} : mcpTool);
|
|
147
158
|
}
|
|
148
159
|
} catch (err) {
|
|
149
160
|
const label = source.transport === 'stdio' ? source.command : source.url;
|
|
@@ -152,7 +163,13 @@ async function buildAgentTools({ agent, context, depth = 0 }) {
|
|
|
152
163
|
}
|
|
153
164
|
// Build sub-agent tools
|
|
154
165
|
for (const subAgentRef of agent.agents ?? []){
|
|
155
|
-
|
|
166
|
+
assertNotPlatformToolName(subAgentRef.agentId, 'Sub-agent', context.i18n);
|
|
167
|
+
// Same policy as the endpoint tool name above: unreachable from valid config, so skip rather
|
|
168
|
+
// than fail the whole agent.
|
|
169
|
+
if (isReserved(subAgentRef.agentId)) {
|
|
170
|
+
console.warn(`Sub-agent tool "${subAgentRef.agentId}" uses a reserved key name — skipped.`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
156
173
|
const subAgentConfig = await context.getAgentConfig({
|
|
157
174
|
agentId: subAgentRef.agentId
|
|
158
175
|
});
|
|
@@ -192,7 +209,7 @@ async function buildAgentTools({ agent, context, depth = 0 }) {
|
|
|
192
209
|
'task'
|
|
193
210
|
]
|
|
194
211
|
});
|
|
195
|
-
tools
|
|
212
|
+
setKey(tools, subAgentRef.agentId, tool({
|
|
196
213
|
description,
|
|
197
214
|
inputSchema,
|
|
198
215
|
execute: async (input, { abortSignal })=>{
|
|
@@ -213,7 +230,7 @@ async function buildAgentTools({ agent, context, depth = 0 }) {
|
|
|
213
230
|
type: 'text',
|
|
214
231
|
value: output.text ?? String(output)
|
|
215
232
|
})
|
|
216
|
-
});
|
|
233
|
+
}));
|
|
217
234
|
}
|
|
218
235
|
// Build fileSystem tools
|
|
219
236
|
if (agent.properties?.fileSystem) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/ai-utils",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.6.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@ai-sdk/mcp": "1.0.41",
|
|
20
|
-
"@lowdefy/errors": "5.
|
|
21
|
-
"@lowdefy/helpers": "5.
|
|
20
|
+
"@lowdefy/errors": "5.6.0",
|
|
21
|
+
"@lowdefy/helpers": "5.6.0",
|
|
22
22
|
"ai": "6.0.176",
|
|
23
23
|
"glob": "13.0.6"
|
|
24
24
|
},
|