"Missing required parameter: 'role'" when posting to an existing thread in Unity C#

I am developing assistants for use within the Unity Engine using C# so that the assistant can have access to the project’s scripts, etc.

I am able to create an assistant, add retrieval files, activate code interpreter and file retrieval, as well as create a thread with a message, then run the assistant and get an initial response.

The trouble I am having is then posting another message to the existing thread. The payload is exactly the same for creating a new thread and posting a message to an existing thread. From my understanding, the endpoint is different but I am unsure what else needs to be different.

Essentially my function checks if I already have a threadID saved; if not, create a new thread and post the message. If it does, use the thread id to post a new message. But that is where it fails, giving me the error “Missing required parameter: ‘role’.”

public async Task PostToThreadAsync(GPTAssistantConfig _config, string _prompt)
		{
			var payload = new MessagePayload
			{
				messages = new Message[]
					{
						new Message { role = "user", content = _prompt }
					}
			};
			string jsonPayload = JsonConvert.SerializeObject(payload);
			var sendcontent = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
			_httpClient.DefaultRequestHeaders.Clear();
			_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _config.apiKey);
			_httpClient.DefaultRequestHeaders.Add("OpenAI-Beta", "assistants=v1");
			string postUrl;

			// Check if a thread already exists
			if (!string.IsNullOrEmpty(_config.threadID))
			{
				// Log the thread ID
				Debug.Log($"Posting to existing thread {_config.threadID} with payload: {jsonPayload}");
				postUrl = $"v1/threads/{_config.threadID}/messages";
			}
			else
			{
				// No thread ID, so create a new thread
				Debug.Log($"Posting to new thread with payload: {jsonPayload}");
				postUrl = $"v1/threads";
			}

			HttpResponseMessage response = await _httpClient.PostAsync(postUrl, sendcontent);

			if (response.IsSuccessStatusCode)
			{
				string responseBody = await response.Content.ReadAsStringAsync();
				Debug.Log("Posted successfully. Response: " + responseBody);
				ThreadObject threadObj = JsonConvert.DeserializeObject<ThreadObject>(responseBody);
				_config.threadID = threadObj.id;
				Debug.Log("Thread ID set to: " + _config.threadID);
			}
			else
			{
				string newThreadErrorContent = await response.Content.ReadAsStringAsync();
				Debug.LogError("Error while posting message: " + response.StatusCode + "\nError Content: " + newThreadErrorContent);
			}
		}
1 Like

Hey there and welcome to the community!

Yay, I’ve been waiting for C# Unity devs to pop in here! I love C#.

So, just to confirm, the “postUrl” is missing the “https://api.openai.com” chunk in this code. Is that intentional, or I guess is that standard for the API call in this language? I’m guessing that’s the chunk of code before you instantiate the postUrl var?

I don’t see anything wrong with the code snippet from a quick glance, but the error means that there’s potentially something wrong with how the payload is getting serialized into a format that the API can read. Honestly, I can’t explain how it’s able to work when creating the thread but not an existing one, because to me, my first question is: Are you serializing just the values, or the key-value pairs?

You would have to be very careful about using an array for your data and payload. In fact, I would actually recommend you use a C# dictionary to represent the data structure of a message. You would then need to serialize the dictionary.

Why a dictionary?

Because this:
{
“user”
“Content”
}
Is what an array would look like, and is not the correct JSON representation of sending a message. By using a dictionary, you can serialize it into a JSON value like this:

{
“role” : “user”
“content” : “What are the mating rituals of African Ants?”
}

Which is the correct format that the API call will accept.

Passing the data isn’t enough; the data needs to be passed as key/value pairs representing the identical structure to what the API call expects.

I hope this helps! If this doesn’t work/help, let us know so we can continue to help debug!

1 Like

I’m not familiar with C#, but the payload is different across these two endpoints.

POST v1/threads accepts a messages: list, whereas POST v1/threads/:id/messages accepts top-level role, content, etc.

You might have to change the payload for the second endpoint.

2 Likes

Awesome, this was indeed the solution! Thank you so much.