use agentforge_core::{
AgentFile, AgentForgeError, EvalHints, ModelConfig, ModelProvider, Result, ToolDefinition,
};
pub fn normalize(value: &serde_json::Value) -> Result<AgentFile> {
let name = value
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("anthropic-agent")
.to_string();
let system_prompt = value
.get("system")
.or_else(|| value.get("system_prompt"))
.and_then(|v| v.as_str())
.ok_or_else(|| {
AgentForgeError::ValidationError("Anthropic: missing 'system' field".to_string())
})?
.to_string();
let model_id = value
.get("model")
.and_then(|v| v.as_str())
.ok_or_else(|| {
AgentForgeError::ValidationError("Anthropic: missing 'model' field".to_string())
})?
.to_string();
let max_tokens = value
.get("max_tokens")
.and_then(|t| t.as_u64())
.map(|v| v as u32);
let temperature = value.get("temperature").and_then(|t| t.as_f64());
let model = ModelConfig {
provider: ModelProvider::Anthropic,
model_id,
temperature,
max_tokens,
top_p: None,
};
let tools = parse_anthropic_tools(value)?;
Ok(AgentFile {
agentforge_schema_version: "1".to_string(),
name,
version: "1.0.0".to_string(),
model,
system_prompt,
tools,
output_schema: None,
constraints: vec![],
eval_hints: Some(EvalHints::default()),
metadata: None,
})
}
fn parse_anthropic_tools(value: &serde_json::Value) -> Result<Vec<ToolDefinition>> {
let tools_val = match value.get("tools") {
Some(t) => t,
None => return Ok(vec![]),
};
let arr = tools_val
.as_array()
.ok_or_else(|| AgentForgeError::ValidationError("tools must be an array".to_string()))?;
arr.iter()
.map(|t| {
let name = t
.get("name")
.and_then(|n| n.as_str())
.ok_or_else(|| {
AgentForgeError::ValidationError("Anthropic tool missing name".to_string())
})?
.to_string();
let description = t
.get("description")
.and_then(|d| d.as_str())
.unwrap_or("")
.to_string();
let parameters = t
.get("input_schema")
.cloned()
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
Ok(ToolDefinition {
name,
description,
parameters,
})
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn normalizes_anthropic_agent() {
let v = json!({
"model": "claude-3-5-sonnet-20241022",
"system": "You are a helpful support agent.",
"max_tokens": 1024,
"tools": [
{
"name": "get_order",
"description": "Get order details",
"input_schema": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"]
}
}
]
});
let agent = normalize(&v).unwrap();
assert_eq!(agent.model.provider, ModelProvider::Anthropic);
assert_eq!(agent.tools.len(), 1);
assert_eq!(agent.tools[0].name, "get_order");
assert_eq!(agent.model.max_tokens, Some(1024));
}
#[test]
fn accepts_system_prompt_key() {
let v = json!({
"model": "claude-3-opus-20240229",
"system_prompt": "You are helpful."
});
let agent = normalize(&v).unwrap();
assert_eq!(agent.system_prompt, "You are helpful.");
}
}