formalize ai input transform (#7078)

* ai input transform

* fix
This commit is contained in:
Ruben Fiszel
2025-11-07 09:03:44 +01:00
committed by GitHub
parent 5f7e0b7244
commit ad861f5312
6 changed files with 41 additions and 11 deletions
+1
View File
@@ -3769,6 +3769,7 @@ async fn batch_rerun_handle_job(
batch_rerun_compute_js_expression(expr.clone(), job.clone()).await?,
);
}
InputTransform::Ai => {}
}
}
+3 -2
View File
@@ -643,6 +643,7 @@ pub enum InputTransform {
#[serde(default = "default_empty_string")]
expr: String,
},
Ai,
}
impl InputTransform {
@@ -661,6 +662,7 @@ impl TryFrom<UntaggedInputTransform> for InputTransform {
let input_transform = match value.type_.as_str() {
"static" => InputTransform::new_static_value(value.value.unwrap_or_else(default_null)),
"javascript" => InputTransform::new_javascript_expr(&value.expr.unwrap_or_default()),
"ai" => InputTransform::Ai,
other => {
return Err(anyhow::anyhow!(
"got value: {other} for field `type`, expected value: `static` or `javascript`"
@@ -816,8 +818,7 @@ pub struct McpToolValue {
pub exclude_tools: Vec<String>,
}
fn is_none_or_empty_vec<T>(expr: &Option<Vec<T>>) -> bool
{
fn is_none_or_empty_vec<T>(expr: &Option<Vec<T>>) -> bool {
expr.is_none() || expr.as_ref().unwrap().is_empty()
}
+9 -3
View File
@@ -322,11 +322,17 @@ async fn execute_windmill_tool(
// Evaluate each input transform and merge with AI-provided args
for (key, transform) in input_transforms.iter() {
// We skip static empty / null values, those are the one the AI will fill in
if let InputTransform::Static { value } = transform {
let val = value.get().trim();
if val.is_empty() || val == "null" {
match transform {
InputTransform::Static { value } => {
let val = value.get().trim();
if val.is_empty() || val == "null" {
continue;
}
}
InputTransform::Ai => {
continue;
}
_ => (),
}
let result = evaluate_input_transform::<Box<RawValue>>(
transform,
+1
View File
@@ -78,6 +78,7 @@ pub fn filter_schema_by_input_transforms(
!val.is_empty() && val != "null"
}
InputTransform::Javascript { expr } => !expr.trim().is_empty(),
InputTransform::Ai => false,
};
if is_completed {
Some(key.clone())
+19 -4
View File
@@ -1910,11 +1910,8 @@ pub async fn evaluate_input_transform<T>(
by_id: Option<&IdContext>,
) -> error::Result<T>
where
T: for<'de> serde::Deserialize<'de> + Send,
T: for<'de> serde::Deserialize<'de> + Send + Default,
{
let mut context = HashMap::with_capacity(2);
context.insert("result".to_string(), last_result.clone());
context.insert("previous_result".to_string(), last_result.clone());
match transform {
InputTransform::Static { value } => serde_json::from_str(value.get()).map_err(|e| {
Error::ExecutionErr(format!(
@@ -1923,6 +1920,9 @@ where
))
}),
InputTransform::Javascript { expr } => {
let mut context = HashMap::with_capacity(2);
context.insert("result".to_string(), last_result.clone());
context.insert("previous_result".to_string(), last_result.clone());
let result = eval_timeout(
expr.to_string(),
context,
@@ -1947,6 +1947,7 @@ where
))
})
}
InputTransform::Ai => Ok(T::default()),
}
}
@@ -2007,6 +2008,7 @@ async fn transform_input(
})?;
mapped.insert(key.to_string(), v);
}
InputTransform::Ai => (),
}
}
@@ -2441,6 +2443,9 @@ async fn push_next_flow_job(
)));
}
}
InputTransform::Ai => {
user_groups_required = Vec::new();
}
}
} else {
user_groups_required = Vec::new();
@@ -4348,6 +4353,11 @@ async fn next_forloop_status(
/* Iterator is an InputTransform, evaluate it into an array. */
let itered_raw = match iterator {
InputTransform::Static { value } => to_raw_value(value),
InputTransform::Ai => {
return Err(Error::ExecutionErr(format!(
"AI input transform not supported for iterator"
)))?
}
InputTransform::Javascript { expr } => {
let mut context = HashMap::with_capacity(5);
context.insert("result".to_string(), arc_last_job_result.clone());
@@ -4429,6 +4439,11 @@ async fn next_forloop_status(
)
.await?
}
InputTransform::Ai => {
return Err(Error::ExecutionErr(format!(
"AI input transform not supported for iterator"
)))?
}
};
serde_json::from_str::<Vec<Box<RawValue>>>(itered_raw.get()).map_err(
|not_array| {
@@ -159,7 +159,13 @@
function getPropertyType(arg: InputTransform | any): PropertyType {
// For agent tools, if static with undefined/empty value, treat as 'ai', meaning the field will be filled by the AI agent dynamically.
if (isAgentTool && arg?.type === 'static' && arg?.value === undefined) {
if (
isAgentTool &&
((arg?.type === 'static' && arg?.value === undefined) || arg?.type === 'ai')
) {
if (arg?.type === 'static') {
arg.type = 'ai'
}
return 'ai'
}
@@ -563,7 +569,7 @@
if (e.detail === 'ai') {
// Switch to AI mode: static with no value
if (arg) {
arg.type = 'static'
arg.type = 'ai'
arg.value = undefined
arg.expr = undefined
}