use std::collections::BTreeMap;
use dynamo_parsers::tool_calling::ToolDefinition;
use dynamo_parsers::tool_calling::parsers::detect_and_parse_tool_call_with_recovery;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Deserialize)]
struct Input {
family: String,
cases: BTreeMap<String, CaseIn>,
}
#[derive(Deserialize)]
struct CaseIn {
model_text: String,
#[serde(default)]
tools: Vec<RawTool>,
}
#[derive(Deserialize)]
struct RawTool {
name: String,
#[serde(default)]
parameters: Option<Value>,
#[serde(default)]
strict: Option<bool>,
}
#[derive(Serialize)]
struct CaseOut {
calls: Vec<CallOut>,
normal_text: String,
}
#[derive(Serialize)]
struct CallOut {
name: String,
arguments: Value,
}
#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
let path = std::env::args()
.nth(1)
.ok_or_else(|| anyhow::anyhow!("usage: record_dynamo_batch <input.json>"))?;
let input: Input = serde_json::from_str(&std::fs::read_to_string(&path)?)?;
let mut out = BTreeMap::new();
for (cid, case) in &input.cases {
let tools: Vec<ToolDefinition> = case
.tools
.iter()
.map(|t| ToolDefinition {
name: t.name.clone(),
parameters: t.parameters.clone(),
strict: t.strict,
})
.collect();
let tools_opt = (!tools.is_empty()).then_some(tools.as_slice());
match detect_and_parse_tool_call_with_recovery(
&case.model_text,
Some(&input.family),
tools_opt,
)
.await
{
Ok((calls, normal_text)) => {
out.insert(
cid.clone(),
CaseOut {
calls: calls
.into_iter()
.map(|c| CallOut {
name: c.function.name.clone(),
arguments: serde_json::from_str(&c.function.arguments)
.unwrap_or(Value::String(c.function.arguments)),
})
.collect(),
normal_text: normal_text.unwrap_or_default(),
},
);
}
Err(e) => eprintln!("record_dynamo_batch: {} [{cid}]: {e}", input.family),
}
}
println!("{}", serde_json::to_string_pretty(&out)?);
Ok(())
}