/**
* Data Tool
*
* M5 Task 5.6: Second tool for multi-tool coordination testing
*
* Purpose: Manages structured data resources in shared conversation context.
* Tests cross-tool resource access and per-tool permission scoping.
*/
import {
BaseTool,
type ToolIdentity,
type ToolContext,
type ToolResult,
type ToolClass,
} from '../core/tool-interface.js';
import type { ConversationState } from '../core/conversation-migration.js';
import type { SharedContext } from '../core/shared-context.js';
/**
* Data Tool Implementation
*
* Capabilities:
* - create-resource: Create named resource in shared context
* - read-resource: Read resource from shared context
* - update-resource: Update existing resource
* - list-resources: List all resources in shared context
*/
class DataTool extends BaseTool {
constructor() {
super({
name: 'data-tool',
version: '1.0.0',
capabilities: ['create-resource', 'read-resource', 'update-resource', 'list-resources'],
});
}
/**
* Execute tool action
*/
async execute(action: string, context: ToolContext): Promise<ToolResult> {
console.error(`[DataTool] Executing action: ${action}`);
console.error(`[DataTool] Alignment: ${context.alignmentCheck?.alignment || 'none'}`);
// M5: Require shared context
if (!context.sharedContext) {
return {
success: false,
error: 'SharedContext not available in tool context',
};
}
const toolName = context.toolName || 'data-tool';
const args = context.args || {};
switch (action) {
case 'create-resource':
return this.createResource(context.sharedContext, args, toolName);
case 'read-resource':
return this.readResource(context.sharedContext, args);
case 'update-resource':
return this.updateResource(context.sharedContext, args, toolName);
case 'list-resources':
return this.listResources(context.sharedContext);
default:
return {
success: false,
error: `Unknown action: ${action}. Available: create-resource, read-resource, update-resource, list-resources`,
};
}
}
/**
* Create resource in shared context
*/
private createResource(context: SharedContext, args: any, toolName: string): ToolResult {
if (!args.name) {
return {
success: false,
error: 'Required parameter: name',
};
}
if (!args.data) {
return {
success: false,
error: 'Required parameter: data',
};
}
// Check if resource already exists
if (context.hasResource(args.name)) {
return {
success: false,
error: `Resource '${args.name}' already exists. Use update-resource to modify it.`,
};
}
context.createResource(args.name, args.data, toolName);
return {
success: true,
output: {
message: `Resource '${args.name}' created`,
resource: context.getResource(args.name),
},
};
}
/**
* Read resource from shared context
*/
private readResource(context: SharedContext, args: any): ToolResult {
if (!args.name) {
return {
success: false,
error: 'Required parameter: name',
};
}
const resource = context.getResource(args.name);
if (!resource) {
return {
success: false,
error: `Resource '${args.name}' not found`,
};
}
return {
success: true,
output: resource,
};
}
/**
* Update resource in shared context
*/
private updateResource(context: SharedContext, args: any, toolName: string): ToolResult {
if (!args.name) {
return {
success: false,
error: 'Required parameter: name',
};
}
if (!args.data) {
return {
success: false,
error: 'Required parameter: data',
};
}
const updated = context.updateResource(args.name, args.data, toolName);
if (!updated) {
return {
success: false,
error: `Resource '${args.name}' not found`,
};
}
return {
success: true,
output: {
message: `Resource '${args.name}' updated`,
resource: context.getResource(args.name),
},
};
}
/**
* List all resources in shared context
*/
private listResources(context: SharedContext): ToolResult {
const resources = context.listResources();
return {
success: true,
output: {
count: resources.length,
resources: resources.map(r => ({
name: r.name,
createdBy: r.createdBy,
createdAt: new Date(r.createdAt).toISOString(),
updatedAt: new Date(r.updatedAt).toISOString(),
})),
},
};
}
/**
* Restore state after hot-reload
*/
static fromState(state: ConversationState): DataTool {
const tool = new DataTool();
console.error(`[DataTool] Restored from state: conversation ${state.conversationId}`);
return tool;
}
}
/**
* Tool Class Export
*
* Static identity property required for hot-reload and registry discovery
* M5.5: Added actionSchemas for precise parameter requirements (Task 5.9)
*/
const DataToolClass: ToolClass = Object.assign(DataTool, {
identity: {
name: 'data-tool',
version: '1.0.0',
capabilities: ['create-resource', 'read-resource', 'update-resource', 'list-resources'],
} as ToolIdentity,
actionSchemas: {
'create-resource': {
params: ['name', 'data'],
required: ['name', 'data'],
description: 'Create a named resource in shared context',
},
'read-resource': {
params: ['name'],
required: ['name'],
description: 'Read a resource from shared context',
},
'update-resource': {
params: ['name', 'data'],
required: ['name', 'data'],
description: 'Update an existing resource',
},
'list-resources': {
params: [],
required: [],
description: 'List all resources in shared context',
},
},
});
export default DataToolClass;