diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.Designer.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.Designer.cs
new file mode 100644
index 000000000..3f1247abe
--- /dev/null
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.Designer.cs
@@ -0,0 +1,311 @@
+//
+using System;
+using LINGYUN.Abp.MicroService.AIService;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Volo.Abp.EntityFrameworkCore;
+
+#nullable disable
+
+namespace LINGYUN.Abp.MicroService.AIService.Migrations
+{
+ [DbContext(typeof(AIServiceMigrationsDbContext))]
+ [Migration("20260313034606_Add-IsSystem-To-Workspace-Record")]
+ partial class AddIsSystemToWorkspaceRecord
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
+ .HasAnnotation("ProductVersion", "10.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExpiredAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UpdateAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Workspace")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AbpAIConversations", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.Property("ConversationId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("ReplyAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ReplyMessage")
+ .HasColumnType("text");
+
+ b.Property("Role")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("Workspace")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ConversationId");
+
+ b.ToTable("AbpAITextChatMessages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("CachedInputTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("ConversationId")
+ .HasColumnType("uuid");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("InputTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("MessageId")
+ .HasColumnType("uuid");
+
+ b.Property("OutputTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("ReasoningTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("TotalTokenCount")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ConversationId");
+
+ b.ToTable("AbpAITokenUsages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ApiBaseUrl")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("ApiKey")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("Description")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("FrequencyPenalty")
+ .HasColumnType("real");
+
+ b.Property("Instructions")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("IsSystem")
+ .HasColumnType("boolean");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("MaxOutputTokens")
+ .HasColumnType("integer");
+
+ b.Property("ModelName")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("PresencePenalty")
+ .HasColumnType("real");
+
+ b.Property("Provider")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("StateCheckers")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("SystemPrompt")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("Temperature")
+ .HasColumnType("real");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.cs
new file mode 100644
index 000000000..eb0bc436c
--- /dev/null
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.cs
@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace LINGYUN.Abp.MicroService.AIService.Migrations
+{
+ ///
+ public partial class AddIsSystemToWorkspaceRecord : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "IsSystem",
+ table: "AbpAIWorkspaceDefinitions",
+ type: "boolean",
+ nullable: false,
+ defaultValue: false);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "IsSystem",
+ table: "AbpAIWorkspaceDefinitions");
+ }
+ }
+}
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs
index 9cc821579..734232117 100644
--- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs
@@ -252,6 +252,9 @@ namespace LINGYUN.Abp.MicroService.AIService.Migrations
b.Property("IsEnabled")
.HasColumnType("boolean");
+ b.Property("IsSystem")
+ .HasColumnType("boolean");
+
b.Property("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordDto.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordDto.cs
index f65dd0ee9..07cc111c7 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordDto.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordDto.cs
@@ -33,6 +33,8 @@ public class WorkspaceDefinitionRecordDto : ExtensibleAuditedEntityDto, IH
public bool IsEnabled { get; set; }
+ public bool IsSystem { get; set; }
+
public string? StateCheckers { get; set; }
public string ConcurrencyStamp { get; set; }
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionAppService.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionAppService.cs
index 696b331b9..38f7a016a 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionAppService.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionAppService.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
+using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Data;
@@ -56,6 +57,21 @@ public class WorkspaceDefinitionAppService :
return Task.FromResult(new ListResultDto(providers.ToImmutableArray()));
}
+ protected async override Task DeleteByIdAsync(Guid id)
+ {
+ var workspace = await Repository.GetAsync(id);
+
+ if (workspace.IsSystem)
+ {
+ throw new BusinessException(
+ AIManagementErrorCodes.Workspace.SystemWorkspaceNotAllowedToBeDeleted,
+ $"System workspace {workspace.Name} is not allowed to be deleted!")
+ .WithData("Workspace", workspace.Name);
+ }
+
+ await Repository.DeleteAsync(workspace);
+ }
+
protected async override Task> CreateFilteredQueryAsync(WorkspaceDefinitionRecordGetListInput input)
{
var queryable = await base.CreateFilteredQueryAsync(input);
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AIManagementErrorCodes.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AIManagementErrorCodes.cs
index 253c9467d..bdd94b6cd 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AIManagementErrorCodes.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AIManagementErrorCodes.cs
@@ -7,6 +7,13 @@ public static class AIManagementErrorCodes
{
public const string Prefix = Namespace + ":111";
+ ///
+ /// Workspace {Workspace} already exists!
+ ///
public const string NameAlreadyExists = Prefix + "001";
+ ///
+ /// System workspace {Workspace} is not allowed to be deleted!
+ ///
+ public const string SystemWorkspaceNotAllowedToBeDeleted = Prefix + "002";
}
}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AbpAIManagementDomainSharedModule.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AbpAIManagementDomainSharedModule.cs
index 5c0168a94..b6d31ceb0 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AbpAIManagementDomainSharedModule.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AbpAIManagementDomainSharedModule.cs
@@ -1,6 +1,7 @@
using LINGYUN.Abp.AIManagement.Localization;
using Volo.Abp.Domain;
using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@@ -21,5 +22,10 @@ public class AbpAIManagementDomainSharedModule : AbpModule
options.Resources.Add()
.AddVirtualJson("/LINGYUN/Abp/AIManagement/Localization/Resources");
});
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace(AIManagementErrorCodes.Namespace, typeof(AIManagementResource));
+ });
}
}
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json
index dbec885cd..ccdec0db2 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json
@@ -2,6 +2,7 @@
"culture": "en",
"texts": {
"AIManagement:111001": "Workspace {Workspace} already exists!",
+ "AIManagement:111002": "System workspace {Workspace} is not allowed to be deleted!",
"DisplayName:MaxLatestHistoryMessagesToKeep": "Carry the recent conversation records",
"Description:MaxLatestHistoryMessagesToKeep": "When a user initiates a conversation with a large model, the upper limit of the user's recent conversation history that is carried along.",
"Conversations:Delete": "Delete Conversation",
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json
index d749e4ec7..dfe1f5e75 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json
@@ -2,6 +2,7 @@
"culture": "zh-Hans",
"texts": {
"AIManagement:111001": "工作区 {Workspace} 已存在!",
+ "AIManagement:111002": "系统工作区 {Workspace} 不允许删除!",
"DisplayName:MaxLatestHistoryMessagesToKeep": "携带最近对话记录",
"Description:MaxLatestHistoryMessagesToKeep": "用户发起与大模型对话时,携带用户最近对话记录的上限.",
"Conversations:Delete": "删除对话",
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs
index e93500b17..487256815 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs
@@ -34,6 +34,8 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot
public bool IsEnabled { get; set; }
+ public bool IsSystem { get; set; }
+
public string? StateCheckers { get; set; }
protected WorkspaceDefinitionRecord()
diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs
index 94096f797..ec8ad7403 100644
--- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs
+++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs
@@ -71,6 +71,9 @@ public class WorkspaceDefinitionSerializer : IWorkspaceDefinitionSerializer, ITr
workspace.SetProperty(property.Key, property.Value);
}
+ workspace.IsEnabled = definition.IsEnabled;
+ workspace.IsSystem = true;
+
return Task.FromResult(workspace);
}
}