use serde_json::Value;
use super::call::{GuardedToolCall, InteropError, ToolCallRequest};
use super::{anthropic, langchain, mcp, openai, pydantic_ai};
pub type ParseFn = fn(&Value) -> Result<Vec<ToolCallRequest>, InteropError>;
pub type DenialFn = fn(&GuardedToolCall) -> Option<Value>;
pub type FilterFn = fn(&Value, &dyn Fn(&str) -> bool) -> Value;
pub struct Dialect {
pub name: &'static str,
pub parse: ParseFn,
pub denial: DenialFn,
pub filter: FilterFn,
}
pub const DIALECTS: &[Dialect] = &[
Dialect {
name: openai::DIALECT,
parse: openai::parse_tool_calls,
denial: openai::denial,
filter: openai::filter_tools,
},
Dialect {
name: anthropic::DIALECT,
parse: anthropic::parse_tool_calls,
denial: anthropic::denial,
filter: anthropic::filter_tools,
},
Dialect {
name: langchain::DIALECT,
parse: langchain::parse_tool_calls,
denial: langchain::denial,
filter: langchain::filter_tools,
},
Dialect {
name: pydantic_ai::DIALECT,
parse: pydantic_ai::parse_tool_calls,
denial: pydantic_ai::denial,
filter: pydantic_ai::filter_tools,
},
Dialect {
name: mcp::DIALECT,
parse: mcp::parse_tool_calls,
denial: mcp::denial,
filter: mcp::filter_tools,
},
];
pub fn dialect(name: &str) -> Option<&'static Dialect> {
let canonical = if name == "pydantic_ai" {
"pydantic-ai"
} else {
name
};
DIALECTS.iter().find(|dialect| dialect.name == canonical)
}
pub fn unknown_dialect_message(name: &str) -> String {
format!("unknown dialect '{name}' (expected openai, anthropic, langchain, pydantic-ai, or mcp)")
}