1use std::sync::{Arc, Mutex};
13
14use kernel::{
15 AxCode, AxError, CostTier, Effect, Payload, RenderIntent, Temporal, Tool, ToolCall, ToolMeta,
16 ToolName, ToolOutcome,
17};
18
19use crate::catalog::Catalog;
20
21pub struct CallTool {
23 catalog: Arc<Mutex<Catalog>>,
24 meta: ToolMeta,
25}
26
27impl CallTool {
28 pub const NAME: &'static str = "call";
31
32 pub fn new(catalog: Arc<Mutex<Catalog>>) -> Result<CallTool, AxError> {
36 Ok(CallTool {
37 catalog,
38 meta: ToolMeta {
39 name: ToolName::parse(Self::NAME)?,
40 disclosure: "Run a tool from the dormant index by its name. `describe` it first \
41 for its input schema; arguments that do not fit are refused with \
42 the schema."
43 .to_owned(),
44 params: Payload::of(&serde_json::json!({
45 "type": "object",
46 "properties": {
47 "name": { "type": "string", "description": "the tool to run, as the \
48 dormant index or `describe` spells it" },
49 "args": { "type": "object", "description": "the tool's own \
50 arguments, as its input schema asks" },
51 },
52 "required": ["name", "args"],
53 }))?,
54 effect: Effect::Read,
55 cost_tier: CostTier::Free,
56 timeout: None,
57 render: RenderIntent::Generic,
58 temporal: Temporal::Timeless,
59 },
60 })
61 }
62}
63
64impl Tool for CallTool {
65 fn meta(&self) -> &ToolMeta {
66 &self.meta
67 }
68
69 fn invoke(&self, call: &ToolCall) -> Result<ToolOutcome, AxError> {
70 if call.name != self.meta.name {
71 return Err(AxError::failure(
72 AxCode::InvalidArgs,
73 "call a dormant tool",
74 format!("call routed to the wrong tool: {}", call.name.as_str()),
75 )
76 .with_recovery(format!(
77 "call `{}`, the name this tool answers to",
78 Self::NAME
79 )));
80 }
81 let resolved = self
82 .catalog
83 .lock()
84 .map_err(|_| super::describe::poisoned())?
85 .resolve_call(call)?;
86 Err(AxError::failure(
90 AxCode::ToolUnavailable,
91 "call a dormant tool",
92 format!("`{}` was not resolved before it ran", resolved.name),
93 )
94 .with_recovery(
95 "report this against the tool face driving this run: it must resolve a `call` \
96 before admitting it",
97 ))
98 }
99}