#!/usr/bin/env node
/**
* Task 5.9: Action-Specific Schema Generation Test
*
* Verifies that tools with actionSchemas generate precise parameter schemas
*/
import { ToolRegistry } from './dist/core/tool-registry.js';
const registry = new ToolRegistry();
await registry.loadTools();
console.log('=== Task 5.9: Action-Specific Schema Generation ===\n');
// Helper to generate schema (same logic as in index.ts)
function generateToolSchema(toolClass) {
const identity = toolClass?.identity;
const actionSchemas = toolClass?.actionSchemas;
if (actionSchemas && Object.keys(actionSchemas).length > 0) {
const oneOfSchemas = Object.entries(actionSchemas).map(([action, schema]) => {
const properties = {
action: {
type: 'string',
const: action,
description: schema.description || action,
},
conversationId: {
type: 'string',
description: 'Conversation ID for multi-user isolation (optional, defaults to "default")',
},
};
if (schema.params && schema.params.length > 0) {
for (const param of schema.params) {
if (param === 'data') {
properties[param] = { type: 'object', description: 'Resource data' };
} else {
properties[param] = { type: 'string', description: `${param} parameter` };
}
}
}
return {
type: 'object',
properties,
required: ['action', ...(schema.required || [])],
};
});
return { oneOf: oneOfSchemas };
}
return { type: 'object', properties: {}, required: ['action'] };
}
// Test 1: Verify data-tool has precise schemas
console.log('Test 1: data-tool schema precision');
const dataToolClass = registry.getTool('data-tool');
const dataSchema = generateToolSchema(dataToolClass);
console.assert(dataSchema.oneOf, 'data-tool should have oneOf schema');
console.assert(dataSchema.oneOf.length === 4, `data-tool should have 4 action schemas (got ${dataSchema.oneOf.length})`);
// Check create-resource schema
const createResourceSchema = dataSchema.oneOf.find(s => s.properties.action.const === 'create-resource');
console.assert(createResourceSchema, 'Should have create-resource schema');
console.assert(createResourceSchema.properties.name, 'create-resource should have name param');
console.assert(createResourceSchema.properties.data, 'create-resource should have data param');
console.assert(createResourceSchema.required.includes('name'), 'name should be required');
console.assert(createResourceSchema.required.includes('data'), 'data should be required');
console.log('✅ PASSED: data-tool create-resource has precise schema\n');
// Check read-resource schema
const readResourceSchema = dataSchema.oneOf.find(s => s.properties.action.const === 'read-resource');
console.assert(readResourceSchema, 'Should have read-resource schema');
console.assert(readResourceSchema.properties.name, 'read-resource should have name param');
console.assert(!readResourceSchema.properties.data, 'read-resource should NOT have data param');
console.assert(readResourceSchema.required.includes('name'), 'name should be required');
console.assert(!readResourceSchema.required.includes('data'), 'data should NOT be required');
console.log('✅ PASSED: data-tool read-resource has precise schema (no data param)\n');
// Test 2: Verify example-tool has precise schemas with no params
console.log('Test 2: example-tool schema precision');
const exampleToolClass = registry.getTool('example-tool');
const exampleSchema = generateToolSchema(exampleToolClass);
console.assert(exampleSchema.oneOf, 'example-tool should have oneOf schema');
console.assert(exampleSchema.oneOf.length === 7, `example-tool should have 7 action schemas (got ${exampleSchema.oneOf.length})`);
// Check greet schema (should have no params beyond action and conversationId)
const greetSchema = exampleSchema.oneOf.find(s => s.properties.action.const === 'greet');
console.assert(greetSchema, 'Should have greet schema');
const greetParamCount = Object.keys(greetSchema.properties).length;
console.assert(greetParamCount === 2, `greet should only have action + conversationId (got ${greetParamCount} params)`);
console.assert(greetSchema.required.length === 1, `greet should only require action (got ${greetSchema.required.length} required)`);
console.log('✅ PASSED: example-tool greet has minimal schema (no extra params)\n');
// Test 3: Verify admin-tool schemas
console.log('Test 3: admin-tool schema precision');
const adminToolClass = registry.getTool('admin-tool');
const adminSchema = generateToolSchema(adminToolClass);
console.assert(adminSchema.oneOf, 'admin-tool should have oneOf schema');
console.assert(adminSchema.oneOf.length === 2, `admin-tool should have 2 action schemas (got ${adminSchema.oneOf.length})`);
// Check delete-resource schema
const deleteResourceSchema = adminSchema.oneOf.find(s => s.properties.action.const === 'delete-resource');
console.assert(deleteResourceSchema, 'Should have delete-resource schema');
console.assert(deleteResourceSchema.properties.name, 'delete-resource should have name param');
console.assert(!deleteResourceSchema.properties.data, 'delete-resource should NOT have data param');
console.log('✅ PASSED: admin-tool delete-resource has precise schema\n');
// Test 4: Verify schema descriptions
console.log('Test 4: Schema descriptions');
console.assert(
createResourceSchema.properties.action.description === 'Create a named resource in shared context',
'create-resource should have descriptive text'
);
console.assert(
greetSchema.properties.action.description === 'Greet and return tool version',
'greet should have descriptive text'
);
console.log('✅ PASSED: Actions have descriptive documentation\n');
console.log('=== All Task 5.9 Tests PASSED ===');
console.log('\nSchema precision benefits:');
console.log('- create-resource: Shows name + data (hides irrelevant params)');
console.log('- read-resource: Shows only name (hides data)');
console.log('- greet: Shows no params (clean, focused UX)');
console.log('- IDE autocomplete now shows only relevant params per action');