use super::request::{Request, Turn};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SystemDelivery {
Flag,
Inline,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FlatPayload {
pub system: Option<String>,
pub body: String,
}
pub fn flatten_for_subprocess(req: &Request, delivery: SystemDelivery) -> FlatPayload {
let body = build_body(req);
match delivery {
SystemDelivery::Flag => FlatPayload {
system: req.system.clone(),
body,
},
SystemDelivery::Inline => {
let body = match &req.system {
Some(sys) => format!("System: {sys}\n\n{body}"),
None => body,
};
FlatPayload { system: None, body }
}
}
}
fn build_body(req: &Request) -> String {
let mut out = String::new();
if !req.contexts.is_empty() {
for ctx in &req.contexts {
out.push_str(ctx);
out.push_str("\n\n");
}
}
if req.turns.len() > 1 {
out.push_str("[prior conversation:]\n");
for (i, t) in req.turns.iter().enumerate() {
if i == req.turns.len() - 1 {
break; }
match t {
Turn::User(s) => out.push_str(&format!("User: {s}\n")),
Turn::Assistant(s) => out.push_str(&format!("Assistant: {s}\n")),
}
}
out.push_str("\n[current prompt:]\n");
}
if let Some(Turn::User(last)) = req.turns.last() {
out.push_str(last);
}
out
}
#[cfg(test)]
mod tests {
use super::*;
fn req_with(prompt: &str) -> Request {
let mut r = Request::new();
r.set_user(prompt);
r
}
#[test]
fn single_turn_inline_system_only() {
let mut r = req_with("hello");
r.set_system("you are helpful");
let p = flatten_for_subprocess(&r, SystemDelivery::Inline);
assert_eq!(p.system, None);
assert_eq!(p.body, "System: you are helpful\n\nhello");
}
#[test]
fn single_turn_flag_system_only() {
let mut r = req_with("hello");
r.set_system("you are helpful");
let p = flatten_for_subprocess(&r, SystemDelivery::Flag);
assert_eq!(p.system.as_deref(), Some("you are helpful"));
assert_eq!(p.body, "hello");
}
#[test]
fn single_turn_no_system_no_context() {
let r = req_with("just this");
let p = flatten_for_subprocess(&r, SystemDelivery::Flag);
assert_eq!(p.system, None);
assert_eq!(p.body, "just this");
}
#[test]
fn contexts_accumulate_in_order() {
let mut r = req_with("analyze");
r.push_context("cert: AAA");
r.push_context("probe: BBB");
let p = flatten_for_subprocess(&r, SystemDelivery::Flag);
assert_eq!(p.body, "cert: AAA\n\nprobe: BBB\n\nanalyze");
}
#[test]
fn multi_turn_renders_transcript() {
let mut r = Request::new();
r.set_user("Q1");
r.push_assistant("A1").unwrap();
r.set_user("Q2");
r.push_assistant("A2").unwrap();
r.set_user("Q3");
let p = flatten_for_subprocess(&r, SystemDelivery::Flag);
assert_eq!(
p.body,
"[prior conversation:]\nUser: Q1\nAssistant: A1\nUser: Q2\nAssistant: A2\n\n[current prompt:]\nQ3"
);
}
#[test]
fn multi_turn_with_system_and_context_inline() {
let mut r = Request::new();
r.set_system("be concise");
r.push_context("ctx1");
r.set_user("Q1");
r.push_assistant("A1").unwrap();
r.set_user("Q2");
let p = flatten_for_subprocess(&r, SystemDelivery::Inline);
let expected = "System: be concise\n\n\
ctx1\n\n\
[prior conversation:]\n\
User: Q1\n\
Assistant: A1\n\
\n[current prompt:]\n\
Q2";
assert_eq!(p.body, expected);
}
}