package workflowbridge import ( "errors" "regexp" "strings" ) const DefaultTextModel = "deepseek-v4-1-flash-260910" const DefaultBookModel = "doubao-seed-evolving" const DefaultImageModel = "doubao-seedream-5-0-pro-260628" var modelID = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$`) var errInvalidModel = errors.New("invalid model selection") // Nodes carry only an Ark model/endpoint identifier. URL and credentials remain // server configuration; choosing a model never silently falls back to another. func selectedModel(step, model, custom string) (string, error) { var fallback string switch step { case "classify", "daily": fallback = DefaultTextModel case "write-book": fallback = DefaultBookModel case "illustrate": fallback = DefaultImageModel default: return "", nil } model = strings.TrimSpace(model) if model == "__custom__" { model = strings.TrimSpace(custom) if model == "" { return "", errInvalidModel } } if model == "" { if inCustom := strings.TrimSpace(custom); inCustom != "" { return "", errInvalidModel } model = fallback } if !modelID.MatchString(model) || model == "__custom__" { return "", errInvalidModel } if step == "illustrate" { if !strings.HasPrefix(model, "doubao-seedream-") && !strings.HasPrefix(model, "ep-") { return "", errInvalidModel } } else { for _, modality := range []string{"seedream", "seedance", "embedding", "seed3d"} { if strings.Contains(strings.ToLower(model), modality) { return "", errInvalidModel } } } return model, nil }