use super::super::staging::StagingWriter;
use super::{ModelCall, SegmentOutcome, stderr};
use crate::prompt::Error;
use brazen::{CanonicalError, Event, FinishReason};
use std::fs::File;
use std::io::Write;
pub(super) fn run_attempt(
call: &ModelCall<'_>,
args: &[&str],
request_bytes: &[u8],
response_file: &mut File,
stderr_file: &mut File,
staging: &mut StagingWriter,
) -> Result<SegmentOutcome, Error> {
let mut feed_err: Option<serde_json::Error> = None;
let mut staging_err: Option<Error> = None;
let mut error: Option<CanonicalError> = None;
let mut truncated = false;
let mut ended = false;
let mut handshake_v: Option<u8> = None;
let stderr = call
.adapter
.run(call.binary, args, request_bytes, &mut |line| {
response_file.write_all(line)?;
response_file.write_all(b"\n")?;
if feed_err.is_none() && staging_err.is_none() && !ended {
match serde_json::from_slice::<Event>(line) {
Ok(event) => {
match &event {
Event::MessageStart { v, .. } => handshake_v = Some(*v),
Event::Error(e) => error = Some(e.clone()),
Event::Finish { reason } => {
truncated = *reason == FinishReason::Length;
}
Event::End => ended = true,
_ => {}
}
if let Err(e) = staging.feed(&event) {
staging_err = Some(e);
}
}
Err(e) => feed_err = Some(e),
}
}
Ok(())
})
.map_err(|e| crate::prompt::adapter::spawn_error(call.binary, e))?;
stderr_file.write_all(&stderr)?;
if let Some(e) = feed_err {
return Err(Error::AdapterJson(e));
}
if let Some(e) = staging_err {
return Err(e);
}
if let Some(err) = error {
return Ok(SegmentOutcome::Failed(err));
}
if !ended {
return Ok(SegmentOutcome::HalfStream {
stderr_tail: stderr::tail(&stderr),
});
}
if truncated {
return Ok(SegmentOutcome::Truncated);
}
Ok(SegmentOutcome::Complete { handshake_v })
}