feat: harden support, localize knowledge and add operator availability [skip ci]

Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.

Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.

Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.

Expected source tree: 0a4a7528e9.
This commit is contained in:
2026-10-16 15:21:42 +00:00
parent 299ea50fb5
commit 2f7a491666
176 changed files with 11869 additions and 2716 deletions

View File

@@ -1,21 +1,23 @@
// Modified in the independent AgentDesk fork: localized knowledge workflows and safe display errors.
package builders
import (
"agent-desk/internal/models"
"agent-desk/internal/pkg/dto/response"
"agent-desk/internal/pkg/enums"
"agent-desk/internal/pkg/i18nx"
"encoding/json"
"fmt"
)
func BuildKnowledgeBase(item *models.KnowledgeBase) response.KnowledgeBaseResponse {
func BuildKnowledgeBase(item *models.KnowledgeBase, locales ...string) response.KnowledgeBaseResponse {
return response.KnowledgeBaseResponse{
ID: item.ID,
Name: item.Name,
Description: item.Description,
KnowledgeType: item.KnowledgeType,
KnowledgeTypeName: enums.GetKnowledgeBaseTypeLabel(enums.KnowledgeBaseType(item.KnowledgeType)),
KnowledgeTypeName: knowledgeLabel(locales, "type", item.KnowledgeType),
Status: item.Status,
StatusName: enums.GetStatusLabel(item.Status),
StatusName: knowledgeLabel(locales, "status", item.Status),
DefaultTopK: item.DefaultTopK,
DefaultScoreThreshold: item.DefaultScoreThreshold,
DefaultRerankLimit: item.DefaultRerankLimit,
@@ -24,7 +26,7 @@ func BuildKnowledgeBase(item *models.KnowledgeBase) response.KnowledgeBaseRespon
ChunkMaxTokens: item.ChunkMaxTokens,
ChunkOverlapTokens: item.ChunkOverlapTokens,
AnswerMode: item.AnswerMode,
AnswerModeName: enums.GetKnowledgeAnswerModeLabel(enums.KnowledgeAnswerMode(item.AnswerMode)),
AnswerModeName: knowledgeLabel(locales, "mode", item.AnswerMode),
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
@@ -33,18 +35,18 @@ func BuildKnowledgeBase(item *models.KnowledgeBase) response.KnowledgeBaseRespon
}
}
func BuildKnowledgeDocument(item *models.KnowledgeDocument) response.KnowledgeDocumentResponse {
func BuildKnowledgeDocument(item *models.KnowledgeDocument, locales ...string) response.KnowledgeDocumentResponse {
return response.KnowledgeDocumentResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
DirectoryID: item.DirectoryID,
Title: item.Title,
Status: item.Status,
StatusName: enums.GetStatusLabel(item.Status),
StatusName: knowledgeLabel(locales, "status", item.Status),
IndexStatus: item.IndexStatus,
IndexStatusName: enums.GetKnowledgeDocumentIndexStatusLabel(item.IndexStatus),
IndexStatusName: knowledgeLabel(locales, "index", item.IndexStatus),
IndexedAt: item.IndexedAt,
IndexError: item.IndexError,
IndexError: knowledgeIndexError(locales, item.IndexError),
ContentHash: item.ContentHash,
ContentType: item.ContentType,
Content: item.Content,
@@ -55,18 +57,18 @@ func BuildKnowledgeDocument(item *models.KnowledgeDocument) response.KnowledgeDo
}
}
func BuildKnowledgeDocumentList(item *models.KnowledgeDocument) response.KnowledgeDocumentListResponse {
func BuildKnowledgeDocumentList(item *models.KnowledgeDocument, locales ...string) response.KnowledgeDocumentListResponse {
return response.KnowledgeDocumentListResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
DirectoryID: item.DirectoryID,
Title: item.Title,
Status: item.Status,
StatusName: enums.GetStatusLabel(item.Status),
StatusName: knowledgeLabel(locales, "status", item.Status),
IndexStatus: item.IndexStatus,
IndexStatusName: enums.GetKnowledgeDocumentIndexStatusLabel(item.IndexStatus),
IndexStatusName: knowledgeLabel(locales, "index", item.IndexStatus),
IndexedAt: item.IndexedAt,
IndexError: item.IndexError,
IndexError: knowledgeIndexError(locales, item.IndexError),
ContentHash: item.ContentHash,
ContentType: item.ContentType,
CreatedAt: item.CreatedAt,
@@ -76,7 +78,7 @@ func BuildKnowledgeDocumentList(item *models.KnowledgeDocument) response.Knowled
}
}
func BuildKnowledgeFAQ(item *models.KnowledgeFAQ) response.KnowledgeFAQResponse {
func BuildKnowledgeFAQ(item *models.KnowledgeFAQ, locales ...string) response.KnowledgeFAQResponse {
return response.KnowledgeFAQResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
@@ -85,11 +87,11 @@ func BuildKnowledgeFAQ(item *models.KnowledgeFAQ) response.KnowledgeFAQResponse
Answer: item.Answer,
SimilarQuestions: parseSimilarQuestions(item.SimilarQuestions),
Status: item.Status,
StatusName: enums.GetStatusLabel(item.Status),
StatusName: knowledgeLabel(locales, "status", item.Status),
IndexStatus: item.IndexStatus,
IndexStatusName: enums.GetKnowledgeDocumentIndexStatusLabel(item.IndexStatus),
IndexStatusName: knowledgeLabel(locales, "index", item.IndexStatus),
IndexedAt: item.IndexedAt,
IndexError: item.IndexError,
IndexError: knowledgeIndexError(locales, item.IndexError),
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
@@ -98,7 +100,7 @@ func BuildKnowledgeFAQ(item *models.KnowledgeFAQ) response.KnowledgeFAQResponse
}
}
func BuildKnowledgeDirectory(item *models.KnowledgeDirectory) response.KnowledgeDirectoryResponse {
func BuildKnowledgeDirectory(item *models.KnowledgeDirectory, locales ...string) response.KnowledgeDirectoryResponse {
return response.KnowledgeDirectoryResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
@@ -106,7 +108,7 @@ func BuildKnowledgeDirectory(item *models.KnowledgeDirectory) response.Knowledge
Name: item.Name,
SortNo: item.SortNo,
Status: item.Status,
StatusName: enums.GetStatusLabel(item.Status),
StatusName: knowledgeLabel(locales, "status", item.Status),
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
@@ -116,14 +118,14 @@ func BuildKnowledgeDirectory(item *models.KnowledgeDirectory) response.Knowledge
}
}
func BuildKnowledgeRetrieveLog(item *models.KnowledgeRetrieveLog) response.KnowledgeRetrieveLogResponse {
func BuildKnowledgeRetrieveLog(item *models.KnowledgeRetrieveLog, locales ...string) response.KnowledgeRetrieveLogResponse {
return response.KnowledgeRetrieveLogResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
Channel: item.Channel,
ChannelName: enums.GetKnowledgeRetrieveChannelLabel(enums.KnowledgeRetrieveChannel(item.Channel)),
ChannelName: knowledgeLabel(locales, "channel", item.Channel),
Scene: item.Scene,
SceneName: enums.GetKnowledgeRetrieveSceneLabel(enums.KnowledgeRetrieveScene(item.Scene)),
SceneName: knowledgeLabel(locales, "scene", item.Scene),
SessionID: item.SessionID,
ConversationID: item.ConversationID,
RequestID: item.RequestID,
@@ -131,7 +133,7 @@ func BuildKnowledgeRetrieveLog(item *models.KnowledgeRetrieveLog) response.Knowl
RewriteQuestion: item.RewriteQuestion,
Answer: item.Answer,
AnswerStatus: item.AnswerStatus,
AnswerStatusName: enums.GetKnowledgeAnswerStatusLabel(enums.KnowledgeAnswerStatus(item.AnswerStatus)),
AnswerStatusName: knowledgeLabel(locales, "answer", item.AnswerStatus),
HitCount: item.HitCount,
TopScore: item.TopScore,
ChunkProvider: item.ChunkProvider,
@@ -153,7 +155,7 @@ func BuildKnowledgeRetrieveLog(item *models.KnowledgeRetrieveLog) response.Knowl
}
}
func BuildKnowledgeRetrieveHitResponse(item *models.KnowledgeRetrieveHit) response.KnowledgeRetrieveHitResponse {
func BuildKnowledgeRetrieveHitResponse(item *models.KnowledgeRetrieveHit, locales ...string) response.KnowledgeRetrieveHitResponse {
return response.KnowledgeRetrieveHitResponse{
ID: item.ID,
RetrieveLogID: item.RetrieveLogID,
@@ -167,7 +169,7 @@ func BuildKnowledgeRetrieveHitResponse(item *models.KnowledgeRetrieveHit) respon
Title: item.Title,
SectionPath: item.SectionPath,
ChunkType: item.ChunkType,
ChunkTypeName: enums.GetKnowledgeChunkTypeLabel(enums.KnowledgeChunkType(item.ChunkType)),
ChunkTypeName: knowledgeLabel(locales, "chunk", item.ChunkType),
Provider: item.Provider,
RankNo: item.RankNo,
Score: item.Score,
@@ -189,3 +191,41 @@ func parseSimilarQuestions(raw string) []string {
}
return items
}
var knowledgeLabelCodes = map[string]map[string]bool{
"type": {"document": true, "faq": true},
"status": {"0": true, "1": true, "2": true},
"index": {"pending": true, "indexed": true, "failed": true},
"mode": {"1": true, "2": true},
"channel": {"im": true, "agent_assist": true, "api": true, "debug": true},
"scene": {"first_response": true, "assist": true, "qa": true},
"answer": {"1": true, "2": true, "3": true, "4": true},
"chunk": {"text": true, "faq": true, "table": true, "code": true},
}
// Labels are application-owned; titles, content, snippets and historical answers are not.
func knowledgeLabel(locales []string, group string, value any) string {
code := fmt.Sprint(value)
key := "knowledge.labels.unknown"
if knowledgeLabelCodes[group][code] {
key = "knowledge.labels." + group + "." + code
}
return i18nx.Getf(knowledgeLocale(locales), key)
}
func knowledgeLocale(locales []string) string {
if len(locales) > 0 {
return i18nx.NormalizeLocale(locales[0])
}
return i18nx.DefaultLocale
}
// Legacy index_error values can contain SQL, credentials or provider response bodies.
// Keep those values out of the public DTO; this does not rewrite persisted diagnostics.
func knowledgeIndexError(locales []string, stored string) string {
if stored == "" {
return ""
}
return i18nx.Getf(knowledgeLocale(locales), "error.knowledge.indexFailed")
}