Skip to content

Commit 7944913

Browse files
committed
feat(plugin-code-execution): enhance schema validation for code execution and improve error messages
1 parent 0904c0b commit 7944913

File tree

5 files changed

+74
-14
lines changed

5 files changed

+74
-14
lines changed

packages/core/src/executors/agentic/agentic-executor.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,16 @@ export class AgenticExecutor {
104104

105105
const result: CallToolResult = { content: [] };
106106
this.appendToolSchemas(result, definitionsOf, hasDefinitions);
107-
107+
108108
// If no schemas were added (all requested tools already in hasDefinitions), give feedback
109109
if (result.content.length === 0 && definitionsOf.length > 0) {
110110
result.content.push({
111111
type: "text",
112-
text: `All requested tool schemas are already in hasDefinitions. You can now call a tool using "${this.USE_TOOL_KEY}".`,
112+
text:
113+
`All requested tool schemas are already in hasDefinitions. You can now call a tool using "${this.USE_TOOL_KEY}".`,
113114
});
114115
}
115-
116+
116117
return result;
117118
}
118119

@@ -244,7 +245,9 @@ export class AgenticExecutor {
244245
content: [
245246
{
246247
type: "text",
247-
text: `Tool "${useTool}" not found. Available tools: ${this.allToolNames.join(", ")}.`,
248+
text: `Tool "${useTool}" not found. Available tools: ${
249+
this.allToolNames.join(", ")
250+
}.`,
248251
},
249252
],
250253
isError: true,

packages/core/src/factories/args-def-factory.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,21 @@ Workflow step definitions - provide ONLY on initial call.
109109
enum: Object.values(DECISION_OPTIONS),
110110
description:
111111
`**Step control: \`${DECISION_OPTIONS.PROCEED}\` = next step, \`${DECISION_OPTIONS.RETRY}\` = retry/repeat current, \`${DECISION_OPTIONS.COMPLETE}\` = finish workflow**`,
112+
errorMessage: {
113+
enum: `Invalid decision. Must be one of: ${
114+
Object.values(DECISION_OPTIONS).join(", ")
115+
}.`,
116+
},
112117
}),
113118

114119
action: (): JSONSchema => ({
115120
type: "string",
116121
description: "Define the current workflow action to be performed",
117122
enum: allToolNames,
118123
required: ["action"],
124+
errorMessage: {
125+
enum: `Invalid action. Must be one of: ${allToolNames.join(", ")}.`,
126+
},
119127
}),
120128

121129
forTool: function (): JSONSchema {
@@ -162,6 +170,14 @@ Workflow step definitions - provide ONLY on initial call.
162170
},
163171
},
164172
required: ["userRequest", "context"],
173+
errorMessage: {
174+
required: {
175+
userRequest:
176+
"Missing required field 'userRequest'. Please provide a clear task description.",
177+
context:
178+
"Missing required field 'context'. Please provide relevant context (e.g., current working directory).",
179+
},
180+
},
165181
};
166182
},
167183

@@ -183,7 +199,8 @@ Workflow step definitions - provide ONLY on initial call.
183199
required: [toolName],
184200
errorMessage: {
185201
required: {
186-
[toolName]: `Tool "${toolName}" is selected but its parameters are missing. Please provide "${toolName}": { ...parameters }.`,
202+
[toolName]:
203+
`Tool "${toolName}" is selected but its parameters are missing. Please provide "${toolName}": { ...parameters }.`,
187204
},
188205
},
189206
},
@@ -205,7 +222,9 @@ Workflow step definitions - provide ONLY on initial call.
205222
enum: allToolNames,
206223
description: useToolDescription,
207224
errorMessage: {
208-
enum: `Invalid tool name. Available tools: ${allToolNames.join(", ")}.`,
225+
enum: `Invalid tool name. Available tools: ${
226+
allToolNames.join(", ")
227+
}.`,
209228
},
210229
},
211230
hasDefinitions: {
@@ -243,7 +262,10 @@ Workflow step definitions - provide ONLY on initial call.
243262
required: [USE_TOOL_KEY],
244263
errorMessage: {
245264
required: {
246-
[USE_TOOL_KEY]: `No tool selected. Please specify "${USE_TOOL_KEY}" to select one of: ${allToolNames.join(", ")}. Or use "definitionsOf" with tool names to get their schemas first.`,
265+
[USE_TOOL_KEY]:
266+
`No tool selected. Please specify "${USE_TOOL_KEY}" to select one of: ${
267+
allToolNames.join(", ")
268+
}. Or use "definitionsOf" with tool names to get their schemas first.`,
247269
},
248270
},
249271
};

packages/core/src/utils/schema-validator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function validateSchema(
1919
const validate = ajv.compile(schema);
2020
if (!validate(args)) {
2121
const errors = validate.errors!;
22-
22+
2323
// If there are custom errorMessage errors, use only those
2424
const customErrors = errors.filter((err) => err.keyword === "errorMessage");
2525
if (customErrors.length > 0) {
@@ -29,7 +29,7 @@ export function validateSchema(
2929
error: messages.join("; "),
3030
};
3131
}
32-
32+
3333
// Fallback to human-readable error formatting
3434
const aggregateError = new AggregateAjvError(errors);
3535
return {

packages/plugin-code-execution/deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mcpc/plugin-code-execution",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"repository": {
55
"type": "git",
66
"url": "git+https://github.com/mcpc-tech/mcpc.git"

packages/plugin-code-execution/src/plugin.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,32 @@ export function createCodeExecutionPlugin(
6363
"Tool names whose schemas were already provided in this conversation. List all tools you have schemas for to avoid duplicate schema requests",
6464
},
6565
},
66+
// Conditional validation: if code is provided, hasDefinitions must be non-empty
67+
if: {
68+
properties: { code: { type: "string", minLength: 1 } },
69+
required: ["code"],
70+
},
71+
then: {
72+
properties: {
73+
hasDefinitions: { type: "array", minItems: 1 },
74+
},
75+
required: ["hasDefinitions"],
76+
errorMessage: {
77+
required: {
78+
hasDefinitions:
79+
"When executing code, you must provide 'hasDefinitions' with tool schemas you have. First request schemas using 'definitionsOf'.",
80+
},
81+
},
82+
},
83+
// If no code, must have definitionsOf
84+
else: {
85+
anyOf: [
86+
{ required: ["definitionsOf"] },
87+
{ required: ["code"] },
88+
],
89+
errorMessage:
90+
"Provide either 'code' to execute or 'definitionsOf' to request tool schemas.",
91+
},
6692
} as const;
6793

6894
// Register tool with enhanced description
@@ -76,8 +102,8 @@ export function createCodeExecutionPlugin(
76102
const hasDefinitions = (args.hasDefinitions as string[]) || [];
77103
const contentParts: CallToolResult["content"] = [];
78104

79-
// Execute code
80-
if (code && hasDefinitions.length > 0) {
105+
// Execute code (schema validation ensures hasDefinitions is present when code is provided)
106+
if (code) {
81107
if (!executor) throw new Error("Sandbox not initialized");
82108

83109
const result = await executor.executeCode(code, hasDefinitions);
@@ -116,8 +142,17 @@ export function createCodeExecutionPlugin(
116142
}
117143
}
118144

119-
const text = contentParts.map((p) => p.text).join("\n") ||
120-
"No output generated, use console.log() to log output";
145+
// Generate appropriate response message
146+
let text: string;
147+
if (contentParts.length > 0) {
148+
text = contentParts.map((p) => p.text).join("\n");
149+
} else if (definitionsOf.length > 0) {
150+
// All requested schemas already in hasDefinitions
151+
text =
152+
"All requested tool schemas are already available. You can now execute code using 'code' parameter.";
153+
} else {
154+
text = "no output generated, use console.log() to log output";
155+
}
121156

122157
return { content: [{ type: "text", text }] };
123158
},

0 commit comments

Comments
 (0)