feat(create-basic-tools): add defensive parameter validation to generated tools

- Add defensive checks for required parameters in generated tool code
- Prevents crashes when tools are called with missing/empty params
- Returns descriptive error messages instead of undefined errors
- Update README with explanation of defensive pattern and best practices
- Bump to v1.0.5

Based on learnings from emoji-magic deployment:
- LLMs sometimes make probe calls with empty params
- Defensive checks prevent crashes and provide better error messages
- Even with Zod validation, runtime checks are valuable for robustness
This commit is contained in:
Ajax Davis 2025-12-05 01:17:08 +10:00
parent 6ec6f790d3
commit 6765ad9f17
3 changed files with 35 additions and 1 deletions

View file

@ -102,6 +102,16 @@ export const exampleTool = tool({
description: 'An example tool - customize this for your use case',
inputSchema: ExampleToolSchema,
async execute(input: z.infer<typeof ExampleToolSchema>) {
// Defensive check: Validate required parameters
// This prevents crashes when tools are called with missing/empty params
if (!input.text || input.text.trim().length === 0) {
return {
success: false,
error: 'Missing required parameter: text',
message: 'The "text" parameter is required and cannot be empty.',
};
}
// TODO: Implement the tool logic here
console.log('exampleTool called with:', input);
@ -114,6 +124,21 @@ export const exampleTool = tool({
});
```
### Why Defensive Parameter Validation?
Generated tools include defensive checks for required parameters. While Zod validates the schema, these checks prevent crashes in edge cases where:
- Tools are called with empty/missing parameters during AI exploration
- Parameters are undefined due to serialization issues
- The LLM makes initial "probe" calls to understand tool capabilities
**Best Practice**: Always validate critical required parameters before using them, especially when:
- The parameter is used in string operations (`.toLowerCase()`, `.trim()`, etc.)
- The parameter is required for the tool's core functionality
- Missing the parameter would cause a runtime error
This defensive approach ensures tools return helpful error messages instead of crashing.
## After Generation
Once the package is generated:

View file

@ -1,6 +1,6 @@
{
"name": "@tpmjs/create-basic-tools",
"version": "1.0.4",
"version": "1.0.5",
"description": "CLI generator for scaffolding production-ready TPMJS tool packages",
"type": "module",
"bin": {

View file

@ -23,6 +23,15 @@ export const ${exportName} = tool({
description: '${description}',
inputSchema: ${schemaName},
async execute(input: z.infer<typeof ${schemaName}>) {
// Defensive check: Validate required parameters
if (!input.text || input.text.trim().length === 0) {
return {
success: false,
error: 'Missing required parameter: text',
message: 'The "text" parameter is required and cannot be empty.',
};
}
// TODO: Implement the tool logic here
console.log('${exportName} called with:', input);