chore(evaluation): remove enterprise feature ownership from OSS (#22173)

This commit is contained in:
Sbaaoui Idriss authored and GitHub committed 2026-11-09 19:19:48 +08:00
1 parent 70b09ce5af
commit 8e3e549a34
11 files changed
+58 -153

No files matched your search

@@ -331,7 +331,7 @@ the fields they display.
| Resource table | Owner source |
|----------------|--------------|
| `chat_channel`, `compilation_template_group`, `compilation_template`, `connector`, `dialog`, `memory`, `mcp_server`, `skill_spaces` | `tenant_id` |
| `file`, `knowledgebase`, `search`, `evaluation_datasets` | `created_by`; if empty, `tenant_id` |
| `file`, `knowledgebase`, `search` | `created_by`; if empty, `tenant_id` |
| `document` | `created_by` |
Tables that do not exist are skipped. If a listed table exists but its `user_id` or owner-source column is missing after `AutoMigrate`, the migration stops with an error. When the source values are empty, the resulting `user_id` remains empty.
+1 -35
View File
@@ -437,24 +437,19 @@ func (data *userDeletionData) deleteDatabaseRows(ctx context.Context, tx *gorm.D
}
owner := data.ownedTenantID
var chatIDs, canvasIDs, conversationIDs, apiConversationIDs []string
var evaluationDatasetIDs, evaluationRunIDs, connectorIDs, providerIDs, instanceIDs, modelIDs []string
var connectorIDs, providerIDs, instanceIDs, modelIDs []string
var ingestionTaskIDs, pipelineLogIDs, memoryTaskIDs, commitIDs []string
var err error
if owner != "" {
if chatIDs, err = selectIDs(&entity.Chat{}, "tenant_id = ?", owner); err != nil {
return err
}
if evaluationDatasetIDs, err = selectIDs(&entity.EvaluationDataset{}, "tenant_id = ? OR created_by = ?", owner, userID); err != nil {
return err
}
if connectorIDs, err = selectIDs(&entity.Connector{}, "tenant_id = ?", owner); err != nil {
return err
}
if providerIDs, err = selectIDs(&entity.TenantModelProvider{}, "tenant_id = ?", owner); err != nil {
return err
}
} else if evaluationDatasetIDs, err = selectIDs(&entity.EvaluationDataset{}, "created_by = ?", userID); err != nil {
return err
}
if canvasIDs, err = selectIDs(&entity.UserCanvas{}, "user_id = ?", userID); err != nil {
return err
@@ -479,14 +474,6 @@ func (data *userDeletionData) deleteDatabaseRows(ctx context.Context, tx *gorm.D
if err != nil {
return err
}
if len(evaluationDatasetIDs) > 0 {
evaluationRunIDs, err = selectIDs(&entity.EvaluationRun{}, "dataset_id IN ? OR created_by = ?", evaluationDatasetIDs, userID)
} else {
evaluationRunIDs, err = selectIDs(&entity.EvaluationRun{}, "created_by = ?", userID)
}
if err != nil {
return err
}
if len(providerIDs) > 0 {
if instanceIDs, err = selectIDs(&entity.TenantModelInstance{}, "provider_id IN ?", providerIDs); err != nil {
return err
@@ -579,27 +566,6 @@ func (data *userDeletionData) deleteDatabaseRows(ctx context.Context, tx *gorm.D
if err := removeIDs("agents", &entity.UserCanvas{}, "id", canvasIDs); err != nil {
return err
}
if err := removeIDs("evaluation results", &entity.EvaluationResult{}, "run_id", evaluationRunIDs); err != nil {
return err
}
if err := removeIDs("evaluation runs", &entity.EvaluationRun{}, "id", evaluationRunIDs); err != nil {
return err
}
if len(evaluationDatasetIDs) > 0 {
var caseIDs []string
if caseIDs, err = selectIDs(&entity.EvaluationCase{}, "dataset_id IN ?", evaluationDatasetIDs); err != nil {
return err
}
if err := removeIDs("evaluation results", &entity.EvaluationResult{}, "case_id", caseIDs); err != nil {
return err
}
if err := removeIDs("evaluation cases", &entity.EvaluationCase{}, "id", caseIDs); err != nil {
return err
}
if err := removeIDs("evaluation datasets", &entity.EvaluationDataset{}, "id", evaluationDatasetIDs); err != nil {
return err
}
}
if err := removeIDs("ingestion task logs", &entity.IngestionTaskLog{}, "task_id", ingestionTaskIDs); err != nil {
return err
}
+13 -1
View File
@@ -126,7 +126,6 @@ func setupUserDeletionDB(t *testing.T) *gorm.DB {
&entity.Search{}, &entity.Memory{}, &entity.MemoryTask{}, &entity.MCPServer{},
&entity.SkillSearchConfig{},
&entity.CompilationTemplate{}, &entity.CompilationTemplateGroup{},
&entity.EvaluationDataset{}, &entity.EvaluationCase{}, &entity.EvaluationRun{}, &entity.EvaluationResult{},
&entity.Connector{}, &entity.Connector2Kb{}, &entity.SyncLogs{},
&entity.KnowledgeCompileDataset{}, &entity.WikiDocumentDirty{}, &entity.PipelineOperationLog{},
&entity.IngestionTask{}, &entity.IngestionTaskLog{}, &entity.FileCommit{}, &entity.FileCommitItem{},
@@ -190,6 +189,10 @@ func TestDeleteUserRemovesOwnedDataAndJoinedDocuments(t *testing.T) {
insert("INSERT INTO file_commit (id, folder_id, message, author_id, file_count) VALUES (?, ?, ?, ?, ?)", "other-commit", "team-kb", "Other page edit", "user-2", 1)
insert("INSERT INTO file_commit_item (id, commit_id, file_id, operation) VALUES (?, ?, ?, ?)", "other-commit-item", "other-commit", "other-page", "add")
for _, table := range []string{"evaluation_datasets", "evaluation_cases", "evaluation_runs", "evaluation_results"} {
insert("CREATE TABLE " + table + " (id TEXT, tenant_id TEXT, created_by TEXT, dataset_id TEXT, run_id TEXT, case_id TEXT)")
insert("INSERT INTO " + table + " VALUES ('history', 'user-1', 'user-1', 'history', 'history', 'history')")
}
docEngine := &deletionEngine{}
store := &deletionStorage{}
core, logs := observer.New(zapcore.InfoLevel)
@@ -203,6 +206,15 @@ func TestDeleteUserRemovesOwnedDataAndJoinedDocuments(t *testing.T) {
if err != nil {
t.Fatalf("DeleteUser: %v", err)
}
for _, table := range []string{"evaluation_datasets", "evaluation_cases", "evaluation_runs", "evaluation_results"} {
var count int64
if err := db.Table(table).Count(&count).Error; err != nil {
t.Fatal(err)
}
if count != 1 {
t.Fatalf("%s history removed", table)
}
}
if result.UserCount != 1 || result.TenantCount != 1 {
t.Fatalf("unexpected deletion result: %+v", result)
}
-4
View File
@@ -278,10 +278,6 @@ func autoMigrateModels() []interface{} {
&entity.MemoryTask{},
&entity.Search{},
&entity.PipelineOperationLog{},
&entity.EvaluationDataset{},
&entity.EvaluationCase{},
&entity.EvaluationRun{},
&entity.EvaluationResult{},
&entity.TimeRecord{},
&entity.License{},
&entity.SkillSpace{},
+43
View File
@@ -569,3 +569,46 @@ func TestAutoMigrateRuntimeModelsNamesFailingTable(t *testing.T) {
t.Fatalf("autoMigrateRuntimeModels error = %v, want failing table name", err)
}
}
func TestAutoMigrateLeavesEnterpriseEvaluationHistoryUntouched(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
tables := []string{"evaluation_datasets", "evaluation_cases", "evaluation_runs", "evaluation_results"}
for _, table := range tables {
for _, model := range autoMigrateModels() {
stmt := &gorm.Statement{DB: db}
if err := stmt.Parse(model); err != nil {
t.Fatal(err)
}
if stmt.Schema.Table == table {
t.Fatalf("OSS registers %s", table)
}
}
if err := db.Exec("CREATE TABLE " + table + " (id TEXT PRIMARY KEY, history TEXT)").Error; err != nil {
t.Fatal(err)
}
if err := db.Exec("INSERT INTO " + table + " VALUES ('historical', 'keep')").Error; err != nil {
t.Fatal(err)
}
}
if err := autoMigrateRuntimeModels(t.Context(), db); err != nil {
t.Fatal(err)
}
if err := migrateResourceUserIDs(t.Context(), db); err != nil {
t.Fatal(err)
}
for _, table := range tables {
var history string
if err := db.Table(table).Select("history").Where("id = ?", "historical").Scan(&history).Error; err != nil {
t.Fatal(err)
}
if history != "keep" {
t.Fatalf("%s history changed: %q", table, history)
}
if db.Migrator().HasColumn(table, "user_id") {
t.Fatalf("OSS altered %s", table)
}
}
}
-1
View File
@@ -1129,7 +1129,6 @@ var modelIDJSONColumns = map[string][]string{
"api_4_conversation": {"dsl"},
"pipeline_operation_log": {"dsl"},
"connector": {"config"},
"evaluation_runs": {"config_snapshot"},
}
var modelIDFieldSet = map[string]bool{
@@ -59,7 +59,6 @@ func migrateResourceUserIDs(ctx context.Context, db *gorm.DB) error {
{table: "mcp_server", model: &entity.MCPServer{}, ownerField: "TenantID", ownerColumn: "tenant_id"},
{table: "skill_spaces", model: &entity.SkillSpace{}, ownerField: "TenantID", ownerColumn: "tenant_id"},
{table: "document", model: &entity.Document{}, ownerField: "CreatedBy", ownerColumn: "created_by"},
{table: "evaluation_datasets", model: &entity.EvaluationDataset{}, ownerField: "CreatedBy", ownerColumn: "created_by", fallbackField: "TenantID", fallbackColumn: "tenant_id"},
}
scoped := db.WithContext(ctx)
-98
View File
@@ -1,98 +0,0 @@
//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package entity
// EvaluationDataset evaluation dataset model
// Note: Python defines custom create_time/update_time (not null) instead of using BaseModel's
type EvaluationDataset struct {
ID string `gorm:"column:id;primaryKey;size:32" json:"id"`
UserID string `gorm:"column:user_id;size:32;not null;default:'';index" json:"user_id"`
TenantID string `gorm:"column:tenant_id;size:32;not null;index" json:"tenant_id"`
Name string `gorm:"column:name;size:255;not null;index" json:"name"`
Description *string `gorm:"column:description;type:longtext" json:"description,omitempty"`
KbIDs JSONMap `gorm:"column:kb_ids;type:longtext;not null" json:"kb_ids"`
CreatedBy string `gorm:"column:created_by;size:32;not null;index" json:"created_by"`
// Custom time fields (not null) to match Python
CreateTime int64 `gorm:"column:create_time;not null;index" json:"create_time"`
UpdateTime int64 `gorm:"column:update_time;not null" json:"update_time"`
Status int64 `gorm:"column:status;default:1;index" json:"status"`
}
// TableName specify table name
func (EvaluationDataset) TableName() string {
return "evaluation_datasets"
}
// EvaluationCase evaluation case model
// Note: Python defines custom create_time (not null) instead of using BaseModel's
type EvaluationCase struct {
ID string `gorm:"column:id;primaryKey;size:32" json:"id"`
DatasetID string `gorm:"column:dataset_id;size:32;not null;index" json:"dataset_id"`
Question string `gorm:"column:question;type:longtext;not null" json:"question"`
ReferenceAnswer *string `gorm:"column:reference_answer;type:longtext" json:"reference_answer,omitempty"`
RelevantDocIDs *JSONMap `gorm:"column:relevant_doc_ids;type:longtext" json:"relevant_doc_ids,omitempty"`
RelevantChunkIDs *JSONMap `gorm:"column:relevant_chunk_ids;type:longtext" json:"relevant_chunk_ids,omitempty"`
Metadata *JSONMap `gorm:"column:metadata;type:longtext" json:"metadata,omitempty"`
// Custom time field (not null) to match Python
CreateTime int64 `gorm:"column:create_time;not null" json:"create_time"`
}
// TableName specify table name
func (EvaluationCase) TableName() string {
return "evaluation_cases"
}
// EvaluationRun evaluation run model
// Note: Python defines custom create_time/complete_time instead of using BaseModel's
type EvaluationRun struct {
ID string `gorm:"column:id;primaryKey;size:32" json:"id"`
DatasetID string `gorm:"column:dataset_id;size:32;not null;index" json:"dataset_id"`
DialogID string `gorm:"column:dialog_id;size:32;not null;index" json:"dialog_id"`
Name string `gorm:"column:name;size:255;not null" json:"name"`
ConfigSnapshot JSONMap `gorm:"column:config_snapshot;type:longtext;not null" json:"config_snapshot"`
MetricsSummary *JSONMap `gorm:"column:metrics_summary;type:longtext" json:"metrics_summary,omitempty"`
Status string `gorm:"column:status;size:32;not null;default:PENDING" json:"status"`
CreatedBy string `gorm:"column:created_by;size:32;not null;index" json:"created_by"`
// Custom time fields to match Python
CreateTime int64 `gorm:"column:create_time;not null;index" json:"create_time"`
CompleteTime *int64 `gorm:"column:complete_time" json:"complete_time,omitempty"`
}
// TableName specify table name
func (EvaluationRun) TableName() string {
return "evaluation_runs"
}
// EvaluationResult evaluation result model
// Note: Python defines custom create_time (not null) instead of using BaseModel's
type EvaluationResult struct {
ID string `gorm:"column:id;primaryKey;size:32" json:"id"`
RunID string `gorm:"column:run_id;size:32;not null;index" json:"run_id"`
CaseID string `gorm:"column:case_id;size:32;not null;index" json:"case_id"`
GeneratedAnswer string `gorm:"column:generated_answer;type:longtext;not null" json:"generated_answer"`
RetrievedChunks JSONMap `gorm:"column:retrieved_chunks;type:longtext;not null" json:"retrieved_chunks"`
Metrics JSONMap `gorm:"column:metrics;type:longtext;not null" json:"metrics"`
ExecutionTime float64 `gorm:"column:execution_time;not null" json:"execution_time"`
TokenUsage *JSONMap `gorm:"column:token_usage;type:longtext" json:"token_usage,omitempty"`
// Custom time field to match Python
CreateTime int64 `gorm:"column:create_time;not null" json:"create_time"`
}
// TableName specify table name
func (EvaluationResult) TableName() string {
return "evaluation_results"
}
@@ -1,8 +0,0 @@
/**
* Enterprise slot for the chat evaluation entry. The enterprise build replaces
* this file with the evaluation button; open source has no evaluation module,
* so the slot renders nothing.
*/
export function ChatEvaluationButton() {
return null;
}
-2
View File
@@ -8,8 +8,6 @@ import type { ComponentType, ReactNode } from 'react';
export enum PrivateRoutes {
Price = '/price',
Billing = '/billing',
EvaluationDetail = '/evaluation-detail',
Evaluation = '/evaluation',
Tickets = '/support',
TicketCreate = '/support/create',
TicketDetail = '/support/:id',
-2
View File
@@ -1,6 +1,5 @@
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { ChatEvaluationButton } from '@/ee/pages/next-chats/chat/evaluation-button';
import {
useFetchSessionList,
useFetchSessionManually,
@@ -121,7 +120,6 @@ export default function Chat() {
<CardTitle className="flex justify-between items-center text-base gap-2">
<div className="truncate">{currentConversationName}</div>
<div className="flex gap-4 items-center">
<ChatEvaluationButton />
<Button
variant="ghost"
onClick={switchDebugMode}