Skip to content

Conversation

@ianmacartney
Copy link
Member

@ianmacartney ianmacartney commented Jan 6, 2026

Enables:

export const parentWorkflow = workflow
  .define({
    args: { prompt: v.string() },
    returns: v.number(),
  })
  .handler(async (ctx, args) => {

Fixes


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

The changes introduce a fluent API for workflow definitions, enabling .define().handler() chaining. Return value validation is now specified via a returns validator in the define call. A new workpoolOptions parameter allows configuring retry behavior at definition time. The underlying type system is refactored to support optional return validators.

Changes

Cohort / File(s) Summary
Workflow Definition Pattern
example/convex/example.ts, example/convex/nestedWorkflow.ts
Workflows refactored to use fluent .define(...).handler(...) chaining instead of inline handlers. returns validator added to define call for runtime validation. workpoolOptions configuration introduced in example.ts with retryActionsByDefault: true. Handler signature updated to remove explicit Promise return type.
Client API and Type System
src/client/index.ts
WorkflowManager.define method signature updated: removed Infer type usage, replaced with ReturnValueForOptionalValidator<ReturnsValidator>. Two new overloads added: one accepting workflow definition without handler returning an object with handler() setter; another accepting definitions with or without handlers, branching on handler presence. Runtime logic checks for "handler" in workflow to route to appropriate path.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Chaining workflows, fluent and clean,
Handlers now dance in a validation dream,
Retries configured, returns now blessed,
The API transforms—onwards to the test!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Allow defining handler after args & returns' directly and accurately describes the main change: introducing fluent syntax support for defining workflow handlers after specifying args and returns validators.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 6, 2026

Open in StackBlitz

npm i https://pkg.pr.new/get-convex/workflow/@convex-dev/workflow@187

commit: b5f6e67

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @example/convex/example.ts:
- Around line 20-26: The property and variable "farenheit" is misspelled; rename
it to "fahrenheit" everywhere: update the validator schema in the returns object
(v.object) changing the key "farenheit" to "fahrenheit", rename the
corresponding variable/identifier that computes/stores the value (the variable
currently named "farenheit"), and update the returned object to use the
"fahrenheit" property name so all three usages (validator, variable, and return)
match the corrected spelling.
🧹 Nitpick comments (1)
example/convex/nestedWorkflow.ts (1)

13-22: Unused variable length from child workflow.

The length variable from the child workflow (line 13) is logged but never used in the return value. Only stepResult from the mutation is returned. If the child workflow result is not needed beyond logging, consider removing the variable assignment for clarity.

🔎 Suggested simplification
-    const length = await ctx.runWorkflow(
+    await ctx.runWorkflow(
       internal.nestedWorkflow.childWorkflow,
       { foo: args.prompt },
     );
-    console.log("Length:", length);

Or if the logging is valuable, the current implementation is acceptable.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78ff9d1 and b5f6e67.

📒 Files selected for processing (3)
  • example/convex/example.ts
  • example/convex/nestedWorkflow.ts
  • src/client/index.ts
🧰 Additional context used
🧬 Code graph analysis (2)
example/convex/nestedWorkflow.ts (1)
example/convex/example.ts (1)
  • workflow (9-9)
example/convex/example.ts (2)
example/convex/nestedWorkflow.ts (1)
  • step (33-39)
src/component/schema.ts (1)
  • step (72-92)
🔇 Additional comments (7)
example/convex/nestedWorkflow.ts (2)

25-31: LGTM - Demonstrates backward compatibility.

The inline handler pattern is preserved, confirming that the new fluent API doesn't break existing workflow definitions.


33-39: LGTM - Clean mutation implementation.

The step mutation is straightforward and correctly returns a number as expected by the parent workflow.

src/client/index.ts (4)

20-20: LGTM - Required import for new validator types.

The Validator import is correctly added to support the returns validator in workflow definitions.


107-119: LGTM - Backward-compatible overload.

The first overload preserves the original API where the handler is provided directly in the workflow definition object.


120-142: LGTM - Fluent API overload.

The second overload enables the fluent .handler() chaining pattern. Type safety is preserved with proper generic constraints and return type matching.


143-171: LGTM - Clean branching implementation.

The implementation correctly handles both API patterns:

  • Direct handler: calls workflowMutation immediately
  • Fluent API: returns an object with a .handler() method that merges the handler and calls workflowMutation

Type safety is maintained through the overload signatures.

example/convex/example.ts (1)

28-59: LGTM - Well-structured workflow demonstration.

The handler correctly demonstrates:

  • Parallel step execution with Promise.all
  • Sequential step execution
  • Return value matching the validator schema
  • Proper use of the step context

The weather2 variable (line 32) appears to be for demonstrating parallel execution and consistency checking, which is appropriate for an example.

Comment on lines +20 to +26
returns: v.object({
name: v.string(),
celsius: v.number(),
farenheit: v.number(),
windSpeed: v.number(),
windGust: v.number(),
}),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Spelling: "farenheit" should be "fahrenheit".

The validator schema uses "farenheit" (line 23), but the correct spelling is "fahrenheit". This spelling is also used in the return statement (line 58) and the variable name (line 44), so the change would need to be applied consistently across all three locations.

🔎 Suggested fix
     returns: v.object({
       name: v.string(),
       celsius: v.number(),
-      farenheit: v.number(),
+      fahrenheit: v.number(),
       windSpeed: v.number(),
       windGust: v.number(),
     }),

Also update line 44:

-    const farenheit = (celsius * 9) / 5 + 32;
+    const fahrenheit = (celsius * 9) / 5 + 32;

And line 58:

-    return { name, celsius, farenheit, windSpeed, windGust };
+    return { name, celsius, fahrenheit, windSpeed, windGust };

And line 55:

-      out: { name, celsius, farenheit, windSpeed, windGust },
+      out: { name, celsius, fahrenheit, windSpeed, windGust },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
returns: v.object({
name: v.string(),
celsius: v.number(),
farenheit: v.number(),
windSpeed: v.number(),
windGust: v.number(),
}),
returns: v.object({
name: v.string(),
celsius: v.number(),
fahrenheit: v.number(),
windSpeed: v.number(),
windGust: v.number(),
}),
🤖 Prompt for AI Agents
In @example/convex/example.ts around lines 20 - 26, The property and variable
"farenheit" is misspelled; rename it to "fahrenheit" everywhere: update the
validator schema in the returns object (v.object) changing the key "farenheit"
to "fahrenheit", rename the corresponding variable/identifier that
computes/stores the value (the variable currently named "farenheit"), and update
the returned object to use the "fahrenheit" property name so all three usages
(validator, variable, and return) match the corrected spelling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants