ferrin_tool/
model_output.rs1use ferrin_spec::JsonValue;
4use ferrin_spec::ToolCallId;
5use ferrin_spec::language_model::prompt::ToolResultOutput;
6
7use crate::error::ToolError;
8use crate::tool::ModelOutputArgs;
9use crate::tool::Tool;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13#[non_exhaustive]
14pub enum ErrorMode {
15 #[default]
17 None,
18 Text,
20 Json,
22}
23
24#[must_use]
30pub fn create_tool_model_output(
31 tool: Option<&Tool>,
32 tool_call_id: &ToolCallId,
33 input: &JsonValue,
34 output: &JsonValue,
35 error_mode: ErrorMode,
36) -> ToolResultOutput {
37 match error_mode {
38 ErrorMode::Text => return ToolResultOutput::error_text(error_message(output)),
39 ErrorMode::Json => return ToolResultOutput::error_json(output.clone()),
40 ErrorMode::None => {}
41 }
42 if let Some(convert) = tool.and_then(Tool::to_model_output) {
43 return convert(ModelOutputArgs {
44 tool_call_id,
45 input,
46 output,
47 });
48 }
49 match output {
50 JsonValue::String(text) => ToolResultOutput::text(text.clone()),
51 other => ToolResultOutput::json(other.clone()),
52 }
53}
54
55#[must_use]
57pub fn tool_error_output(error: &ToolError) -> ToolResultOutput {
58 match error {
59 ToolError::Json { value } => ToolResultOutput::error_json(value.clone()),
60 other => ToolResultOutput::error_text(other.to_string()),
61 }
62}
63
64#[must_use]
67pub fn error_message(value: &JsonValue) -> String {
68 match value {
69 JsonValue::Null => "unknown error".to_owned(),
70 JsonValue::String(text) => text.clone(),
71 JsonValue::Object(map) => match map.get("message") {
72 Some(JsonValue::String(message)) => message.clone(),
73 _ => value.to_string(),
74 },
75 other => other.to_string(),
76 }
77}