From 1333b10cd8e492bed88e1d512447a801c614b84d Mon Sep 17 00:00:00 2001 From: cogwheel0 <172976095+cogwheel0@users.noreply.github.com> Date: Sat, 11 Oct 2025 13:27:39 +0530 Subject: [PATCH] feat: enhance model and tools integration with auto-selection functionality - Added a new `toolIds` field to the `Model` class to support tool identification. - Implemented `modelToolsAutoSelectionProvider` to automatically apply model-specific tools when the selected model changes. - Enhanced the logic to filter and set valid tool IDs based on available tools, improving user experience by ensuring relevant tools are automatically selected. - Updated the default model auto-selection provider to initialize the new tools auto-selection feature, ensuring seamless integration within the app's lifecycle. --- lib/core/models/model.dart | 14 ++++++++++ lib/core/providers/app_providers.dart | 37 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/lib/core/models/model.dart b/lib/core/models/model.dart index b0fcac7..712f59f 100644 --- a/lib/core/models/model.dart +++ b/lib/core/models/model.dart @@ -16,6 +16,7 @@ sealed class Model with _$Model { Map? capabilities, Map? metadata, List? supportedParameters, + List? toolIds, }) = _Model; factory Model.fromJson(Map json) { @@ -111,6 +112,18 @@ sealed class Model with _$Model { mergedMetadata['info'] = {...existingInfo, ...infoSection}; } + // Extract toolIds from info.meta.toolIds (OpenWebUI format) + List? toolIds; + final infoMeta = (infoSection?['meta'] as Map?) ?? + (metaSection) ?? + (mergedMetadata['meta'] as Map?); + if (infoMeta != null) { + final toolIdsData = infoMeta['toolIds']; + if (toolIdsData is List) { + toolIds = toolIdsData.map((e) => e.toString()).toList(); + } + } + return Model( id: json['id'] as String, name: json['name'] as String, @@ -126,6 +139,7 @@ sealed class Model with _$Model { 'supported_parameters': supportedParamsList ?? supportedParams, }, metadata: mergedMetadata, + toolIds: toolIds, ); } } diff --git a/lib/core/providers/app_providers.dart b/lib/core/providers/app_providers.dart index b81f6bc..7a91e12 100644 --- a/lib/core/providers/app_providers.dart +++ b/lib/core/providers/app_providers.dart @@ -25,6 +25,7 @@ import '../utils/debug_logger.dart'; import '../models/socket_event.dart'; import '../../shared/theme/color_palettes.dart'; import '../../shared/theme/app_theme.dart'; +import '../../features/tools/providers/tools_providers.dart'; part 'app_providers.g.dart'; @@ -645,9 +646,45 @@ final _settingsWatcherProvider = Provider((ref) { }); }); +// Auto-apply model-specific tools when model changes +final modelToolsAutoSelectionProvider = Provider((ref) { + ref.listen(selectedModelProvider, (previous, next) { + // Only react when the model actually changes + if (previous?.id == next?.id) return; + if (next == null) return; + + // Load tools configured for this model + final modelToolIds = next.toolIds ?? []; + if (modelToolIds.isNotEmpty) { + // Filter to only include tools that are actually available + final toolsAsync = ref.read(toolsListProvider); + toolsAsync.whenData((availableTools) { + final validToolIds = modelToolIds + .where((id) => availableTools.any((t) => t.id == id)) + .toList(); + + if (validToolIds.isNotEmpty) { + ref.read(selectedToolIdsProvider.notifier).set(validToolIds); + DebugLogger.log( + 'auto-apply-tools', + scope: 'models/tools', + data: {'modelId': next.id, 'toolCount': validToolIds.length}, + ); + } + }); + } else { + // Clear tools if model has no configured tools + ref.read(selectedToolIdsProvider.notifier).set([]); + } + }); +}); + // Auto-apply default model from settings when it changes (and not manually overridden) // keepAlive to maintain listener throughout app lifecycle final defaultModelAutoSelectionProvider = Provider((ref) { + // Initialize the model tools auto-selection + ref.watch(modelToolsAutoSelectionProvider); + ref.listen(appSettingsProvider, (previous, next) { // Only react when default model value changes if (previous?.defaultModel == next.defaultModel) return;