Browse Source

feat: Add system workspace deletion check

pull/1421/head
colin 2 weeks ago
parent
commit
bac6500c9c
  1. 311
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.Designer.cs
  2. 29
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.cs
  3. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs
  4. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordDto.cs
  5. 16
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionAppService.cs
  6. 7
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AIManagementErrorCodes.cs
  7. 6
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AbpAIManagementDomainSharedModule.cs
  8. 1
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json
  9. 1
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json
  10. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs
  11. 3
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs

311
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/20260313034606_Add-IsSystem-To-Workspace-Record.Designer.cs

@ -0,0 +1,311 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<DateTime>("ExpiredAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<DateTime?>("UpdateAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("ReplyAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ReplyMessage")
.HasColumnType("text");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uuid");
b.Property<long?>("CachedInputTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<long?>("InputTokenCount")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<long?>("OutputTokenCount")
.HasColumnType("bigint");
b.Property<long?>("ReasoningTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<long?>("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<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ApiBaseUrl")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ApiKey")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<float?>("FrequencyPenalty")
.HasColumnType("real");
b.Property<string>("Instructions")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<bool>("IsEnabled")
.HasColumnType("boolean");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxOutputTokens")
.HasColumnType("integer");
b.Property<string>("ModelName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<float?>("PresencePenalty")
.HasColumnType("real");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("SystemPrompt")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<float?>("Temperature")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
});
#pragma warning restore 612, 618
}
}
}

29
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
{
/// <inheritdoc />
public partial class AddIsSystemToWorkspaceRecord : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsSystem",
table: "AbpAIWorkspaceDefinitions",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsSystem",
table: "AbpAIWorkspaceDefinitions");
}
}
}

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService.EntityFrameworkCore/Migrations/AIServiceMigrationsDbContextModelSnapshot.cs

@ -252,6 +252,9 @@ namespace LINGYUN.Abp.MicroService.AIService.Migrations
b.Property<bool>("IsEnabled") b.Property<bool>("IsEnabled")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime") b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime"); .HasColumnName("LastModificationTime");

2
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordDto.cs

@ -33,6 +33,8 @@ public class WorkspaceDefinitionRecordDto : ExtensibleAuditedEntityDto<Guid>, IH
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
public bool IsSystem { get; set; }
public string? StateCheckers { get; set; } public string? StateCheckers { get; set; }
public string ConcurrencyStamp { get; set; } public string ConcurrencyStamp { get; set; }

16
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.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Data; using Volo.Abp.Data;
@ -56,6 +57,21 @@ public class WorkspaceDefinitionAppService :
return Task.FromResult(new ListResultDto<ChatClientProviderDto>(providers.ToImmutableArray())); return Task.FromResult(new ListResultDto<ChatClientProviderDto>(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<IQueryable<WorkspaceDefinitionRecord>> CreateFilteredQueryAsync(WorkspaceDefinitionRecordGetListInput input) protected async override Task<IQueryable<WorkspaceDefinitionRecord>> CreateFilteredQueryAsync(WorkspaceDefinitionRecordGetListInput input)
{ {
var queryable = await base.CreateFilteredQueryAsync(input); var queryable = await base.CreateFilteredQueryAsync(input);

7
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"; public const string Prefix = Namespace + ":111";
/// <summary>
/// Workspace {Workspace} already exists!
/// </summary>
public const string NameAlreadyExists = Prefix + "001"; public const string NameAlreadyExists = Prefix + "001";
/// <summary>
/// System workspace {Workspace} is not allowed to be deleted!
/// </summary>
public const string SystemWorkspaceNotAllowedToBeDeleted = Prefix + "002";
} }
} }

6
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/AbpAIManagementDomainSharedModule.cs

@ -1,6 +1,7 @@
using LINGYUN.Abp.AIManagement.Localization; using LINGYUN.Abp.AIManagement.Localization;
using Volo.Abp.Domain; using Volo.Abp.Domain;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
@ -21,5 +22,10 @@ public class AbpAIManagementDomainSharedModule : AbpModule
options.Resources.Add<AIManagementResource>() options.Resources.Add<AIManagementResource>()
.AddVirtualJson("/LINGYUN/Abp/AIManagement/Localization/Resources"); .AddVirtualJson("/LINGYUN/Abp/AIManagement/Localization/Resources");
}); });
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(AIManagementErrorCodes.Namespace, typeof(AIManagementResource));
});
} }
} }

1
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json

@ -2,6 +2,7 @@
"culture": "en", "culture": "en",
"texts": { "texts": {
"AIManagement:111001": "Workspace {Workspace} already exists!", "AIManagement:111001": "Workspace {Workspace} already exists!",
"AIManagement:111002": "System workspace {Workspace} is not allowed to be deleted!",
"DisplayName:MaxLatestHistoryMessagesToKeep": "Carry the recent conversation records", "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.", "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", "Conversations:Delete": "Delete Conversation",

1
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json

@ -2,6 +2,7 @@
"culture": "zh-Hans", "culture": "zh-Hans",
"texts": { "texts": {
"AIManagement:111001": "工作区 {Workspace} 已存在!", "AIManagement:111001": "工作区 {Workspace} 已存在!",
"AIManagement:111002": "系统工作区 {Workspace} 不允许删除!",
"DisplayName:MaxLatestHistoryMessagesToKeep": "携带最近对话记录", "DisplayName:MaxLatestHistoryMessagesToKeep": "携带最近对话记录",
"Description:MaxLatestHistoryMessagesToKeep": "用户发起与大模型对话时,携带用户最近对话记录的上限.", "Description:MaxLatestHistoryMessagesToKeep": "用户发起与大模型对话时,携带用户最近对话记录的上限.",
"Conversations:Delete": "删除对话", "Conversations:Delete": "删除对话",

2
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs

@ -34,6 +34,8 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot<Guid>
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
public bool IsSystem { get; set; }
public string? StateCheckers { get; set; } public string? StateCheckers { get; set; }
protected WorkspaceDefinitionRecord() protected WorkspaceDefinitionRecord()

3
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.SetProperty(property.Key, property.Value);
} }
workspace.IsEnabled = definition.IsEnabled;
workspace.IsSystem = true;
return Task.FromResult(workspace); return Task.FromResult(workspace);
} }
} }

Loading…
Cancel
Save