Skip to content

Commit 88938f0

Browse files
committed
feat: Add has_reasoning flag to chat completion responses
- Add has_reasoning field to ChatChoice and ChatChoiceStream structs - Set has_reasoning to true when reasoning_content is present and non-empty - Helps clients identify responses that include reasoning content Fixes #7154 Signed-off-by: Asad Shahid <asad.shahid@berkeley.edu>
1 parent 06f1701 commit 88938f0

5 files changed

Lines changed: 26 additions & 0 deletions

File tree

lib/async-openai/src/types/chat.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,10 @@ pub struct ChatChoice {
11571157
/// Log probability information for the choice.
11581158
#[serde(skip_serializing_if = "Option::is_none")]
11591159
pub logprobs: Option<ChatChoiceLogprobs>,
1160+
/// Flag indicating whether this choice includes reasoning content.
1161+
/// Set to `true` when `message.reasoning_content` is present.
1162+
#[serde(skip_serializing_if = "Option::is_none")]
1163+
pub has_reasoning: Option<bool>,
11601164
}
11611165

11621166
/// Represents a chat completion response returned by model, based on the provided input.
@@ -1256,6 +1260,10 @@ pub struct ChatChoiceStream {
12561260
/// Log probability information for the choice.
12571261
#[serde(skip_serializing_if = "Option::is_none")]
12581262
pub logprobs: Option<ChatChoiceLogprobs>,
1263+
/// Flag indicating whether this choice includes reasoning content.
1264+
/// Set to `true` when `delta.reasoning_content` is present.
1265+
#[serde(skip_serializing_if = "Option::is_none")]
1266+
pub has_reasoning: Option<bool>,
12591267
}
12601268

12611269
#[derive(ToSchema, Debug, Deserialize, Clone, PartialEq, Serialize)]

lib/llm/src/audit/stream.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ pub fn final_response_to_one_chunk_stream(
217217
finish_reason: ch.finish_reason,
218218
stop_reason: ch.stop_reason.clone(),
219219
logprobs: ch.logprobs.clone(),
220+
has_reasoning: ch.has_reasoning,
220221
};
221222
choices.push(choice);
222223
}
@@ -272,6 +273,7 @@ mod tests {
272273
finish_reason: None,
273274
stop_reason: None,
274275
logprobs: None,
276+
has_reasoning: None,
275277
};
276278

277279
let response = NvCreateChatCompletionStreamResponse {
@@ -311,6 +313,7 @@ mod tests {
311313
finish_reason: Some(FinishReason::Stop),
312314
stop_reason: None,
313315
logprobs: None,
316+
has_reasoning: None,
314317
};
315318

316319
let response = NvCreateChatCompletionStreamResponse {
@@ -441,6 +444,7 @@ mod tests {
441444
finish_reason: None,
442445
stop_reason: None,
443446
logprobs: None,
447+
has_reasoning: None,
444448
}
445449
}],
446450
created: 1234567890,

lib/llm/src/protocols/openai/chat_completions/aggregator.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,11 @@ impl From<DeltaChoice> for dynamo_async_openai::types::ChatChoice {
311311
None
312312
};
313313

314+
let has_reasoning = delta
315+
.reasoning_content
316+
.as_ref()
317+
.is_some_and(|r| !r.is_empty());
318+
314319
dynamo_async_openai::types::ChatChoice {
315320
message: dynamo_async_openai::types::ChatCompletionResponseMessage {
316321
role: delta.role.expect("delta should have a Role"),
@@ -325,6 +330,7 @@ impl From<DeltaChoice> for dynamo_async_openai::types::ChatChoice {
325330
finish_reason,
326331
stop_reason: delta.stop_reason,
327332
logprobs: delta.logprobs,
333+
has_reasoning: if has_reasoning { Some(true) } else { None },
328334
}
329335
}
330336
}

lib/llm/src/protocols/openai/chat_completions/delta.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,18 @@ impl DeltaGenerator {
265265
reasoning_content: None,
266266
};
267267

268+
let has_reasoning = delta
269+
.reasoning_content
270+
.as_ref()
271+
.is_some_and(|r| !r.is_empty());
272+
268273
let choice = dynamo_async_openai::types::ChatChoiceStream {
269274
index,
270275
delta,
271276
finish_reason,
272277
stop_reason,
273278
logprobs,
279+
has_reasoning: if has_reasoning { Some(true) } else { None },
274280
};
275281

276282
let choices = vec![choice];

lib/llm/src/protocols/openai/chat_completions/jail.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ fn create_choice_stream(
135135
finish_reason,
136136
stop_reason,
137137
logprobs,
138+
has_reasoning: None,
138139
}
139140
}
140141

@@ -598,6 +599,7 @@ impl JailedStream {
598599
finish_reason: choice.finish_reason,
599600
stop_reason: choice.stop_reason.clone(),
600601
logprobs: choice.logprobs.clone(),
602+
has_reasoning: choice.has_reasoning,
601603
};
602604
all_emissions.push(ChoiceEmission::PassThrough(pass_through_choice));
603605
}

0 commit comments

Comments
 (0)