fix(api): split openai compat stream state into nested flags

Resolves clippy::struct_excessive_bools in openai_compat.rs.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim 2026-04-02 14:57:07 +09:00
parent 464a870180
commit 23ba21bdd5

View file

@ -299,23 +299,31 @@ impl OpenAiSseParser {
#[derive(Debug)] #[derive(Debug)]
struct StreamState { struct StreamState {
model: String, model: String,
message_started: bool, message: MessageState,
text_started: bool, text: TextState,
text_finished: bool,
finished: bool,
stop_reason: Option<String>, stop_reason: Option<String>,
usage: Option<Usage>, usage: Option<Usage>,
tool_calls: BTreeMap<u32, ToolCallState>, tool_calls: BTreeMap<u32, ToolCallState>,
} }
#[derive(Debug, Default)]
struct MessageState {
started: bool,
finished: bool,
}
#[derive(Debug, Default)]
struct TextState {
started: bool,
finished: bool,
}
impl StreamState { impl StreamState {
fn new(model: String) -> Self { fn new(model: String) -> Self {
Self { Self {
model, model,
message_started: false, message: MessageState::default(),
text_started: false, text: TextState::default(),
text_finished: false,
finished: false,
stop_reason: None, stop_reason: None,
usage: None, usage: None,
tool_calls: BTreeMap::new(), tool_calls: BTreeMap::new(),
@ -324,8 +332,8 @@ impl StreamState {
fn ingest_chunk(&mut self, chunk: ChatCompletionChunk) -> Result<Vec<StreamEvent>, ApiError> { fn ingest_chunk(&mut self, chunk: ChatCompletionChunk) -> Result<Vec<StreamEvent>, ApiError> {
let mut events = Vec::new(); let mut events = Vec::new();
if !self.message_started { if !self.message.started {
self.message_started = true; self.message.started = true;
events.push(StreamEvent::MessageStart(MessageStartEvent { events.push(StreamEvent::MessageStart(MessageStartEvent {
message: MessageResponse { message: MessageResponse {
id: chunk.id.clone(), id: chunk.id.clone(),
@ -357,8 +365,8 @@ impl StreamState {
for choice in chunk.choices { for choice in chunk.choices {
if let Some(content) = choice.delta.content.filter(|value| !value.is_empty()) { if let Some(content) = choice.delta.content.filter(|value| !value.is_empty()) {
if !self.text_started { if !self.text.started {
self.text_started = true; self.text.started = true;
events.push(StreamEvent::ContentBlockStart(ContentBlockStartEvent { events.push(StreamEvent::ContentBlockStart(ContentBlockStartEvent {
index: 0, index: 0,
content_block: OutputContentBlock::Text { content_block: OutputContentBlock::Text {
@ -414,14 +422,14 @@ impl StreamState {
} }
fn finish(&mut self) -> Result<Vec<StreamEvent>, ApiError> { fn finish(&mut self) -> Result<Vec<StreamEvent>, ApiError> {
if self.finished { if self.message.finished {
return Ok(Vec::new()); return Ok(Vec::new());
} }
self.finished = true; self.message.finished = true;
let mut events = Vec::new(); let mut events = Vec::new();
if self.text_started && !self.text_finished { if self.text.started && !self.text.finished {
self.text_finished = true; self.text.finished = true;
events.push(StreamEvent::ContentBlockStop(ContentBlockStopEvent { events.push(StreamEvent::ContentBlockStop(ContentBlockStopEvent {
index: 0, index: 0,
})); }));
@ -445,7 +453,7 @@ impl StreamState {
} }
} }
if self.message_started { if self.message.started {
events.push(StreamEvent::MessageDelta(MessageDeltaEvent { events.push(StreamEvent::MessageDelta(MessageDeltaEvent {
delta: MessageDelta { delta: MessageDelta {
stop_reason: Some( stop_reason: Some(