1818import io .cloudevents .CloudEventData ;
1919import io .serverlessworkflow .api .types .FlowDirectiveEnum ;
2020import io .serverlessworkflow .api .types .func .JavaContextFunction ;
21+ import io .serverlessworkflow .api .types .func .JavaFilterFunction ;
2122import io .serverlessworkflow .fluent .func .FuncCallTaskBuilder ;
2223import io .serverlessworkflow .fluent .func .FuncEmitTaskBuilder ;
2324import io .serverlessworkflow .fluent .func .FuncSwitchTaskBuilder ;
2627import io .serverlessworkflow .fluent .func .configurers .FuncTaskConfigurer ;
2728import io .serverlessworkflow .fluent .func .configurers .SwitchCaseConfigurer ;
2829import io .serverlessworkflow .fluent .func .dsl .internal .CommonFuncOps ;
30+ import io .serverlessworkflow .impl .TaskContextData ;
31+ import io .serverlessworkflow .impl .WorkflowContextData ;
2932import java .util .Collection ;
3033import java .util .List ;
3134import java .util .Map ;
@@ -286,7 +289,7 @@ public static <T, R> FuncCallStep<T, R> function(Function<T, R> fn, Class<T> cla
286289 }
287290
288291 /**
289- * Build a call step for functions that need {@code WorkflowContextData} as the first parameter.
292+ * Build a call step for functions that need {@link WorkflowContextData} as the first parameter.
290293 * The DSL wraps it as a {@link JavaContextFunction} and injects the runtime context.
291294 *
292295 * <p>Signature expected: {@code (ctx, payload) -> result}
@@ -297,7 +300,7 @@ public static <T, R> FuncCallStep<T, R> function(Function<T, R> fn, Class<T> cla
297300 * @param <R> result type
298301 * @return a call step
299302 */
300- public static <T , R > FuncCallStep <T , R > withContext (CtxBiFunction <T , R > fn , Class <T > in ) {
303+ public static <T , R > FuncCallStep <T , R > withContext (JavaContextFunction <T , R > fn , Class <T > in ) {
301304 return withContext (null , fn , in );
302305 }
303306
@@ -319,7 +322,7 @@ public static <T, R> FuncCallStep<T, R> withInstanceId(
319322 }
320323
321324 /**
322- * Named variant of {@link #withContext(CtxBiFunction , Class)}.
325+ * Named variant of {@link #withContext(JavaContextFunction , Class)}.
323326 *
324327 * @param name task name
325328 * @param fn context-aware bi-function
@@ -329,9 +332,40 @@ public static <T, R> FuncCallStep<T, R> withInstanceId(
329332 * @return a named call step
330333 */
331334 public static <T , R > FuncCallStep <T , R > withContext (
332- String name , CtxBiFunction <T , R > fn , Class <T > in ) {
333- JavaContextFunction <T , R > jcf = (payload , wctx ) -> fn .apply (wctx , payload );
334- return new FuncCallStep <>(name , jcf , in );
335+ String name , JavaContextFunction <T , R > fn , Class <T > in ) {
336+ return new FuncCallStep <>(name , fn , in );
337+ }
338+
339+ /**
340+ * Build a call step for functions that need {@link WorkflowContextData} and {@link
341+ * io.serverlessworkflow.impl.TaskContextData} as the first and second parameter. The DSL wraps it
342+ * as a {@link JavaFilterFunction} and injects the runtime context.
343+ *
344+ * <p>Signature expected: {@code (wctx, tctx, payload) -> result}
345+ *
346+ * @param fn context-aware bi-function
347+ * @param in payload input class
348+ * @param <T> input type
349+ * @param <R> result type
350+ * @return a call step
351+ */
352+ public static <T , R > FuncCallStep <T , R > withFilter (JavaFilterFunction <T , R > fn , Class <T > in ) {
353+ return withFilter (null , fn , in );
354+ }
355+
356+ /**
357+ * Named variant of {@link #withFilter(JavaFilterFunction, Class)}.
358+ *
359+ * @param name task name
360+ * @param fn context-aware bi-function
361+ * @param in payload input class
362+ * @param <T> input type
363+ * @param <R> result type
364+ * @return a named call step
365+ */
366+ public static <T , R > FuncCallStep <T , R > withFilter (
367+ String name , JavaFilterFunction <T , R > fn , Class <T > in ) {
368+ return new FuncCallStep <>(name , fn , in );
335369 }
336370
337371 /**
@@ -350,6 +384,38 @@ public static <T, R> FuncCallStep<T, R> withInstanceId(
350384 return new FuncCallStep <>(name , jcf , in );
351385 }
352386
387+ /**
388+ * Builds a composition of the current workflow instance id and the definition of the task
389+ * position as a JSON pointer.
390+ */
391+ static String defaultUniqueId (WorkflowContextData wctx , TaskContextData tctx ) {
392+ return String .format ("%s-%s" , wctx .instanceData ().id (), tctx .position ().jsonPointer ());
393+ }
394+
395+ /**
396+ * Build a call step for functions that expect a composition with the workflow instance id and the
397+ * task position as the first parameter. The instance ID is extracted from the runtime context,
398+ * the task position from the definition.
399+ *
400+ * <p>Signature expected: {@code (uniqueId, payload) -> result}
401+ *
402+ * @param fn unique-id-aware bi-function
403+ * @param in payload input class
404+ * @param <T> input type
405+ * @param <R> result type
406+ * @return a call step
407+ */
408+ public static <T , R > FuncCallStep <T , R > withUniqueId (
409+ String name , UniqueIdBiFunction <T , R > fn , Class <T > in ) {
410+ JavaFilterFunction <T , R > jff =
411+ (payload , wctx , tctx ) -> fn .apply (defaultUniqueId (wctx , tctx ), payload );
412+ return new FuncCallStep <>(name , jff , in );
413+ }
414+
415+ public static <T , R > FuncCallStep <T , R > withUniqueId (UniqueIdBiFunction <T , R > fn , Class <T > in ) {
416+ return withUniqueId (null , fn , in );
417+ }
418+
353419 /**
354420 * Create a fire-and-forget side-effect step (unnamed). The consumer receives the typed input.
355421 *
@@ -387,12 +453,12 @@ public static <T> ConsumeStep<T> consume(String name, Consumer<T> consumer, Clas
387453 * @param <R> result type
388454 * @return a call step
389455 */
390- public static <T , R > FuncCallStep <T , R > agent (InstanceIdBiFunction <T , R > fn , Class <T > in ) {
391- return withInstanceId (fn , in );
456+ public static <T , R > FuncCallStep <T , R > agent (UniqueIdBiFunction <T , R > fn , Class <T > in ) {
457+ return withUniqueId (fn , in );
392458 }
393459
394460 /**
395- * Named agent-style sugar. See {@link #agent(InstanceIdBiFunction , Class)}.
461+ * Named agent-style sugar. See {@link #agent(UniqueIdBiFunction , Class)}.
396462 *
397463 * @param name task name
398464 * @param fn (instanceId, payload) -> result
@@ -402,8 +468,8 @@ public static <T, R> FuncCallStep<T, R> agent(InstanceIdBiFunction<T, R> fn, Cla
402468 * @return a named call step
403469 */
404470 public static <T , R > FuncCallStep <T , R > agent (
405- String name , InstanceIdBiFunction <T , R > fn , Class <T > in ) {
406- return withInstanceId (name , fn , in );
471+ String name , UniqueIdBiFunction <T , R > fn , Class <T > in ) {
472+ return withUniqueId (name , fn , in );
407473 }
408474
409475 /**
@@ -677,7 +743,7 @@ public static <T> FuncTaskConfigurer switchWhenOrElse(
677743 * switchWhenOrElse(".approved == true", "sendEmail", FlowDirectiveEnum.END)
678744 * </pre>
679745 *
680- * The JQ expression is evaluated against the task input at runtime.
746+ * <p> The JQ expression is evaluated against the task input at runtime.
681747 */
682748 public static FuncTaskConfigurer switchWhenOrElse (
683749 String jqExpression , String thenTask , FlowDirectiveEnum otherwise ) {
@@ -698,7 +764,7 @@ public static FuncTaskConfigurer switchWhenOrElse(
698764 * switchWhenOrElse(".score >= 80", "pass", "fail")
699765 * </pre>
700766 *
701- * The JQ expression is evaluated against the task input at runtime.
767+ * <p> The JQ expression is evaluated against the task input at runtime.
702768 */
703769 public static FuncTaskConfigurer switchWhenOrElse (
704770 String jqExpression , String thenTask , String otherwiseTask ) {
0 commit comments