1#[cfg(not(feature = "export_golem_agentic"))]
16pub use crate::bindings::golem::agent::common::Principal;
17#[cfg(not(feature = "export_golem_agentic"))]
18pub use crate::bindings::golem::tool::streams::ToolOutputWriter;
19#[cfg(feature = "export_golem_agentic")]
20pub use crate::golem_agentic::golem::agent::common::Principal;
21#[cfg(feature = "export_golem_agentic")]
22pub use crate::golem_agentic::golem::tool::streams::ToolOutputWriter;
23pub use crate::schema::tool::Tool;
24pub use crate::schema::tool::{
25 MonomorphicToolMiddlewareScope, ProcessExitStatus, ToolMiddleware, ToolMiddlewareScope,
26};
27pub use tool_middleware::{
28 InputStream, InvocationResult, RawCustomToolError, ToolInvokeError, TypedUnderlyingInvocation,
29 UnderlyingInvocation, UnderlyingTool, decode_result_empty, decode_result_outputs_only,
30 decode_result_stderr_only, decode_result_stdout_only, decode_result_value,
31 decode_result_with_outputs, decode_result_with_stderr, decode_result_with_stdout,
32};
33
34#[doc(hidden)]
35#[derive(crate::IntoSchema, crate::FromSchema)]
36pub struct EmptyMiddlewareParameters {}
37
38#[doc(hidden)]
39pub fn decode_middleware_parameters<T>(
40 parameters: crate::TypedSchemaValue,
41) -> Result<T, ToolInvokeError<RawCustomToolError>>
42where
43 T: crate::IntoSchema + crate::FromSchema,
44{
45 let expected = crate::schema::try_into_schema_graph::<T>()
46 .map_err(|error| ToolInvokeError::InvalidInput(error.to_string()))?;
47 if parameters.graph() != &expected {
48 return Err(ToolInvokeError::InvalidInput(
49 "tool middleware installation parameters do not match the declared schema".to_string(),
50 ));
51 }
52 T::from_value(parameters.value())
53 .map_err(|error| ToolInvokeError::InvalidInput(error.to_string()))
54}
55pub use tool_middleware::OutputStream;
56#[doc(hidden)]
57pub use tool_middleware::{ToolMiddlewareInvokeFuture, ToolMiddlewareInvokeFutureFor};
58#[doc(hidden)]
59pub use tool_middleware_registry::{
60 ToolMiddlewareInvoker, get_all_tool_middlewares, get_tool_middleware_by_name,
61 get_tool_middleware_invoker_by_name, register_tool_middleware,
62};
63
64#[cfg(any(test, feature = "export_golem_agentic"))]
65pub(crate) use crate::schema::tool::wit::wire;
66
67#[cfg(any(test, feature = "export_golem_agentic"))]
68pub(crate) mod invocation_result;
69mod tool_middleware;
70#[cfg(feature = "export_golem_agentic")]
71mod tool_middleware_impl;
72#[cfg(feature = "export_golem_agentic")]
73#[doc(hidden)]
74pub use tool_middleware_impl::install_middleware_exports;
75mod tool_middleware_registry;
76
77#[doc(hidden)]
78pub trait ToolUnderlying: Sized {
79 fn __golem_from_underlying(underlying: UnderlyingTool) -> Self;
80
81 fn __golem_tool_descriptor() -> Tool;
82}
83
84#[cfg(test)]
85mod parameter_tests {
86 use super::*;
87 use crate::{FromSchema, IntoSchema, IntoTypedSchemaValue};
88 use test_r::test;
89
90 #[derive(Debug, PartialEq, IntoSchema, FromSchema)]
91 struct NestedParameters {
92 prefix: String,
93 rules: Vec<Rule>,
94 }
95
96 #[derive(Debug, PartialEq, IntoSchema, FromSchema)]
97 struct Rule {
98 label: String,
99 enabled: bool,
100 }
101
102 #[test]
103 fn decodes_distinct_invocation_local_parameter_values() {
104 for prefix in ["first", "second"] {
105 let value = NestedParameters {
106 prefix: prefix.to_string(),
107 rules: vec![Rule {
108 label: "nested".to_string(),
109 enabled: true,
110 }],
111 };
112 let decoded = decode_middleware_parameters::<NestedParameters>(
113 value.into_typed_schema_value().unwrap(),
114 )
115 .unwrap();
116 assert_eq!(decoded, value);
117 }
118 }
119
120 #[test]
121 fn rejects_parameter_value_with_wrong_declared_type() {
122 let error = decode_middleware_parameters::<NestedParameters>(
123 "not parameters"
124 .to_string()
125 .into_typed_schema_value()
126 .unwrap(),
127 )
128 .unwrap_err();
129 assert!(matches!(error, ToolInvokeError::InvalidInput(_)));
130 }
131
132 #[test]
133 fn omitted_parameters_use_an_empty_record_schema() {
134 let schema = crate::schema::try_into_schema_graph::<EmptyMiddlewareParameters>().unwrap();
135 assert!(matches!(
136 schema.resolve_ref(&schema.root).unwrap(),
137 crate::schema::SchemaType::Record { fields, .. } if fields.is_empty()
138 ));
139 }
140}