use nexo_llm::PromptBlock;
pub struct PromptInputs {
pub workspace: Option<String>,
pub skills: Option<String>,
pub binding_glue: Option<String>,
pub channel_meta: Option<String>,
}
pub fn build_blocks(inputs: PromptInputs) -> Vec<PromptBlock> {
let mut out: Vec<PromptBlock> = Vec::with_capacity(4);
if let Some(text) = non_empty(inputs.workspace) {
out.push(PromptBlock::cached_long("workspace", text));
}
if let Some(text) = non_empty(inputs.skills) {
out.push(PromptBlock::cached_long("skills", text));
}
if let Some(text) = non_empty(inputs.binding_glue) {
out.push(PromptBlock::cached_long("binding_glue", text));
}
if let Some(text) = non_empty(inputs.channel_meta) {
out.push(PromptBlock::cached_short("channel_meta", text));
}
out
}
fn non_empty(s: Option<String>) -> Option<String> {
s.and_then(|t| if t.trim().is_empty() { None } else { Some(t) })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_inputs_yield_empty_list() {
let out = build_blocks(PromptInputs {
workspace: None,
skills: None,
binding_glue: None,
channel_meta: None,
});
assert!(out.is_empty());
}
#[test]
fn empty_strings_drop_out() {
let out = build_blocks(PromptInputs {
workspace: Some("".to_string()),
skills: Some(" ".to_string()),
binding_glue: Some("real".to_string()),
channel_meta: None,
});
assert_eq!(out.len(), 1);
assert_eq!(out[0].label, "binding_glue");
assert_eq!(out[0].text, "real");
}
#[test]
fn ordered_and_labeled() {
let out = build_blocks(PromptInputs {
workspace: Some("ws".into()),
skills: Some("sk".into()),
binding_glue: Some("bg".into()),
channel_meta: Some("cm".into()),
});
assert_eq!(out.len(), 4);
let labels: Vec<_> = out.iter().map(|b| b.label).collect();
assert_eq!(
labels,
vec!["workspace", "skills", "binding_glue", "channel_meta"]
);
}
#[test]
fn workspace_skills_glue_get_long_ttl_and_meta_short() {
use nexo_llm::CachePolicy;
let out = build_blocks(PromptInputs {
workspace: Some("ws".into()),
skills: Some("sk".into()),
binding_glue: Some("bg".into()),
channel_meta: Some("cm".into()),
});
assert_eq!(out[0].cache, CachePolicy::Ephemeral1h);
assert_eq!(out[1].cache, CachePolicy::Ephemeral1h);
assert_eq!(out[2].cache, CachePolicy::Ephemeral1h);
assert_eq!(out[3].cache, CachePolicy::Ephemeral5m);
}
#[test]
fn cap_at_four_blocks_by_construction() {
let out = build_blocks(PromptInputs {
workspace: Some("a".into()),
skills: Some("b".into()),
binding_glue: Some("c".into()),
channel_meta: Some("d".into()),
});
assert!(out.len() <= 4);
}
}