Repository: sashabaranov/go-openai
Pull request #795 (2024-07-18 13:09:41)

Add New Optional Parameters to `AssistantRequest` Struct
## Add New Optional Parameters to `AssistantRequest` Struct

This update introduces three new optional parameters to the `AssistantRequest` struct: `ResponseFormat`, `Temperature`, and `TopP`. These parameters provide additional control over the output format and sampling behavior of the OpenAI assistant, enhancing its flexibility and usability.

### OpenAI Documentation Link

For detailed information about these parameters, please refer to the OpenAI API documentation: [OpenAI API Reference](https://platform.openai.com/docs/api-reference/assistants/object)

### Solution Description

The solution involves extending the `AssistantRequest` struct to include the following fields:

- `ResponseFormat any`: Specifies the format that the model must output. Example: setting this to `{ "type": "json_object" }` ensures the model generates valid JSON. but it can also be a string format for 'auto'
- `Temperature *float32`: Determines the sampling temperature. 
- `TopP *float32`: Defines the nucleus sampling parameter.

These additions enable users to specify advanced settings for response generation, aligning the API with the latest OpenAI features.

### Struct Definition

Here is the updated `AssistantRequest` struct with the new fields included:

```go
type AssistantRequest struct {
    Model         string                 `json:"model"`
    Name          *string                `json:"name,omitempty"`
    Description   *string                `json:"description,omitempty"`
    Instructions  *string                `json:"instructions,omitempty"`
    Tools         []AssistantTool        `json:"-"`
    FileIDs       []string               `json:"file_ids,omitempty"`
    Metadata      map[string]any         `json:"metadata,omitempty"`
    ToolResources *AssistantToolResource `json:"tool_resources,omitempty"`
    ResponseFormat any                   `json:"response_format,omitempty"`
    Temperature   *float32               `json:"temperature,omitempty"`
    TopP          *float32               `json:"top_p,omitempty"`
}


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/sashabaranov/go-openai/pull/795?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alex+Baranov) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 98.88%. Comparing base [(`774fc9d`)](https://app.codecov.io/gh/sashabaranov/go-openai/commit/774fc9dd12ed60c10a9f9f03319ddb9cd5f8780c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alex+Baranov) to head [(`8a05028`)](https://app.codecov.io/gh/sashabaranov/go-openai/commit/8a05028997ec96e86cf69d8920ac8d60b23a482a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alex+Baranov).
> Report is 27 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #795      +/-   ##
==========================================
+ Coverage   98.46%   98.88%   +0.42%     
==========================================
  Files          24       26       +2     
  Lines        1364     1343      -21     
==========================================
- Hits         1343     1328      -15     
+ Misses         15        9       -6     
  Partials        6        6              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/sashabaranov/go-openai/pull/795?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alex+Baranov).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alex+Baranov).


Patch:
diff --git a/assistant.go b/assistant.go
index cc13a30..4c89c1b 100644
--- a/assistant.go
+++ b/assistant.go
@@ -62,14 +62,17 @@ type AssistantToolResource struct {
 // If Tools is empty slice it will effectively delete all of the Assistant's tools.
 // If Tools is populated, it will replace all of the existing Assistant's tools with the provided tools.
 type AssistantRequest struct {
-	Model         string                 `json:"model"`
-	Name          *string                `json:"name,omitempty"`
-	Description   *string                `json:"description,omitempty"`
-	Instructions  *string                `json:"instructions,omitempty"`
-	Tools         []AssistantTool        `json:"-"`
-	FileIDs       []string               `json:"file_ids,omitempty"`
-	Metadata      map[string]any         `json:"metadata,omitempty"`
-	ToolResources *AssistantToolResource `json:"tool_resources,omitempty"`
+	Model          string                 `json:"model"`
+	Name           *string                `json:"name,omitempty"`
+	Description    *string                `json:"description,omitempty"`
+	Instructions   *string                `json:"instructions,omitempty"`
+	Tools          []AssistantTool        `json:"-"`
+	FileIDs        []string               `json:"file_ids,omitempty"`
+	Metadata       map[string]any         `json:"metadata,omitempty"`
+	ToolResources  *AssistantToolResource `json:"tool_resources,omitempty"`
+	ResponseFormat any                    `json:"response_format,omitempty"`
+	Temperature    *float32               `json:"temperature,omitempty"`
+	TopP           *float32               `json:"top_p,omitempty"`
 }
 
 // MarshalJSON provides a custom marshaller for the assistant request to handle the API use cases
diff --git a/client.go b/client.go
index 7bc28e9..d5d555c 100644
--- a/client.go
+++ b/client.go
@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"net/url"
 	"strings"
 
 	utils "github.com/sashabaranov/go-openai/internal"
@@ -228,10 +229,13 @@ func (c *Client) fullURL(suffix string, args ...any) string {
 	if c.config.APIType == APITypeAzure || c.config.APIType == APITypeAzureAD {
 		baseURL := c.config.BaseURL
 		baseURL = strings.TrimRight(baseURL, "/")
+		parseURL, _ := url.Parse(baseURL)
+		query := parseURL.Query()
+		query.Add("api-version", c.config.APIVersion)
 		// if suffix is /models change to {endpoint}/openai/models?api-version=2022-12-01
 		// https://learn.microsoft.com/en-us/rest/api/cognitiveservices/azureopenaistable/models/list?tabs=HTTP
 		if containsSubstr([]string{"/models", "/assistants", "/threads", "/files"}, suffix) {
-			return fmt.Sprintf("%s/%s%s?api-version=%s", baseURL, azureAPIPrefix, suffix, c.config.APIVersion)
+			return fmt.Sprintf("%s/%s%s?%s", baseURL, azureAPIPrefix, suffix, query.Encode())
 		}
 		azureDeploymentName := "UNKNOWN"
 		if len(args) > 0 {
@@ -240,9 +244,9 @@ func (c *Client) fullURL(suffix string, args ...any) string {
 				azureDeploymentName = c.config.GetAzureDeploymentByModel(model)
 			}
 		}
-		return fmt.Sprintf("%s/%s/%s/%s%s?api-version=%s",
+		return fmt.Sprintf("%s/%s/%s/%s%s?%s",
 			baseURL, azureAPIPrefix, azureDeploymentsPrefix,
-			azureDeploymentName, suffix, c.config.APIVersion,
+			azureDeploymentName, suffix, query.Encode(),
 		)
 	}
 
diff --git a/completion.go b/completion.go
index 024f09b..4ff1123 100644
--- a/completion.go
+++ b/completion.go
@@ -24,6 +24,8 @@ const (
 	GPT40314              = "gpt-4-0314"
 	GPT4o                 = "gpt-4o"
 	GPT4o20240513         = "gpt-4o-2024-05-13"
+	GPT4oMini             = "gpt-4o-mini"
+	GPT4oMini20240718     = "gpt-4o-mini-2024-07-18"
 	GPT4Turbo             = "gpt-4-turbo"
 	GPT4Turbo20240409     = "gpt-4-turbo-2024-04-09"
 	GPT4Turbo0125         = "gpt-4-0125-preview"
@@ -89,6 +91,8 @@ var disabledModelsForEndpoints = map[string]map[string]bool{
 		GPT4:                 true,
 		GPT4o:                true,
 		GPT4o20240513:        true,
+		GPT4oMini:            true,
+		GPT4oMini20240718:    true,
 		GPT4TurboPreview:     true,
 		GPT4VisionPreview:    true,
 		GPT4Turbo1106:        true,
diff --git a/files.go b/files.go
index 26ad6bd..edc9f2a 100644
--- a/files.go
+++ b/files.go
@@ -102,6 +102,7 @@ func (c *Client) CreateFile(ctx context.Context, request FileRequest) (file File
 	if err != nil {
 		return
 	}
+	defer fileData.Close()
 
 	err = builder.CreateFormFile("file", fileData)
 	if err != nil {
diff --git a/fine_tuning_job.go b/fine_tuning_job.go
index 9dcb49d..5a9f54a 100644
--- a/fine_tuning_job.go
+++ b/fine_tuning_job.go
@@ -26,7 +26,9 @@ type FineTuningJob struct {
 }
 
 type Hyperparameters struct {
-	Epochs any `json:"n_epochs,omitempty"`
+	Epochs                 any `json:"n_epochs,omitempty"`
+	LearningRateMultiplier any `json:"learning_rate_multiplier,omitempty"`
+	BatchSize              any `json:"batch_size,omitempty"`
 }
 
 type FineTuningJobRequest struct {
diff --git a/thread.go b/thread.go
index 6f75214..bc08e2b 100644
--- a/thread.go
+++ b/thread.go
@@ -83,14 +83,25 @@ type ModifyThreadRequest struct {
 type ThreadMessageRole string
 
 const (
-	ThreadMessageRoleUser ThreadMessageRole = "user"
+	ThreadMessageRoleAssistant ThreadMessageRole = "assistant"
+	ThreadMessageRoleUser      ThreadMessageRole = "user"
 )
 
 type ThreadMessage struct {
-	Role     ThreadMessageRole `json:"role"`
-	Content  string            `json:"content"`
-	FileIDs  []string          `json:"file_ids,omitempty"`
-	Metadata map[string]any    `json:"metadata,omitempty"`
+	Role        ThreadMessageRole  `json:"role"`
+	Content     string             `json:"content"`
+	FileIDs     []string           `json:"file_ids,omitempty"`
+	Attachments []ThreadAttachment `json:"attachments,omitempty"`
+	Metadata    map[string]any     `json:"metadata,omitempty"`
+}
+
+type ThreadAttachment struct {
+	FileID string                 `json:"file_id"`
+	Tools  []ThreadAttachmentTool `json:"tools"`
+}
+
+type ThreadAttachmentTool struct {
+	Type string `json:"type"`
 }
 
 type ThreadDeleteResponse struct {


Test patch:
diff --git a/fine_tuning_job_test.go b/fine_tuning_job_test.go
index d2fbcd4..5f63ef2 100644
--- a/fine_tuning_job_test.go
+++ b/fine_tuning_job_test.go
@@ -33,7 +33,9 @@ func TestFineTuningJob(t *testing.T) {
 				ValidationFile: "",
 				TrainingFile:   "file-abc123",
 				Hyperparameters: openai.Hyperparameters{
-					Epochs: "auto",
+					Epochs:                 "auto",
+					LearningRateMultiplier: "auto",
+					BatchSize:              "auto",
 				},
 				TrainedTokens: 5768,
 			})