package workbench import ( "context" "encoding/json" "errors" "fmt" "strings" platformid "aigateway.local/core/internal/platform/id" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) type Service struct { pool *pgxpool.Pool embedder Embedder } func NewService(pool *pgxpool.Pool) *Service { return &Service{pool: pool} } // SetEmbedder 注入向量化器(M8 P2)。为 nil 时知识库退回纯 FTS,不生成 embedding。 func (s *Service) SetEmbedder(embedder Embedder) { s.embedder = embedder } // Embedder 返回当前向量化器(可能为 nil)。 func (s *Service) Embedder() Embedder { return s.embedder } func newUUID() (string, error) { return platformid.NewUUID() } func emit(ctx context.Context, tx pgx.Tx, eventType, aggregateType, aggregateID, actorID string, values map[string]any) error { eventID, err := newUUID() if err != nil { return err } if values == nil { values = make(map[string]any) } values[aggregateType+"_id"] = aggregateID values["actor_id"] = actorID payload, err := json.Marshal(values) if err != nil { return err } _, err = tx.Exec(ctx, `INSERT INTO gateway.outbox_events(event_id,event_type,event_version,aggregate_type,aggregate_id,payload) VALUES($1,$2,1,$3,$4,$5)`, eventID, eventType, aggregateType, aggregateID, payload) return err } func normalizeStrings(values []string, maximum int) ([]string, error) { seen := make(map[string]struct{}, len(values)) result := make([]string, 0, len(values)) for _, value := range values { value = strings.TrimSpace(value) if value == "" { continue } if len(value) > 255 { return nil, errors.New("列表项过长") } if _, ok := seen[value]; ok { continue } seen[value] = struct{}{} result = append(result, value) } if len(result) > maximum { return nil, fmt.Errorf("列表最多允许 %d 项", maximum) } return result, nil } func mapNotFound(err error) error { if errors.Is(err, pgx.ErrNoRows) { return ErrNotFound } return err } func rollback(ctx context.Context, tx pgx.Tx) { _ = tx.Rollback(ctx) }