mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-12 15:21:09 +00:00
feat(task): replace built-in task adaptors with a sandboxed JS plugin system (#7076)
This commit is contained in:
+53
-33
@@ -3,12 +3,12 @@ package model
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/relaykit/dto"
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"gorm.io/gorm"
|
||||
@@ -105,23 +105,40 @@ func getChannelQuery(group string, model string, retry int) (*gorm.DB, error) {
|
||||
return channelQuery, nil
|
||||
}
|
||||
|
||||
func GetChannel(group string, model string, retry int, requestPath string) (*Channel, error) {
|
||||
func GetChannel(
|
||||
group string,
|
||||
model string,
|
||||
retry int,
|
||||
filters []dto.ChannelFilter,
|
||||
) (*Channel, error) {
|
||||
var abilities []Ability
|
||||
|
||||
var err error = nil
|
||||
channelQuery, err := getChannelQuery(group, model, retry)
|
||||
err := DB.Where(commonGroupCol+" = ? and model = ? and enabled = ?", group, model, true).Order("priority DESC, weight DESC").Find(&abilities).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if common.UsingMainDatabase(common.DatabaseTypeSQLite) || common.UsingMainDatabase(common.DatabaseTypePostgreSQL) {
|
||||
err = channelQuery.Order("weight DESC").Find(&abilities).Error
|
||||
} else {
|
||||
err = channelQuery.Order("weight DESC").Find(&abilities).Error
|
||||
abilities = filterAbilitiesByConstraints(abilities, model, filters)
|
||||
if len(abilities) > 0 {
|
||||
priorities := make([]int64, 0)
|
||||
seen := make(map[int64]bool)
|
||||
for _, ability := range abilities {
|
||||
priority := int64(0)
|
||||
if ability.Priority != nil {
|
||||
priority = *ability.Priority
|
||||
}
|
||||
if !seen[priority] {
|
||||
seen[priority] = true
|
||||
priorities = append(priorities, priority)
|
||||
}
|
||||
}
|
||||
sort.Slice(priorities, func(i, j int) bool { return priorities[i] > priorities[j] })
|
||||
if retry >= len(priorities) {
|
||||
retry = len(priorities) - 1
|
||||
}
|
||||
targetPriority := priorities[retry]
|
||||
abilities = lo.Filter(abilities, func(ability Ability, _ int) bool {
|
||||
return ability.Priority == nil && targetPriority == 0 || ability.Priority != nil && *ability.Priority == targetPriority
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
abilities = filterAbilitiesByRequestPathAndModel(abilities, requestPath, model)
|
||||
channel := Channel{}
|
||||
if len(abilities) > 0 {
|
||||
// Randomly choose one
|
||||
@@ -146,14 +163,12 @@ func GetChannel(group string, model string, retry int, requestPath string) (*Cha
|
||||
return &channel, err
|
||||
}
|
||||
|
||||
// filterAbilitiesByRequestPathAndModel restricts candidates by request path and
|
||||
// model for the DB (non-memory-cache) selection path. Only Advanced Custom
|
||||
// (type 58) channels are path-checked: kept only when one of their routes matches
|
||||
// requestPath and model; all other channel types always pass. When requestPath is
|
||||
// empty, filtering is skipped.
|
||||
func filterAbilitiesByRequestPathAndModel(abilities []Ability, requestPath string, model string) []Ability {
|
||||
if requestPath == "" || len(abilities) == 0 {
|
||||
return abilities
|
||||
// filterAbilitiesByConstraints applies the same ChannelSatisfiesFilters
|
||||
// predicate used by the memory-cache path. A failed channel lookup fails
|
||||
// closed when a task-plugin identity is required and fails open otherwise.
|
||||
func filterAbilitiesByConstraints(abilities []Ability, modelName string, filters []dto.ChannelFilter) []Ability {
|
||||
if len(abilities) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
channelIds := make([]int, 0, len(abilities))
|
||||
@@ -168,31 +183,36 @@ func filterAbilitiesByRequestPathAndModel(abilities []Ability, requestPath strin
|
||||
|
||||
var channels []*Channel
|
||||
if err := DB.Where("id IN ?", channelIds).Find(&channels).Error; err != nil {
|
||||
// On error, fall back to unfiltered candidates to avoid blocking selection
|
||||
if identityFilterRequiresKey(filters) {
|
||||
return nil
|
||||
}
|
||||
return abilities
|
||||
}
|
||||
|
||||
advancedConfigs := make(map[int]*dto.AdvancedCustomConfig)
|
||||
channelsByID := make(map[int]*Channel, len(channels))
|
||||
for _, channel := range channels {
|
||||
if channel.Type == constant.ChannelTypeAdvancedCustom {
|
||||
advancedConfigs[channel.Id] = channel.GetOtherSettings().AdvancedCustom
|
||||
}
|
||||
channelsByID[channel.Id] = channel
|
||||
}
|
||||
|
||||
filtered := make([]Ability, 0, len(abilities))
|
||||
for _, ability := range abilities {
|
||||
config, isAdvancedCustom := advancedConfigs[ability.ChannelId]
|
||||
if !isAdvancedCustom {
|
||||
filtered = append(filtered, ability)
|
||||
continue
|
||||
}
|
||||
if config != nil && config.SupportsPathForModel(requestPath, model) {
|
||||
channel := channelsByID[ability.ChannelId]
|
||||
if ok, _ := ChannelSatisfiesFilters(channel, modelName, filters); ok {
|
||||
filtered = append(filtered, ability)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func identityFilterRequiresKey(filters []dto.ChannelFilter) bool {
|
||||
for _, filter := range filters {
|
||||
if filter.Kind == dto.FilterTaskPluginIdentity && filter.TaskPluginKey != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (channel *Channel) AddAbilities(tx *gorm.DB) error {
|
||||
models_ := strings.Split(channel.Models, ",")
|
||||
groups_ := strings.Split(channel.Group, ",")
|
||||
|
||||
Reference in New Issue
Block a user