Files
agent-desk-ng/internal/builders/knowledge_builder.go
mono 2f7a491666 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.
2026-10-16 15:21:42 +00:00

232 lines
8.6 KiB
Go

// 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/i18nx"
"encoding/json"
"fmt"
)
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: knowledgeLabel(locales, "type", item.KnowledgeType),
Status: item.Status,
StatusName: knowledgeLabel(locales, "status", item.Status),
DefaultTopK: item.DefaultTopK,
DefaultScoreThreshold: item.DefaultScoreThreshold,
DefaultRerankLimit: item.DefaultRerankLimit,
ChunkProvider: item.ChunkProvider,
ChunkTargetTokens: item.ChunkTargetTokens,
ChunkMaxTokens: item.ChunkMaxTokens,
ChunkOverlapTokens: item.ChunkOverlapTokens,
AnswerMode: item.AnswerMode,
AnswerModeName: knowledgeLabel(locales, "mode", item.AnswerMode),
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
CreateUserName: item.CreateUserName,
UpdateUserName: item.UpdateUserName,
}
}
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: knowledgeLabel(locales, "status", item.Status),
IndexStatus: item.IndexStatus,
IndexStatusName: knowledgeLabel(locales, "index", item.IndexStatus),
IndexedAt: item.IndexedAt,
IndexError: knowledgeIndexError(locales, item.IndexError),
ContentHash: item.ContentHash,
ContentType: item.ContentType,
Content: item.Content,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
CreateUserName: item.CreateUserName,
UpdateUserName: item.UpdateUserName,
}
}
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: knowledgeLabel(locales, "status", item.Status),
IndexStatus: item.IndexStatus,
IndexStatusName: knowledgeLabel(locales, "index", item.IndexStatus),
IndexedAt: item.IndexedAt,
IndexError: knowledgeIndexError(locales, item.IndexError),
ContentHash: item.ContentHash,
ContentType: item.ContentType,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
CreateUserName: item.CreateUserName,
UpdateUserName: item.UpdateUserName,
}
}
func BuildKnowledgeFAQ(item *models.KnowledgeFAQ, locales ...string) response.KnowledgeFAQResponse {
return response.KnowledgeFAQResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
DirectoryID: item.DirectoryID,
Question: item.Question,
Answer: item.Answer,
SimilarQuestions: parseSimilarQuestions(item.SimilarQuestions),
Status: item.Status,
StatusName: knowledgeLabel(locales, "status", item.Status),
IndexStatus: item.IndexStatus,
IndexStatusName: knowledgeLabel(locales, "index", item.IndexStatus),
IndexedAt: item.IndexedAt,
IndexError: knowledgeIndexError(locales, item.IndexError),
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
CreateUserName: item.CreateUserName,
UpdateUserName: item.UpdateUserName,
}
}
func BuildKnowledgeDirectory(item *models.KnowledgeDirectory, locales ...string) response.KnowledgeDirectoryResponse {
return response.KnowledgeDirectoryResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
ParentID: item.ParentID,
Name: item.Name,
SortNo: item.SortNo,
Status: item.Status,
StatusName: knowledgeLabel(locales, "status", item.Status),
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
CreateUserName: item.CreateUserName,
UpdateUserName: item.UpdateUserName,
Children: []response.KnowledgeDirectoryResponse{},
}
}
func BuildKnowledgeRetrieveLog(item *models.KnowledgeRetrieveLog, locales ...string) response.KnowledgeRetrieveLogResponse {
return response.KnowledgeRetrieveLogResponse{
ID: item.ID,
KnowledgeBaseID: item.KnowledgeBaseID,
Channel: item.Channel,
ChannelName: knowledgeLabel(locales, "channel", item.Channel),
Scene: item.Scene,
SceneName: knowledgeLabel(locales, "scene", item.Scene),
SessionID: item.SessionID,
ConversationID: item.ConversationID,
RequestID: item.RequestID,
Question: item.Question,
RewriteQuestion: item.RewriteQuestion,
Answer: item.Answer,
AnswerStatus: item.AnswerStatus,
AnswerStatusName: knowledgeLabel(locales, "answer", item.AnswerStatus),
HitCount: item.HitCount,
TopScore: item.TopScore,
ChunkProvider: item.ChunkProvider,
ChunkTargetTokens: item.ChunkTargetTokens,
ChunkMaxTokens: item.ChunkMaxTokens,
ChunkOverlapTokens: item.ChunkOverlapTokens,
RerankEnabled: item.RerankEnabled,
RerankLimit: item.RerankLimit,
CitationCount: item.CitationCount,
UsedChunkCount: item.UsedChunkCount,
LatencyMs: item.LatencyMs,
RetrieveMs: item.RetrieveMs,
GenerateMs: item.GenerateMs,
PromptTokens: item.PromptTokens,
CompletionTokens: item.CompletionTokens,
ModelName: item.ModelName,
TraceData: item.TraceData,
CreatedAt: item.CreatedAt,
}
}
func BuildKnowledgeRetrieveHitResponse(item *models.KnowledgeRetrieveHit, locales ...string) response.KnowledgeRetrieveHitResponse {
return response.KnowledgeRetrieveHitResponse{
ID: item.ID,
RetrieveLogID: item.RetrieveLogID,
KnowledgeBaseID: item.KnowledgeBaseID,
ChunkID: item.ChunkID,
DocumentID: item.DocumentID,
DocumentTitle: item.DocumentTitle,
FaqID: item.FaqID,
FaqQuestion: item.FaqQuestion,
ChunkNo: item.ChunkNo,
Title: item.Title,
SectionPath: item.SectionPath,
ChunkType: item.ChunkType,
ChunkTypeName: knowledgeLabel(locales, "chunk", item.ChunkType),
Provider: item.Provider,
RankNo: item.RankNo,
Score: item.Score,
RerankScore: item.RerankScore,
UsedInAnswer: item.UsedInAnswer,
IsCitation: item.IsCitation,
Snippet: item.Snippet,
CreatedAt: item.CreatedAt,
}
}
func parseSimilarQuestions(raw string) []string {
if raw == "" {
return []string{}
}
var items []string
if err := json.Unmarshal([]byte(raw), &items); err != nil {
return []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")
}