diff --git a/Directory.Packages.props b/Directory.Packages.props
index 9964f7847..df0b5e2c1 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -348,6 +348,8 @@
+
+
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xml b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xsd b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN.Abp.AI.Tools.csproj b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN.Abp.AI.Tools.csproj
new file mode 100644
index 000000000..d82d95f49
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN.Abp.AI.Tools.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0
+ LINGYUN.Abp.AI.Tools
+ LINGYUN.Abp.AI.Tools
+ false
+ false
+ false
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinition.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinition.cs
new file mode 100644
index 000000000..5e4bc9a7e
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinition.cs
@@ -0,0 +1,55 @@
+using JetBrains.Annotations;
+using System.Collections.Generic;
+using Volo.Abp.Localization;
+using Volo.Abp.SimpleStateChecking;
+
+namespace LINGYUN.Abp.AI.Tools;
+
+public class AIToolDefinition : IHasSimpleStateCheckers
+{
+ ///
+ /// 名称
+ ///
+ [NotNull]
+ public string Name { get; }
+ ///
+ /// 提供者
+ ///
+ [NotNull]
+ public string Provider { get; }
+ ///
+ /// 描述
+ ///
+ public ILocalizableString? Description { get; set; }
+ ///
+ /// 属性
+ ///
+ [NotNull]
+ public Dictionary Properties { get; }
+
+ public List> StateCheckers { get; }
+
+ public AIToolDefinition(
+ [NotNull] string name,
+ [NotNull] string provider,
+ ILocalizableString? description = null)
+ {
+ Name = name;
+ Provider = provider;
+ Description = description;
+
+ Properties = new Dictionary();
+ StateCheckers = new List>();
+ }
+
+ public virtual AIToolDefinition WithProperty(string key, object? value)
+ {
+ Properties[key] = value;
+ return this;
+ }
+
+ public override string ToString()
+ {
+ return $"[{nameof(AIToolDefinition)} {Name}]";
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionContext.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionContext.cs
new file mode 100644
index 000000000..319fa6608
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionContext.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class AIToolDefinitionContext : IAIToolDefinitionContext
+{
+ protected Dictionary Tools { get; }
+
+ public AIToolDefinitionContext(Dictionary tools)
+ {
+ Tools = tools;
+ }
+
+ public virtual AIToolDefinition? GetOrNull(string name)
+ {
+ return Tools.GetOrDefault(name);
+ }
+
+ public virtual IReadOnlyList GetAll()
+ {
+ return Tools.Values.ToImmutableList();
+ }
+
+ public virtual void Add(params AIToolDefinition[] definitions)
+ {
+ if (definitions.IsNullOrEmpty())
+ {
+ return;
+ }
+
+ foreach (var definition in definitions)
+ {
+ Tools[definition.Name] = definition;
+ }
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs
new file mode 100644
index 000000000..2c33bc160
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionManager.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class AIToolDefinitionManager : IAIToolDefinitionManager, ISingletonDependency
+{
+ protected readonly IStaticAIToolDefinitionStore StaticStore;
+ protected readonly IDynamicAIToolDefinitionStore DynamicStore;
+
+ public AIToolDefinitionManager(
+ IStaticAIToolDefinitionStore staticStore,
+ IDynamicAIToolDefinitionStore dynamicStore)
+ {
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
+ }
+
+ public virtual async Task GetAsync(string name)
+ {
+ var workspace = await GetOrNullAsync(name);
+ if (workspace == null)
+ {
+ throw new AbpException("Undefined AITool: " + name);
+ }
+
+ return workspace;
+ }
+
+ public virtual async Task GetOrNullAsync(string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ return await StaticStore.GetOrNullAsync(name) ?? await DynamicStore.GetOrNullAsync(name);
+ }
+
+ public virtual async Task> GetAllAsync()
+ {
+ var staticAITools = await StaticStore.GetAllAsync();
+ var staticAIToolNames = staticAITools
+ .Select(p => p.Name)
+ .ToImmutableHashSet();
+
+ var dynamicAITools = await DynamicStore.GetAllAsync();
+
+ return staticAITools.Concat(dynamicAITools.Where(d => !staticAIToolNames.Contains(d.Name)))
+ .ToImmutableList();
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionProvider.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionProvider.cs
new file mode 100644
index 000000000..ab3641d8f
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolDefinitionProvider.cs
@@ -0,0 +1,7 @@
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AI.Tools;
+public abstract class AIToolDefinitionProvider : IAIToolDefinitionProvider, ITransientDependency
+{
+ public abstract void Define(IAIToolDefinitionContext context);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolFactory.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolFactory.cs
new file mode 100644
index 000000000..5d9a34fc3
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolFactory.cs
@@ -0,0 +1,55 @@
+using Microsoft.Extensions.AI;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.SimpleStateChecking;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class AIToolFactory : IAIToolFactory, ITransientDependency
+{
+ protected ISimpleStateCheckerManager StateCheckerManager { get; }
+ protected IAIToolDefinitionManager AIToolDefinitionManager { get; }
+ protected IAIToolProviderManager AIToolProviderManager { get; }
+
+ public AIToolFactory(
+ ISimpleStateCheckerManager stateCheckerManager,
+ IAIToolDefinitionManager aIToolDefinitionManager,
+ IAIToolProviderManager aIToolProviderManager)
+ {
+ StateCheckerManager = stateCheckerManager;
+ AIToolDefinitionManager = aIToolDefinitionManager;
+ AIToolProviderManager = aIToolProviderManager;
+ }
+
+ public virtual AITool CreateTool(AIToolDefinition definition)
+ {
+ foreach (var provider in AIToolProviderManager.Providers)
+ {
+ if (!string.Equals(provider.Name, definition.Provider))
+ {
+ continue;
+ }
+
+ return provider.CreateTool(definition);
+ }
+
+ throw new AbpException($"The AITool provider implementation named {definition.Provider} was not found!");
+ }
+
+ public async virtual Task CreateAllTools()
+ {
+ var aiTools = new List();
+ var toolDefines = await AIToolDefinitionManager.GetAllAsync();
+
+ foreach (var toolDefine in toolDefines)
+ {
+ if (await StateCheckerManager.IsEnabledAsync(toolDefine))
+ {
+ aiTools.Add(CreateTool(toolDefine));
+ }
+ }
+
+ return aiTools.ToArray();
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolProviderManager.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolProviderManager.cs
new file mode 100644
index 000000000..e58c40a14
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AIToolProviderManager.cs
@@ -0,0 +1,45 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class AIToolProviderManager : IAIToolProviderManager, ISingletonDependency
+{
+ public List Providers => _lazyProviders.Value;
+
+ protected AbpAIToolsOptions Options { get; }
+ protected IServiceProvider ServiceProvider { get; }
+
+ private readonly Lazy> _lazyProviders;
+
+ public AIToolProviderManager(
+ IServiceProvider serviceProvider,
+ IOptions options)
+ {
+
+ Options = options.Value;
+ ServiceProvider = serviceProvider;
+
+ _lazyProviders = new Lazy>(GetProviders, true);
+ }
+
+ protected virtual List GetProviders()
+ {
+ var providers = Options
+ .AIToolProviders
+ .Select(type => (ServiceProvider.GetRequiredService(type) as IAIToolProvider)!)
+ .ToList();
+
+ var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1);
+ if (multipleProviders != null)
+ {
+ throw new AbpException($"Duplicate AITool provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}");
+ }
+
+ return providers;
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
new file mode 100644
index 000000000..30029e5f5
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsModule.cs
@@ -0,0 +1,80 @@
+using LINGYUN.Abp.AI.Localization;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using Volo.Abp.Localization;
+using Volo.Abp.Modularity;
+using Volo.Abp.VirtualFileSystem;
+
+namespace LINGYUN.Abp.AI.Tools;
+
+[DependsOn(typeof(AbpAICoreModule))]
+public class AbpAIToolsModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ AutoAddDefinitionProviders(context.Services);
+ }
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ // 自定义函数工具
+ options.AIToolProviders.Add();
+ });
+
+ Configure(options =>
+ {
+ options.ChatClientBuildActions.Add(async (_, sp, builder) =>
+ {
+ var aiToolFactory = sp.GetRequiredService();
+ var aiTools = await aiToolFactory.CreateAllTools();
+
+ builder.ConfigureOptions(ai =>
+ {
+ ai.ToolMode = ChatToolMode.Auto;
+ ai.AllowMultipleToolCalls = true;
+
+ ai.Tools ??= [];
+
+ foreach (var aiTool in aiTools)
+ {
+ ai.Tools.Add(aiTool);
+ }
+ });
+ });
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Get()
+ .AddVirtualJson("/LINGYUN/Abp/AI/Tools/Localization/Resources");
+ });
+ }
+
+ private static void AutoAddDefinitionProviders(IServiceCollection services)
+ {
+ var definitionProviders = new List();
+
+ services.OnRegistered(context =>
+ {
+ if (typeof(IAIToolDefinitionProvider).IsAssignableFrom(context.ImplementationType))
+ {
+ definitionProviders.Add(context.ImplementationType);
+ }
+ });
+
+ services.Configure(options =>
+ {
+ options.DefinitionProviders.AddIfNotContains(definitionProviders);
+ });
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs
new file mode 100644
index 000000000..c2d4d872c
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/AbpAIToolsOptions.cs
@@ -0,0 +1,13 @@
+using Volo.Abp.Collections;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class AbpAIToolsOptions
+{
+ public ITypeList DefinitionProviders { get; }
+ public ITypeList AIToolProviders { get; }
+ public AbpAIToolsOptions()
+ {
+ DefinitionProviders = new TypeList();
+ AIToolProviders = new TypeList();
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolDefinitionExtenssions.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolDefinitionExtenssions.cs
new file mode 100644
index 000000000..56f9e9e98
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolDefinitionExtenssions.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using Volo.Abp;
+
+namespace LINGYUN.Abp.AI.Tools;
+public static class FunctionAIToolDefinitionExtenssions
+{
+ private const string FunctionType = "Function";
+ public static AIToolDefinition WithFunction(this AIToolDefinition definition)
+ {
+ return definition.WithFunction(typeof(TFunc));
+ }
+
+ public static AIToolDefinition WithFunction(this AIToolDefinition definition, Type funcType)
+ {
+ Check.NotNull(funcType, nameof(funcType));
+
+ definition.WithProperty(FunctionType, funcType);
+
+ return definition;
+ }
+
+ public static Type GetFunction(this AIToolDefinition definition)
+ {
+ var funcTypeSet = definition.Properties.GetOrDefault(FunctionType);
+ Check.NotNull(funcTypeSet, nameof(FunctionType));
+
+ var funcType = Type.GetType(funcTypeSet.ToString()!);
+
+ Check.NotNull(funcType, nameof(funcType));
+
+ return funcType;
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolProvider.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolProvider.cs
new file mode 100644
index 000000000..fea88cecb
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/FunctionAIToolProvider.cs
@@ -0,0 +1,48 @@
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Localization;
+using System;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class FunctionAIToolProvider : IAIToolProvider, ITransientDependency
+{
+ public const string ProviderName = "Function";
+ public string Name => ProviderName;
+
+ protected IServiceProvider ServiceProvider { get; }
+ public FunctionAIToolProvider(IServiceProvider serviceProvider)
+ {
+ ServiceProvider = serviceProvider;
+ }
+
+ public virtual AITool CreateTool(AIToolDefinition definition)
+ {
+ var aiToolType = definition.GetFunction();
+ // 框架约定, 自定义Tool只需要定义同步方法(Invoke)或异步方法(InvokeAsync)即可
+ var aiToolMethodInfo = aiToolType.GetMethod("Invoke") ?? aiToolType.GetMethod("InvokeAsync");
+
+ Check.NotNull(aiToolMethodInfo, nameof(aiToolMethodInfo));
+
+ string? description = null;
+ if (definition.Description != null)
+ {
+ var localizerFactory = ServiceProvider.GetRequiredService();
+ description = definition.Description.Localize(localizerFactory)?.Value;
+ }
+
+ return AIFunctionFactory.Create(
+ method: aiToolMethodInfo,
+ createInstanceFunc: (AIFunctionArguments args) =>
+ {
+ return ActivatorUtilities.CreateInstance(args.Services ?? ServiceProvider, aiToolType);
+ },
+ options: new AIFunctionFactoryOptions
+ {
+ Name = definition.Name,
+ Description = description,
+ AdditionalProperties = definition.Properties,
+ });
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/GlobalAIToolDefinitionProvider.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/GlobalAIToolDefinitionProvider.cs
new file mode 100644
index 000000000..03cfbc3ae
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/GlobalAIToolDefinitionProvider.cs
@@ -0,0 +1,41 @@
+using LINGYUN.Abp.AI.Localization;
+using LINGYUN.Abp.AI.Tools.Settings;
+using LINGYUN.Abp.AI.Tools.Timing;
+using LINGYUN.Abp.AI.Tools.Users;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.AI.Tools;
+public class GlobalAIToolDefinitionProvider : AIToolDefinitionProvider
+{
+ public override void Define(IAIToolDefinitionContext context)
+ {
+ context.Add(
+ new AIToolDefinition(
+ NowTimeTool.Name,
+ FunctionAIToolProvider.ProviderName,
+ L("Tools:GetNowTime"))
+ .WithFunction(),
+
+ new AIToolDefinition(
+ CurrentUserTool.Name,
+ FunctionAIToolProvider.ProviderName,
+ L("Tools:GetUserInfo"))
+ .WithFunction(),
+
+ new AIToolDefinition(
+ GetSettingTool.Name,
+ FunctionAIToolProvider.ProviderName,
+ L("Tools:GetSetting"))
+ .WithFunction(),
+ new AIToolDefinition(
+ GetSettingsTool.Name,
+ FunctionAIToolProvider.ProviderName,
+ L("Tools:GetSettings"))
+ .WithFunction());
+ }
+
+ private static LocalizableString L(string name)
+ {
+ return LocalizableString.Create(name);
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionContext.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionContext.cs
new file mode 100644
index 000000000..20cc54b27
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionContext.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IAIToolDefinitionContext
+{
+ AIToolDefinition? GetOrNull(string name);
+
+ IReadOnlyList GetAll();
+
+ void Add(params AIToolDefinition[] definitions);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionManager.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionManager.cs
new file mode 100644
index 000000000..430763b06
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionManager.cs
@@ -0,0 +1,16 @@
+using JetBrains.Annotations;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IAIToolDefinitionManager
+{
+ [NotNull]
+ Task GetAsync([NotNull] string name);
+
+ [ItemNotNull]
+ Task> GetAllAsync();
+
+ [CanBeNull]
+ Task GetOrNullAsync([NotNull] string name);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionProvider.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionProvider.cs
new file mode 100644
index 000000000..29cd49430
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolDefinitionProvider.cs
@@ -0,0 +1,5 @@
+namespace LINGYUN.Abp.AI.Tools;
+public interface IAIToolDefinitionProvider
+{
+ void Define(IAIToolDefinitionContext context);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolFactory.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolFactory.cs
new file mode 100644
index 000000000..929403ab3
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolFactory.cs
@@ -0,0 +1,10 @@
+using Microsoft.Extensions.AI;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IAIToolFactory
+{
+ AITool CreateTool(AIToolDefinition definition);
+
+ Task CreateAllTools();
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProvider.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProvider.cs
new file mode 100644
index 000000000..2d65d95eb
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProvider.cs
@@ -0,0 +1,9 @@
+using Microsoft.Extensions.AI;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IAIToolProvider
+{
+ string Name { get; }
+
+ AITool CreateTool(AIToolDefinition definition);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProviderManager.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProviderManager.cs
new file mode 100644
index 000000000..5a565483d
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IAIToolProviderManager.cs
@@ -0,0 +1,7 @@
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IAIToolProviderManager
+{
+ List Providers { get; }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IDynamicAIToolDefinitionStore.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IDynamicAIToolDefinitionStore.cs
new file mode 100644
index 000000000..b980cc406
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IDynamicAIToolDefinitionStore.cs
@@ -0,0 +1,13 @@
+using JetBrains.Annotations;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IDynamicAIToolDefinitionStore
+{
+ Task GetAsync([NotNull] string name);
+
+ Task> GetAllAsync();
+
+ Task GetOrNullAsync([NotNull] string name);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IStaticAIToolDefinitionStore.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IStaticAIToolDefinitionStore.cs
new file mode 100644
index 000000000..d938ce26f
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/IStaticAIToolDefinitionStore.cs
@@ -0,0 +1,13 @@
+using JetBrains.Annotations;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.AI.Tools;
+public interface IStaticAIToolDefinitionStore
+{
+ Task GetAsync([NotNull] string name);
+
+ Task> GetAllAsync();
+
+ Task GetOrNullAsync([NotNull] string name);
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/en.json b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/en.json
new file mode 100644
index 000000000..7a1b2b9f1
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/en.json
@@ -0,0 +1,10 @@
+{
+ "culture": "en",
+ "texts": {
+ "Tools": "Tools",
+ "Tools:GetNowTime": "Get now time",
+ "Tools:GetUserInfo": "Get the current user information",
+ "Tools:GetSetting": "Get setting value",
+ "Tools:GetSettings": "Get all settings"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/zh-Hans.json b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/zh-Hans.json
new file mode 100644
index 000000000..0b5545756
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Localization/Resources/zh-Hans.json
@@ -0,0 +1,10 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "Tools": "工具列表",
+ "Tools:GetNowTime": "获取当前时间",
+ "Tools:GetUserInfo": "获取当前用户信息",
+ "Tools:GetSetting": "获取设置值",
+ "Tools:GetSettings": "获取所有设置"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/NullDynamicAIToolDefinitionStore.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/NullDynamicAIToolDefinitionStore.cs
new file mode 100644
index 000000000..b108cf9d6
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/NullDynamicAIToolDefinitionStore.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.AI.Tools;
+
+[Dependency(TryRegister = true)]
+public class NullDynamicAIToolDefinitionStore : IDynamicAIToolDefinitionStore, ISingletonDependency
+{
+ private readonly static Task CachedNullableAIToolResult = Task.FromResult((AIToolDefinition?)null);
+ private readonly static Task CachedAIToolResult = Task.FromResult((AIToolDefinition)null!);
+
+ private readonly static Task> CachedAIToolsResult = Task.FromResult(
+ (IReadOnlyList)Array.Empty().ToImmutableList());
+
+ public Task GetAsync(string name)
+ {
+ return CachedAIToolResult;
+ }
+
+ public Task> GetAllAsync()
+ {
+ return CachedAIToolsResult;
+ }
+
+ public Task GetOrNullAsync(string name)
+ {
+ return CachedNullableAIToolResult;
+ }
+}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingTool.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingTool.cs
new file mode 100644
index 000000000..b5ee97281
--- /dev/null
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools/LINGYUN/Abp/AI/Tools/Settings/GetSettingTool.cs
@@ -0,0 +1,20 @@
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Settings;
+
+namespace LINGYUN.Abp.AI.Tools.Settings;
+public class GetSettingTool : ITransientDependency
+{
+ public const string Name = "GetSetting";
+
+ private readonly ISettingProvider _settingProvider;
+ public GetSettingTool(ISettingProvider settingProvider)
+ {
+ _settingProvider = settingProvider;
+ }
+
+ public async Task