use objectiveai_sdk::agent::completions::message::AssistantMessage;
pub fn tool_calls_from_state(state: &AssistantMessage) -> Vec<(&str, &str)> {
state.tool_calls.as_ref().map_or(Vec::new(), |tcs| {
tcs.iter().map(|tc| match tc {
objectiveai_sdk::agent::completions::message::AssistantToolCall::Function { id, function } => {
(function.name.as_str(), id.as_str())
}
}).collect()
})
}
pub fn tool_call_count(state: &AssistantMessage) -> usize {
state.tool_calls.as_ref().map_or(0, |tcs| tcs.len())
}
pub fn validate_continuation<'a>(
state: &AssistantMessage,
items_after: impl Iterator<Item = &'a super::super::ContinuationItem<AssistantMessage>>,
) -> Result<(), super::Error> {
use objectiveai_sdk::agent::completions::message::RichContent;
let calls = tool_calls_from_state(state);
if !calls.iter().any(|(name, _)| is_append_task(name) || is_write_input_schema(name)) {
return Ok(());
}
for item in items_after {
if let super::super::ContinuationItem::ToolMessage(msg) = item {
if let Some((name, _)) = calls.iter().find(|(_, id)| *id == msg.tool_call_id) {
let content = match &msg.content {
RichContent::Text(t) => t.as_str(),
RichContent::Parts(_) => "",
};
if is_append_task(name) {
if content.is_empty() || !content.bytes().all(|b| b.is_ascii_digit()) {
return Err(super::Error::AppendTaskFailed(content.to_string()));
}
} else if is_write_input_schema(name) {
if content != "Ok" {
return Err(super::Error::WriteInputSchemaFailed(content.to_string()));
}
}
}
}
}
Ok(())
}
const APPEND_TASK: &str = "AppendTask";
const APPEND_TASK_SUFFIXED: &str = "AppendTask (objectiveai-invention)";
const WRITE_INPUT_SCHEMA: &str = "WriteInputSchema";
const WRITE_INPUT_SCHEMA_SUFFIXED: &str = "WriteInputSchema (objectiveai-invention)";
fn is_append_task(name: &str) -> bool {
name == APPEND_TASK || name == APPEND_TASK_SUFFIXED
}
fn is_write_input_schema(name: &str) -> bool {
name == WRITE_INPUT_SCHEMA || name == WRITE_INPUT_SCHEMA_SUFFIXED
}