From f0ae3b31e2d63792316fcf6c490422601780cc90 Mon Sep 17 00:00:00 2001 From: qzl Date: Sat, 28 Feb 2026 13:36:30 +0800 Subject: [PATCH] feat(chat): add ToolRegistry with validation --- .../chat/data/tools/tool_registry.dart | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 apps/lib/features/chat/data/tools/tool_registry.dart diff --git a/apps/lib/features/chat/data/tools/tool_registry.dart b/apps/lib/features/chat/data/tools/tool_registry.dart new file mode 100644 index 0000000..4a88b58 --- /dev/null +++ b/apps/lib/features/chat/data/tools/tool_registry.dart @@ -0,0 +1,130 @@ +typedef ToolHandler = + Future> Function(Map args); + +class ToolDefinition { + final String name; + final String description; + final Map parameters; + final ToolHandler handler; + + ToolDefinition({ + required this.name, + required this.description, + required this.parameters, + required this.handler, + }); +} + +class ToolRegistry { + static final Map _tools = {}; + static bool _initialized = false; + + static void initialize() { + if (_initialized) return; + + _tools['create_calendar_event'] = ToolDefinition( + name: 'create_calendar_event', + description: '创建一个日历事件或待办事项', + parameters: { + 'type': 'object', + 'properties': { + 'title': { + 'type': 'string', + 'description': '事件标题', + 'minLength': 1, + 'maxLength': 100, + }, + 'description': {'type': 'string', 'description': '事件描述'}, + 'startAt': { + 'type': 'string', + 'format': 'date-time', + 'description': '开始时间 (ISO8601)', + }, + 'endAt': { + 'type': 'string', + 'format': 'date-time', + 'description': '结束时间 (ISO8601)', + }, + 'timezone': {'type': 'string', 'default': 'Asia/Shanghai'}, + 'location': {'type': 'string'}, + 'notes': {'type': 'string'}, + }, + 'required': ['title', 'startAt'], + }, + handler: _handleCreateCalendarEvent, + ); + + _initialized = true; + } + + static Future> _handleCreateCalendarEvent( + Map args, + ) async { + final eventId = 'evt_${DateTime.now().millisecondsSinceEpoch}'; + return { + 'eventId': eventId, + 'ok': true, + 'message': '日程已创建', + 'title': args['title'], + 'description': args['description'], + 'startAt': args['startAt'], + 'endAt': args['endAt'], + 'timezone': args['timezone'] ?? 'Asia/Shanghai', + 'location': args['location'], + 'color': '#4F46E5', + 'sourceType': 'agentGenerated', + }; + } + + static ToolDefinition? getTool(String name) => _tools[name]; + static List getAllTools() => _tools.values.toList(); + + static Future> execute( + String toolName, + Map args, + ) async { + final tool = _tools[toolName]; + if (tool == null) throw ToolNotFoundException('Tool not found: $toolName'); + return tool.handler(args); + } + + static ToolValidationResult validateArgs( + String toolName, + Map args, + ) { + final tool = _tools[toolName]; + if (tool == null) + return ToolValidationResult( + ok: false, + error: 'Tool not found: $toolName', + ); + + final required = tool.parameters['required'] as List? ?? []; + final missing = []; + for (final field in required) { + if (!args.containsKey(field) || args[field] == null) + missing.add(field as String); + } + + if (missing.isNotEmpty) { + return ToolValidationResult( + ok: false, + error: 'Missing required fields: ${missing.join(', ')}', + ); + } + return ToolValidationResult(ok: true); + } +} + +class ToolNotFoundException implements Exception { + final String message; + ToolNotFoundException(this.message); + @override + String toString() => 'ToolNotFoundException: $message'; +} + +class ToolValidationResult { + final bool ok; + final String? error; + ToolValidationResult({required this.ok, this.error}); +}