Repository: meilisearch/meilisearch-go

Issue:
[v1.15] Add chat configuration to index settings
**Description**
Each index that you want to be searchable through chat needs specific configuration

**Basic example**

https://www.meilisearch.com/docs/guides/ai/getting_started_with_chat#configure-your-indexes-for-chat

```bash
curl \
  -X PATCH 'http://localhost:7700/indexes/movies/settings' \
  -H 'Authorization: Bearer <master-key>' \
  -H 'Content-Type: application/json' \
  --data-binary '{
    "chat": {
      "description": "A comprehensive movie database containing titles, descriptions, genres, and release dates to help users find movies",
      "documentTemplate": "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
      "documentTemplateMaxBytes": 400,
      "searchParameters": {}
    }
  }'
```

Discussion:

Solution patch:
diff --git a/types.go b/types.go
index b1547c8..d981894 100644
--- a/types.go
+++ b/types.go
@@ -79,6 +79,7 @@ type Settings struct {
 	Embedders            map[string]Embedder    `json:"embedders,omitempty"`
 	PrefixSearch         *string                `json:"prefixSearch,omitempty"`
 	FacetSearch          bool                   `json:"facetSearch,omitempty"`
+	Chat                 *Chat                  `json:"chat,omitempty"`
 }
 
 type LocalizedAttributes struct {
@@ -113,6 +114,23 @@ type Faceting struct {
 	SortFacetValuesBy map[string]SortFacetType `json:"sortFacetValuesBy"`
 }
 
+type Chat struct {
+	Description              string            `json:"description,omitempty"`
+	DocumentTemplate         string            `json:"documentTemplate,omitempty"`
+	DocumentTemplateMaxBytes int               `json:"documentTemplateMaxBytes,omitempty"`
+	SearchParameters         *SearchParameters `json:"searchParameters,omitempty"`
+}
+
+type SearchParameters struct {
+	Limit                 int64                `json:"limit,omitempty"`
+	AttributesToSearchOn  []string             `json:"attributesToSearchOn,omitempty"`
+	MatchingStrategy      MatchingStrategy     `json:"matchingStrategy,omitempty"`
+	Sort                  []string             `json:"sort,omitempty"`
+	Distinct              string               `json:"distinct,omitempty"`
+	Hybrid                *SearchRequestHybrid `json:"hybrid,omitempty"`
+	RankingScoreThreshold float64              `json:"rankingScoreThreshold,omitempty"`
+}
+
 // Embedder represents a unified configuration for various embedder types.
 //
 // Specs: https://www.meilisearch.com/docs/reference/api/settings#body-21



Test patch:
diff --git a/integration/index_settings_test.go b/integration/index_settings_test.go
index 1d299ca..85ffa30 100644
--- a/integration/index_settings_test.go
+++ b/integration/index_settings_test.go
@@ -2,10 +2,11 @@ package integration
 
 import (
 	"crypto/tls"
+	"testing"
+
 	"github.com/meilisearch/meilisearch-go"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	"testing"
 )
 
 func TestIndex_GetFilterableAttributes(t *testing.T) {
@@ -265,6 +266,7 @@ func TestIndex_GetSettings(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -294,6 +296,7 @@ func TestIndex_GetSettings(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 	}
@@ -907,6 +910,7 @@ func TestIndex_ResetSettings(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -938,6 +942,7 @@ func TestIndex_ResetSettings(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 	}
@@ -1771,6 +1776,7 @@ func TestIndex_UpdateSettings(t *testing.T) {
 					PrefixSearch: stringPtr("indexingTime"),
 					FacetSearch:  true,
 					Embedders:    make(map[string]meilisearch.Embedder),
+					Chat:         &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -1802,6 +1808,7 @@ func TestIndex_UpdateSettings(t *testing.T) {
 				PrefixSearch: stringPtr("indexingTime"),
 				FacetSearch:  true,
 				Embedders:    make(map[string]meilisearch.Embedder),
+				Chat:         &defaultChat,
 			},
 		},
 		{
@@ -1859,6 +1866,7 @@ func TestIndex_UpdateSettings(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -1884,6 +1892,7 @@ func TestIndex_UpdateSettings(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 	}
@@ -1962,6 +1971,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					Synonyms: map[string][]string{
@@ -1991,6 +2001,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2015,6 +2026,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2053,6 +2065,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					Synonyms: map[string][]string{
@@ -2082,6 +2095,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2106,6 +2120,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2144,6 +2159,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					SearchableAttributes: []string{
@@ -2173,6 +2189,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2197,6 +2214,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2235,6 +2253,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					DisplayedAttributes: []string{
@@ -2264,6 +2283,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2288,6 +2308,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2326,6 +2347,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					StopWords: []string{
@@ -2355,6 +2377,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2379,6 +2402,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2417,6 +2441,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					FilterableAttributes: []string{
@@ -2446,6 +2471,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2470,6 +2496,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2508,6 +2535,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					SortableAttributes: []string{
@@ -2537,6 +2565,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2561,6 +2590,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2613,6 +2643,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:         stringPtr("indexingTime"),
 					FacetSearch:          true,
 					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat:                 &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					TypoTolerance: &meilisearch.TypoTolerance{
@@ -2664,6 +2695,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2688,6 +2720,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2726,6 +2759,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					Pagination: &meilisearch.Pagination{
@@ -2755,6 +2789,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2779,6 +2814,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2820,6 +2856,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					Faceting: &meilisearch.Faceting{
@@ -2852,6 +2889,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2876,6 +2914,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 		{
@@ -2915,6 +2954,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
 				},
 				secondRequest: meilisearch.Settings{
 					RankingRules: []string{
@@ -2948,6 +2988,109 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 					PrefixSearch:       stringPtr("indexingTime"),
 					FacetSearch:        true,
 					Embedders:          make(map[string]meilisearch.Embedder),
+					Chat:               &defaultChat,
+				},
+			},
+			wantTask: &meilisearch.TaskInfo{
+				TaskUID: 1,
+			},
+			wantResp: &meilisearch.Settings{
+				RankingRules:         defaultRankingRules,
+				DistinctAttribute:    (*string)(nil),
+				SearchableAttributes: []string{"*"},
+				DisplayedAttributes:  []string{"*"},
+				StopWords:            []string{},
+				Synonyms:             make(map[string][]string),
+				FilterableAttributes: []string{},
+				SortableAttributes:   []string{},
+				TypoTolerance:        &defaultTypoTolerance,
+				Pagination:           &defaultPagination,
+				Faceting:             &defaultFaceting,
+				ProximityPrecision:   meilisearch.ByWord,
+				SeparatorTokens:      make([]string, 0),
+				NonSeparatorTokens:   make([]string, 0),
+				Dictionary:           make([]string, 0),
+				PrefixSearch:         stringPtr("indexingTime"),
+				FacetSearch:          true,
+				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
+			},
+		},
+		{
+			name: "TestIndexUpdateJustChat",
+			args: args{
+				UID:    "indexUID",
+				client: meili,
+				firstRequest: meilisearch.Settings{
+					Chat: &meilisearch.Chat{
+						Description:              "A comprehensive movie database containing titles, descriptions, genres, and release dates to help users find movies",
+						DocumentTemplate:         "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
+						DocumentTemplateMaxBytes: 400,
+					},
+				},
+				firstResponse: meilisearch.Settings{
+					RankingRules:         defaultRankingRules,
+					DistinctAttribute:    (*string)(nil),
+					SearchableAttributes: []string{"*"},
+					DisplayedAttributes:  []string{"*"},
+					StopWords:            []string{},
+					Synonyms:             make(map[string][]string),
+					FilterableAttributes: []string{},
+					SortableAttributes:   []string{},
+					TypoTolerance:        &defaultTypoTolerance,
+					Pagination:           &defaultPagination,
+					Faceting:             &defaultFaceting,
+					ProximityPrecision:   meilisearch.ByWord,
+					SeparatorTokens:      make([]string, 0),
+					NonSeparatorTokens:   make([]string, 0),
+					Dictionary:           make([]string, 0),
+					PrefixSearch:         stringPtr("indexingTime"),
+					FacetSearch:          true,
+					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat: &meilisearch.Chat{
+						Description:              "A comprehensive movie database containing titles, descriptions, genres, and release dates to help users find movies",
+						DocumentTemplate:         "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
+						DocumentTemplateMaxBytes: 400,
+						SearchParameters:         defaultChat.SearchParameters,
+					},
+				},
+				secondRequest: meilisearch.Settings{
+					Chat: &meilisearch.Chat{
+						Description:              "A comprehensive movie database containing titles, descriptions, genres, and release dates to help users find movies",
+						DocumentTemplate:         "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
+						DocumentTemplateMaxBytes: 400,
+						SearchParameters: &meilisearch.SearchParameters{
+							Limit: 20,
+						},
+					},
+				},
+				secondResponse: meilisearch.Settings{
+					RankingRules:         defaultRankingRules,
+					DistinctAttribute:    (*string)(nil),
+					SearchableAttributes: []string{"*"},
+					DisplayedAttributes:  []string{"*"},
+					StopWords:            []string{},
+					Synonyms:             make(map[string][]string),
+					FilterableAttributes: []string{},
+					SortableAttributes:   []string{},
+					TypoTolerance:        &defaultTypoTolerance,
+					Pagination:           &defaultPagination,
+					Faceting:             &defaultFaceting,
+					ProximityPrecision:   meilisearch.ByWord,
+					SeparatorTokens:      make([]string, 0),
+					NonSeparatorTokens:   make([]string, 0),
+					Dictionary:           make([]string, 0),
+					PrefixSearch:         stringPtr("indexingTime"),
+					FacetSearch:          true,
+					Embedders:            make(map[string]meilisearch.Embedder),
+					Chat: &meilisearch.Chat{
+						Description:              "A comprehensive movie database containing titles, descriptions, genres, and release dates to help users find movies",
+						DocumentTemplate:         "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
+						DocumentTemplateMaxBytes: 400,
+						SearchParameters: &meilisearch.SearchParameters{
+							Limit: 20,
+						},
+					},
 				},
 			},
 			wantTask: &meilisearch.TaskInfo{
@@ -2972,6 +3115,7 @@ func TestIndex_UpdateSettingsOneByOne(t *testing.T) {
 				PrefixSearch:         stringPtr("indexingTime"),
 				FacetSearch:          true,
 				Embedders:            make(map[string]meilisearch.Embedder),
+				Chat:                 &defaultChat,
 			},
 		},
 	}
diff --git a/integration/main_test.go b/integration/main_test.go
index 2385f8f..c55b942 100644
--- a/integration/main_test.go
+++ b/integration/main_test.go
@@ -5,12 +5,13 @@ import (
 	"encoding/csv"
 	"encoding/json"
 	"fmt"
-	"github.com/meilisearch/meilisearch-go"
-	"github.com/stretchr/testify/require"
 	"io"
 	"os"
 	"strings"
 	"testing"
+
+	"github.com/meilisearch/meilisearch-go"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -37,6 +38,16 @@ var (
 			"*": meilisearch.SortFacetTypeAlpha,
 		},
 	}
+	defaultChat = meilisearch.Chat{
+		DocumentTemplate:         "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
+		DocumentTemplateMaxBytes: 400,
+		SearchParameters: &meilisearch.SearchParameters{
+			Limit:                 0,
+			MatchingStrategy:      "",
+			Distinct:              "",
+			RankingScoreThreshold: 0,
+		},
+	}
 )
 
 var testNdjsonDocuments = []byte(`{"id": 1, "name": "Alice In Wonderland"}