mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-06-06 05:51:19 +08:00
247 lines
6.6 KiB
Go
247 lines
6.6 KiB
Go
package agent
|
||
|
||
import (
|
||
"encoding/json"
|
||
"strings"
|
||
|
||
"nofx/store"
|
||
)
|
||
|
||
func (a *Agent) skillVisibleFieldSummary(storeUserID, lang, skillName, action string) string {
|
||
fieldNames := make([]string, 0, 20)
|
||
add := func(field string) {
|
||
field = strings.TrimSpace(field)
|
||
if field == "" {
|
||
return
|
||
}
|
||
for _, existing := range fieldNames {
|
||
if existing == field {
|
||
return
|
||
}
|
||
}
|
||
fieldNames = append(fieldNames, field)
|
||
}
|
||
|
||
switch skillName {
|
||
case "model_management":
|
||
if lang == "zh" {
|
||
add("Provider")
|
||
} else {
|
||
add("provider")
|
||
}
|
||
add(displayCatalogFieldName("name", lang))
|
||
for _, field := range manualModelEditableFieldKeys() {
|
||
add(displayCatalogFieldName(field, lang))
|
||
}
|
||
case "exchange_management":
|
||
add(slotDisplayName("exchange_type", lang))
|
||
for _, field := range manualExchangeEditableFieldKeys() {
|
||
add(displayCatalogFieldName(field, lang))
|
||
}
|
||
case "trader_management":
|
||
if strings.TrimSpace(action) == "create" {
|
||
add(slotDisplayName("name", lang))
|
||
}
|
||
for _, field := range manualTraderEditableFieldKeys() {
|
||
add(displayCatalogFieldName(field, lang))
|
||
}
|
||
case "strategy_management":
|
||
add(slotDisplayName("name", lang))
|
||
for _, field := range manualStrategyEditableFieldKeys() {
|
||
add(strategyConfigFieldDisplayName(field, lang))
|
||
}
|
||
}
|
||
if len(fieldNames) == 0 {
|
||
return ""
|
||
}
|
||
prefix := "Visible UI fields"
|
||
if lang == "zh" {
|
||
prefix = "当前可见字段"
|
||
}
|
||
return prefix + ":" + strings.Join(fieldNames, "、")
|
||
}
|
||
|
||
func (a *Agent) strategyTypeForTarget(storeUserID string, target *EntityReference) (string, bool) {
|
||
if a == nil || a.store == nil || target == nil {
|
||
return "", false
|
||
}
|
||
var strategy *store.Strategy
|
||
var err error
|
||
if id := strings.TrimSpace(target.ID); id != "" {
|
||
strategy, err = a.store.Strategy().Get(storeUserID, id)
|
||
} else if name := strings.TrimSpace(target.Name); name != "" {
|
||
strategies, listErr := a.store.Strategy().List(storeUserID)
|
||
if listErr != nil {
|
||
return "", false
|
||
}
|
||
for _, item := range strategies {
|
||
if item != nil && strings.EqualFold(strings.TrimSpace(item.Name), name) {
|
||
strategy = item
|
||
break
|
||
}
|
||
}
|
||
} else {
|
||
return "", false
|
||
}
|
||
if err != nil || strategy == nil {
|
||
return "", false
|
||
}
|
||
cfg := store.GetDefaultStrategyConfig("zh")
|
||
if strings.TrimSpace(strategy.Config) != "" {
|
||
_ = json.Unmarshal([]byte(strategy.Config), &cfg)
|
||
}
|
||
strategyType := strings.TrimSpace(cfg.StrategyType)
|
||
if strategyType == "" {
|
||
strategyType = "ai_trading"
|
||
}
|
||
return strategyType, true
|
||
}
|
||
|
||
func (a *Agent) skillVisibleOptionSummary(storeUserID, lang, skillName, action string) string {
|
||
switch skillName {
|
||
case "model_management":
|
||
return a.modelSkillOptionSummary(lang)
|
||
case "exchange_management":
|
||
return a.exchangeSkillOptionSummary(lang)
|
||
case "trader_management":
|
||
return a.traderSkillOptionSummary(storeUserID, lang)
|
||
case "strategy_management":
|
||
return a.strategySkillOptionSummary(storeUserID, lang)
|
||
default:
|
||
return ""
|
||
}
|
||
}
|
||
|
||
func (a *Agent) modelSkillOptionSummary(lang string) string {
|
||
if lang == "zh" {
|
||
return modelProviderChoicePrompt(lang)
|
||
}
|
||
return modelProviderChoicePrompt(lang)
|
||
}
|
||
|
||
func (a *Agent) exchangeSkillOptionSummary(lang string) string {
|
||
options := enumOptionValues("exchange_management", "exchange_type")
|
||
if len(options) == 0 {
|
||
options = []string{"Binance", "Bybit", "OKX", "Bitget", "Gate", "KuCoin", "Hyperliquid", "Aster", "Lighter", "Indodax"}
|
||
}
|
||
if lang == "zh" {
|
||
return "交易所类型选项:" + strings.Join(options, "、")
|
||
}
|
||
return "Exchange type options: " + strings.Join(options, ", ")
|
||
}
|
||
|
||
func enumOptionValues(skillName, field string) []string {
|
||
def, ok := getSkillDefinition(skillName)
|
||
if !ok {
|
||
return nil
|
||
}
|
||
constraint, ok := def.FieldConstraints[field]
|
||
if !ok || len(constraint.Values) == 0 {
|
||
return nil
|
||
}
|
||
values := make([]string, 0, len(constraint.Values))
|
||
for _, value := range constraint.Values {
|
||
if value == "" {
|
||
continue
|
||
}
|
||
switch value {
|
||
case "openai":
|
||
values = append(values, "OpenAI")
|
||
case "deepseek":
|
||
values = append(values, "DeepSeek")
|
||
case "claude":
|
||
values = append(values, "Claude")
|
||
case "gemini":
|
||
values = append(values, "Gemini")
|
||
case "qwen":
|
||
values = append(values, "Qwen")
|
||
case "kimi":
|
||
values = append(values, "Kimi")
|
||
case "grok":
|
||
values = append(values, "Grok")
|
||
case "minimax":
|
||
values = append(values, "Minimax")
|
||
case "binance":
|
||
values = append(values, "Binance")
|
||
case "okx":
|
||
values = append(values, "OKX")
|
||
case "bybit":
|
||
values = append(values, "Bybit")
|
||
case "gate":
|
||
values = append(values, "Gate")
|
||
case "kucoin":
|
||
values = append(values, "KuCoin")
|
||
case "bitget":
|
||
values = append(values, "Bitget")
|
||
case "hyperliquid":
|
||
values = append(values, "Hyperliquid")
|
||
case "aster":
|
||
values = append(values, "Aster")
|
||
case "lighter":
|
||
values = append(values, "Lighter")
|
||
case "indodax":
|
||
values = append(values, "Indodax")
|
||
default:
|
||
values = append(values, value)
|
||
}
|
||
}
|
||
return values
|
||
}
|
||
|
||
func (a *Agent) traderSkillOptionSummary(storeUserID, lang string) string {
|
||
parts := []string{
|
||
formatSkillOptionList(lang, "可选模型", "Available models", a.loadEnabledModelOptions(storeUserID)),
|
||
formatSkillOptionList(lang, "可选交易所", "Available exchanges", a.loadExchangeOptions(storeUserID)),
|
||
formatSkillOptionList(lang, "可选策略", "Available strategies", a.loadStrategyOptions(storeUserID)),
|
||
}
|
||
return strings.Join(filterNonEmptyStrings(parts), "\n")
|
||
}
|
||
|
||
func (a *Agent) strategySkillOptionSummary(storeUserID, lang string) string {
|
||
parts := []string{
|
||
"",
|
||
formatSkillOptionList(lang, "现有策略", "Existing strategies", a.loadStrategyOptions(storeUserID)),
|
||
}
|
||
sourceOptions := []string{"static", "ai500", "oi_top", "oi_low"}
|
||
if lang == "zh" {
|
||
parts[0] = "选币来源选项:static、ai500、oi_top、oi_low"
|
||
} else {
|
||
parts[0] = "Coin source options: static, ai500, oi_top, oi_low"
|
||
}
|
||
_ = sourceOptions
|
||
return strings.Join(filterNonEmptyStrings(parts), "\n")
|
||
}
|
||
|
||
func formatSkillOptionList(lang, zhPrefix, enPrefix string, options []traderSkillOption) string {
|
||
names := make([]string, 0, len(options))
|
||
for _, option := range options {
|
||
label := strings.TrimSpace(defaultIfEmpty(option.Name, option.ID))
|
||
if label == "" {
|
||
continue
|
||
}
|
||
names = append(names, label)
|
||
}
|
||
if len(names) == 0 {
|
||
if lang == "zh" {
|
||
return zhPrefix + ":暂无"
|
||
}
|
||
return enPrefix + ": none"
|
||
}
|
||
if lang == "zh" {
|
||
return zhPrefix + ":" + strings.Join(names, "、")
|
||
}
|
||
return enPrefix + ": " + strings.Join(names, ", ")
|
||
}
|
||
|
||
func filterNonEmptyStrings(items []string) []string {
|
||
out := make([]string, 0, len(items))
|
||
for _, item := range items {
|
||
item = strings.TrimSpace(item)
|
||
if item == "" {
|
||
continue
|
||
}
|
||
out = append(out, item)
|
||
}
|
||
return out
|
||
}
|