Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static Response ToResponse(
Error = null,
Id = context.ResponseId,
Instructions = request.Instructions,
Logprobs = request.Logprobs,
MaxOutputTokens = request.MaxOutputTokens,
MaxToolCalls = request.MaxToolCalls,
Metadata = request.Metadata is IReadOnlyDictionary<string, string> metadata ? new Dictionary<string, string>(metadata) : [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ Response CreateResponse(ResponseStatus status = ResponseStatus.Completed, IEnume
Error = null,
Id = context.ResponseId,
Instructions = request.Instructions,
Logprobs = request.Logprobs,
MaxOutputTokens = request.MaxOutputTokens,
MaxToolCalls = request.MaxToolCalls,
Metadata = request.Metadata != null ? new Dictionary<string, string>(request.Metadata) : [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ private ResponseState InitializeResponse(string responseId, CreateResponse reque
Id = responseId,
IncompleteDetails = null,
Instructions = request.Instructions,
Logprobs = request.Logprobs,
MaxOutputTokens = request.MaxOutputTokens,
MaxToolCalls = request.MaxToolCalls,
Metadata = metadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ internal sealed class CreateResponse
[JsonPropertyName("max_tool_calls")]
public int? MaxToolCalls { get; init; }

/// <summary>
/// Whether to return log probabilities of the output tokens.
/// </summary>
[JsonPropertyName("logprobs")]
public bool? Logprobs { get; init; }

/// <summary>
/// An integer between 0 and 20 specifying the number of most likely tokens to return at each token position.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ internal sealed record Response
[JsonPropertyName("max_tool_calls")]
public int? MaxToolCalls { get; init; }

/// <summary>
/// Whether log probabilities were requested for the output tokens.
/// </summary>
[JsonPropertyName("logprobs")]
public bool? Logprobs { get; init; }
Comment thread
moonbox3 marked this conversation as resolved.

/// <summary>
/// An integer between 0 and 20 specifying the number of most likely tokens to return at each token position.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,31 @@ public void Serialize_CreateRequestWithOptions_IncludesAllFields()
Assert.Equal("value2", metadata.GetProperty("key2").GetString());
}

[Fact]
public void Deserialize_CreateResponseWithLogprobs_RoundTripsFields()
{
const string Json = """
{
"model": "gpt-4o-mini",
"input": "Return token probabilities.",
"logprobs": true,
"top_logprobs": 3
}
""";

CreateResponse? createResponse = JsonSerializer.Deserialize(Json, OpenAIHostingJsonContext.Default.CreateResponse);
string reserializedJson = JsonSerializer.Serialize(createResponse, OpenAIHostingJsonContext.Default.CreateResponse);
using var doc = JsonDocument.Parse(reserializedJson);
var root = doc.RootElement;

Assert.NotNull(createResponse);
Assert.True(createResponse.Logprobs.HasValue);
Assert.True(createResponse.Logprobs.Value);
Assert.Equal(3, createResponse.TopLogprobs);
Assert.True(root.GetProperty("logprobs").GetBoolean());
Assert.Equal(3, root.GetProperty("top_logprobs").GetInt32());
}

[Fact]
public void Serialize_NullableFields_AreOmittedWhenNull()
{
Expand Down Expand Up @@ -535,6 +560,43 @@ public void Deserialize_MetadataResponse_HasModelParameters()
Assert.Equal(150, response.MaxOutputTokens);
}

[Fact]
public void Deserialize_ResponseWithLogprobs_RoundTripsFields()
{
const string Json = """
{
"id": "resp_logprobs",
"object": "response",
"created_at": 1715000000,
"model": "gpt-4o-mini",
"status": "completed",
"output": [],
"usage": {
"input_tokens": 0,
"input_tokens_details": { "cached_tokens": 0 },
"output_tokens": 0,
"output_tokens_details": { "reasoning_tokens": 0 },
"total_tokens": 0
},
"tools": [],
"logprobs": true,
"top_logprobs": 3
}
""";

Response? response = JsonSerializer.Deserialize(Json, OpenAIHostingJsonContext.Default.Response);
string reserializedJson = JsonSerializer.Serialize(response, OpenAIHostingJsonContext.Default.Response);
using var doc = JsonDocument.Parse(reserializedJson);
var root = doc.RootElement;

Assert.NotNull(response);
Assert.True(response.Logprobs.HasValue);
Assert.True(response.Logprobs.Value);
Assert.Equal(3, response.TopLogprobs);
Comment thread
he-yufeng marked this conversation as resolved.
Assert.True(root.GetProperty("logprobs").GetBoolean());
Assert.Equal(3, root.GetProperty("top_logprobs").GetInt32());
}

[Fact]
public void Deserialize_ToolCallResponse_HasFunctionCall()
{
Expand Down
Loading