mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 08:01:38 +00:00
fix: optimize flow lock generation and add rt.d.ts guidance for TS resource types (#8295)
Instruct AI to pass specific flow folder path to `wmill flow generate-locks` instead of running it on all flows. Also add guidance for TypeScript language files to check `rt.d.ts` for available resource types before using them. Re-ran generate.py to propagate changes to all auto-generated files. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+2836
-2503
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
||||
|
||||
The Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.
|
||||
|
||||
Current version: 1.642.0
|
||||
Current version: 1.651.1
|
||||
|
||||
## Global Options
|
||||
|
||||
@@ -60,6 +60,15 @@ Launch a dev server that will spawn a webserver with HMR
|
||||
**Options:**
|
||||
- `--includes <pattern...:string>` - Filter paths givena glob pattern or path
|
||||
|
||||
### docs
|
||||
|
||||
Search Windmill documentation. Requires Enterprise Edition.
|
||||
|
||||
**Arguments:** `<query:string>`
|
||||
|
||||
**Options:**
|
||||
- `--json` - Output results as JSON.
|
||||
|
||||
### flow
|
||||
|
||||
flow related commands
|
||||
@@ -108,7 +117,7 @@ folder related commands
|
||||
- `--json` - Output as JSON (for piping to jq)
|
||||
- `folder new <name:string>` - create a new folder locally
|
||||
- `--summary <summary:string>` - folder summary
|
||||
- `folder push <name:string>` - push a local folder to the remote by name. This overrides any remote versions.
|
||||
- `folder push <name:string>` - push a local folder to the remote by name. This overrides any remote versions.
|
||||
- `folder add-missing` - create default folder.meta.yaml for all subdirectories of f/ that are missing one
|
||||
- `-y, --yes` - skip confirmation prompt
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -17,6 +17,14 @@ properties:
|
||||
items:
|
||||
type: string
|
||||
description: Array of Kafka topic names to subscribe to
|
||||
filters:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
value: {}
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
@@ -64,3 +72,4 @@ required:
|
||||
- kafka_resource_path
|
||||
- group_id
|
||||
- topics
|
||||
- filters
|
||||
|
||||
@@ -122,6 +122,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
```typescript
|
||||
@@ -234,6 +236,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
**No imports allowed.** Use the globally available `fetch` function:
|
||||
@@ -387,6 +391,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
```typescript
|
||||
@@ -729,6 +735,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
**No imports allowed.** Use the globally available `fetch` function:
|
||||
@@ -1118,6 +1126,36 @@ SELECT * FROM users WHERE name = ? AND age > ?;
|
||||
|
||||
Import: import * as wmill from 'windmill-client'
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Initialize the Windmill client with authentication token and base URL
|
||||
* @param token - Authentication token (defaults to WM_TOKEN env variable)
|
||||
@@ -1212,13 +1250,6 @@ async getResult(jobId: string): Promise<any>
|
||||
*/
|
||||
async getResultMaybe(jobId: string): Promise<any>
|
||||
|
||||
/**
|
||||
* Wrap a function to execute as a Windmill task within a flow context
|
||||
* @param f - Function to wrap as a task
|
||||
* @returns Async wrapper function that executes as a Windmill job
|
||||
*/
|
||||
task<P, T>(f: (_: P) => T): (_: P) => Promise<T>
|
||||
|
||||
/**
|
||||
* @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
|
||||
*/
|
||||
@@ -1490,6 +1521,8 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* @param {string} [options.approver] - Optional user ID or name of the approver for the request.
|
||||
* @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
|
||||
* @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
|
||||
* @param {string} [options.resumeButtonText] - Optional text for the resume button.
|
||||
* @param {string} [options.cancelButtonText] - Optional text for the cancel button.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
|
||||
*
|
||||
@@ -1505,12 +1538,14 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* approver: "approver123",
|
||||
* defaultArgsJson: { key1: "value1", key2: 42 },
|
||||
* dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
|
||||
* resumeButtonText: "Resume",
|
||||
* cancelButtonText: "Cancel",
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* **Note:** This function requires execution within a Windmill flow or flow preview.
|
||||
*/
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, }: SlackApprovalOptions): Promise<void>
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
|
||||
|
||||
/**
|
||||
* Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
|
||||
@@ -1554,35 +1589,65 @@ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver
|
||||
*/
|
||||
parseS3Object(s3Object: S3Object): S3ObjectRecord
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
setWorkflowCtx(ctx: WorkflowCtx | null): void
|
||||
|
||||
async sleep(seconds: number): Promise<void>
|
||||
|
||||
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* Create a task that dispatches to a separate Windmill script.
|
||||
*
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
* const extract = taskScript("f/data/extract");
|
||||
* // inside workflow: await extract({ url: "https://..." })
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Create a task that dispatches to a separate Windmill flow.
|
||||
*
|
||||
* @example
|
||||
* const pipeline = taskFlow("f/etl/pipeline");
|
||||
* // inside workflow: await pipeline({ input: data })
|
||||
*/
|
||||
taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Mark an async function as a workflow-as-code entry point.
|
||||
*
|
||||
* The function must be **deterministic**: given the same inputs it must call
|
||||
* tasks in the same order on every replay. Branching on task results is fine
|
||||
* (results are replayed from checkpoint), but branching on external state
|
||||
* (current time, random values, external API calls) must use `step()` to
|
||||
* checkpoint the value so replays see the same result.
|
||||
*/
|
||||
workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
||||
|
||||
/**
|
||||
* Suspend the workflow and wait for an external approval.
|
||||
*
|
||||
* Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage
|
||||
* URLs before calling this function.
|
||||
*
|
||||
* @example
|
||||
* const urls = await step("urls", () => getResumeUrls());
|
||||
* await step("notify", () => sendEmail(urls.approvalPage));
|
||||
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
||||
*/
|
||||
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
||||
|
||||
/**
|
||||
* Process items in parallel with optional concurrency control.
|
||||
*
|
||||
* Each item is processed by calling `fn(item)`, which should be a task().
|
||||
* Items are dispatched in batches of `concurrency` (default: all at once).
|
||||
*
|
||||
* @example
|
||||
* const process = task(async (item: string) => { ... });
|
||||
* const results = await parallel(items, process, { concurrency: 5 });
|
||||
*/
|
||||
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
||||
|
||||
|
||||
# Python SDK (wmill)
|
||||
@@ -1875,6 +1940,16 @@ def load_s3_file_reader(s3object: S3Object | str, s3_resource_path: str | None)
|
||||
# '''
|
||||
def write_s3_file(s3object: S3Object | str | None, file_content: BufferedReader | bytes, s3_resource_path: str | None, content_type: str | None = None, content_disposition: str | None = None) -> S3Object
|
||||
|
||||
# Permanently delete a file from the workspace S3 bucket.
|
||||
#
|
||||
# '''python
|
||||
# from wmill import S3Object
|
||||
#
|
||||
# s3_obj = S3Object(s3="/path/to/my_file.txt")
|
||||
# client.delete_s3_object(s3_obj)
|
||||
# '''
|
||||
def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = None) -> None
|
||||
|
||||
# Sign S3 objects for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
@@ -2093,18 +2168,6 @@ def boto3_connection_settings(s3_resource_path: str = '') -> Boto3ConnectionSett
|
||||
# State path string
|
||||
def get_state_path() -> str
|
||||
|
||||
# Decorator to mark a function as a workflow task.
|
||||
#
|
||||
# When executed inside a Windmill job, the decorated function runs as a
|
||||
# separate workflow step. Outside Windmill, it executes normally.
|
||||
#
|
||||
# Args:
|
||||
# tag: Optional worker tag for execution
|
||||
#
|
||||
# Returns:
|
||||
# Decorated function
|
||||
def task(*args, **kwargs)
|
||||
|
||||
# Parse resource syntax from string.
|
||||
def parse_resource_syntax(s: str) -> Optional[str]
|
||||
|
||||
@@ -2168,3 +2231,93 @@ def infer_sql_type(value) -> str
|
||||
|
||||
def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
|
||||
|
||||
# Decorator that marks a function as a workflow task.
|
||||
#
|
||||
# Works in both WAC v1 (sync, HTTP-based dispatch) and WAC v2
|
||||
# (async, checkpoint/replay) modes:
|
||||
#
|
||||
# - **v2 (inside @workflow)**: dispatches as a checkpoint step.
|
||||
# - **v1 (WM_JOB_ID set, no @workflow)**: dispatches via HTTP API.
|
||||
# - **Standalone**: executes the function body directly.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# @task
|
||||
# async def extract_data(url: str): ...
|
||||
#
|
||||
# @task(path="f/external_script", timeout=600, tag="gpu")
|
||||
# async def run_external(x: int): ...
|
||||
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Create a task that dispatches to a separate Windmill script.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# extract = task_script("f/data/extract", timeout=600)
|
||||
#
|
||||
# @workflow
|
||||
# async def main():
|
||||
# data = await extract(url="https://...")
|
||||
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Create a task that dispatches to a separate Windmill flow.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# pipeline = task_flow("f/etl/pipeline", priority=10)
|
||||
#
|
||||
# @workflow
|
||||
# async def main():
|
||||
# result = await pipeline(input=data)
|
||||
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Decorator marking an async function as a workflow-as-code entry point.
|
||||
#
|
||||
# The function must be **deterministic**: given the same inputs it must call
|
||||
# tasks in the same order on every replay. Branching on task results is fine
|
||||
# (results are replayed from checkpoint), but branching on external state
|
||||
# (current time, random values, external API calls) must use ``step()`` to
|
||||
# checkpoint the value so replays see the same result.
|
||||
def workflow(func)
|
||||
|
||||
# Execute ``fn`` inline and checkpoint the result.
|
||||
#
|
||||
# On replay the cached value is returned without re-executing ``fn``.
|
||||
# Use for lightweight deterministic operations (timestamps, random IDs,
|
||||
# config reads) that should not incur the overhead of a child job.
|
||||
async def step(name: str, fn)
|
||||
|
||||
# Server-side sleep — suspend the workflow for the given duration without holding a worker.
|
||||
#
|
||||
# Inside a @workflow, the parent job suspends and auto-resumes after ``seconds``.
|
||||
# Outside a workflow, falls back to ``asyncio.sleep``.
|
||||
async def sleep(seconds: int)
|
||||
|
||||
# Suspend the workflow and wait for an external approval.
|
||||
#
|
||||
# Use ``get_resume_urls()`` (wrapped in ``step()``) to obtain
|
||||
# resume/cancel/approval URLs before calling this function.
|
||||
#
|
||||
# Returns a dict with ``value`` (form data), ``approver``, and ``approved``.
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# urls = await step("urls", lambda: get_resume_urls())
|
||||
# await step("notify", lambda: send_email(urls["approvalPage"]))
|
||||
# result = await wait_for_approval(timeout=3600)
|
||||
async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> dict
|
||||
|
||||
# Process items in parallel with optional concurrency control.
|
||||
#
|
||||
# Each item is processed by calling ``fn(item)``, which should be a @task.
|
||||
# Items are dispatched in batches of ``concurrency`` (default: all at once).
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# @task
|
||||
# async def process(item: str):
|
||||
# ...
|
||||
#
|
||||
# results = await parallel(items, process, concurrency=5)
|
||||
async def parallel(items, fn, concurrency: Optional[int] = None)
|
||||
|
||||
|
||||
@@ -288,6 +288,16 @@ def load_s3_file_reader(s3object: S3Object | str, s3_resource_path: str | None)
|
||||
# '''
|
||||
def write_s3_file(s3object: S3Object | str | None, file_content: BufferedReader | bytes, s3_resource_path: str | None, content_type: str | None = None, content_disposition: str | None = None) -> S3Object
|
||||
|
||||
# Permanently delete a file from the workspace S3 bucket.
|
||||
#
|
||||
# '''python
|
||||
# from wmill import S3Object
|
||||
#
|
||||
# s3_obj = S3Object(s3="/path/to/my_file.txt")
|
||||
# client.delete_s3_object(s3_obj)
|
||||
# '''
|
||||
def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = None) -> None
|
||||
|
||||
# Sign S3 objects for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
@@ -506,18 +516,6 @@ def boto3_connection_settings(s3_resource_path: str = '') -> Boto3ConnectionSett
|
||||
# State path string
|
||||
def get_state_path() -> str
|
||||
|
||||
# Decorator to mark a function as a workflow task.
|
||||
#
|
||||
# When executed inside a Windmill job, the decorated function runs as a
|
||||
# separate workflow step. Outside Windmill, it executes normally.
|
||||
#
|
||||
# Args:
|
||||
# tag: Optional worker tag for execution
|
||||
#
|
||||
# Returns:
|
||||
# Decorated function
|
||||
def task(*args, **kwargs)
|
||||
|
||||
# Parse resource syntax from string.
|
||||
def parse_resource_syntax(s: str) -> Optional[str]
|
||||
|
||||
@@ -581,3 +579,93 @@ def infer_sql_type(value) -> str
|
||||
|
||||
def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
|
||||
|
||||
# Decorator that marks a function as a workflow task.
|
||||
#
|
||||
# Works in both WAC v1 (sync, HTTP-based dispatch) and WAC v2
|
||||
# (async, checkpoint/replay) modes:
|
||||
#
|
||||
# - **v2 (inside @workflow)**: dispatches as a checkpoint step.
|
||||
# - **v1 (WM_JOB_ID set, no @workflow)**: dispatches via HTTP API.
|
||||
# - **Standalone**: executes the function body directly.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# @task
|
||||
# async def extract_data(url: str): ...
|
||||
#
|
||||
# @task(path="f/external_script", timeout=600, tag="gpu")
|
||||
# async def run_external(x: int): ...
|
||||
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Create a task that dispatches to a separate Windmill script.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# extract = task_script("f/data/extract", timeout=600)
|
||||
#
|
||||
# @workflow
|
||||
# async def main():
|
||||
# data = await extract(url="https://...")
|
||||
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Create a task that dispatches to a separate Windmill flow.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# pipeline = task_flow("f/etl/pipeline", priority=10)
|
||||
#
|
||||
# @workflow
|
||||
# async def main():
|
||||
# result = await pipeline(input=data)
|
||||
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Decorator marking an async function as a workflow-as-code entry point.
|
||||
#
|
||||
# The function must be **deterministic**: given the same inputs it must call
|
||||
# tasks in the same order on every replay. Branching on task results is fine
|
||||
# (results are replayed from checkpoint), but branching on external state
|
||||
# (current time, random values, external API calls) must use ``step()`` to
|
||||
# checkpoint the value so replays see the same result.
|
||||
def workflow(func)
|
||||
|
||||
# Execute ``fn`` inline and checkpoint the result.
|
||||
#
|
||||
# On replay the cached value is returned without re-executing ``fn``.
|
||||
# Use for lightweight deterministic operations (timestamps, random IDs,
|
||||
# config reads) that should not incur the overhead of a child job.
|
||||
async def step(name: str, fn)
|
||||
|
||||
# Server-side sleep — suspend the workflow for the given duration without holding a worker.
|
||||
#
|
||||
# Inside a @workflow, the parent job suspends and auto-resumes after ``seconds``.
|
||||
# Outside a workflow, falls back to ``asyncio.sleep``.
|
||||
async def sleep(seconds: int)
|
||||
|
||||
# Suspend the workflow and wait for an external approval.
|
||||
#
|
||||
# Use ``get_resume_urls()`` (wrapped in ``step()``) to obtain
|
||||
# resume/cancel/approval URLs before calling this function.
|
||||
#
|
||||
# Returns a dict with ``value`` (form data), ``approver``, and ``approved``.
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# urls = await step("urls", lambda: get_resume_urls())
|
||||
# await step("notify", lambda: send_email(urls["approvalPage"]))
|
||||
# result = await wait_for_approval(timeout=3600)
|
||||
async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> dict
|
||||
|
||||
# Process items in parallel with optional concurrency control.
|
||||
#
|
||||
# Each item is processed by calling ``fn(item)``, which should be a @task.
|
||||
# Items are dispatched in batches of ``concurrency`` (default: all at once).
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# @task
|
||||
# async def process(item: str):
|
||||
# ...
|
||||
#
|
||||
# results = await parallel(items, process, concurrency=5)
|
||||
async def parallel(items, fn, concurrency: Optional[int] = None)
|
||||
|
||||
|
||||
@@ -2,6 +2,36 @@
|
||||
|
||||
Import: import * as wmill from 'windmill-client'
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Initialize the Windmill client with authentication token and base URL
|
||||
* @param token - Authentication token (defaults to WM_TOKEN env variable)
|
||||
@@ -96,13 +126,6 @@ async getResult(jobId: string): Promise<any>
|
||||
*/
|
||||
async getResultMaybe(jobId: string): Promise<any>
|
||||
|
||||
/**
|
||||
* Wrap a function to execute as a Windmill task within a flow context
|
||||
* @param f - Function to wrap as a task
|
||||
* @returns Async wrapper function that executes as a Windmill job
|
||||
*/
|
||||
task<P, T>(f: (_: P) => T): (_: P) => Promise<T>
|
||||
|
||||
/**
|
||||
* @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
|
||||
*/
|
||||
@@ -374,6 +397,8 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* @param {string} [options.approver] - Optional user ID or name of the approver for the request.
|
||||
* @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
|
||||
* @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
|
||||
* @param {string} [options.resumeButtonText] - Optional text for the resume button.
|
||||
* @param {string} [options.cancelButtonText] - Optional text for the cancel button.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
|
||||
*
|
||||
@@ -389,12 +414,14 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* approver: "approver123",
|
||||
* defaultArgsJson: { key1: "value1", key2: 42 },
|
||||
* dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
|
||||
* resumeButtonText: "Resume",
|
||||
* cancelButtonText: "Cancel",
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* **Note:** This function requires execution within a Windmill flow or flow preview.
|
||||
*/
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, }: SlackApprovalOptions): Promise<void>
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
|
||||
|
||||
/**
|
||||
* Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
|
||||
@@ -438,32 +465,62 @@ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver
|
||||
*/
|
||||
parseS3Object(s3Object: S3Object): S3ObjectRecord
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
setWorkflowCtx(ctx: WorkflowCtx | null): void
|
||||
|
||||
async sleep(seconds: number): Promise<void>
|
||||
|
||||
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* Create a task that dispatches to a separate Windmill script.
|
||||
*
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
* const extract = taskScript("f/data/extract");
|
||||
* // inside workflow: await extract({ url: "https://..." })
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Create a task that dispatches to a separate Windmill flow.
|
||||
*
|
||||
* @example
|
||||
* const pipeline = taskFlow("f/etl/pipeline");
|
||||
* // inside workflow: await pipeline({ input: data })
|
||||
*/
|
||||
taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Mark an async function as a workflow-as-code entry point.
|
||||
*
|
||||
* The function must be **deterministic**: given the same inputs it must call
|
||||
* tasks in the same order on every replay. Branching on task results is fine
|
||||
* (results are replayed from checkpoint), but branching on external state
|
||||
* (current time, random values, external API calls) must use `step()` to
|
||||
* checkpoint the value so replays see the same result.
|
||||
*/
|
||||
workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
||||
|
||||
/**
|
||||
* Suspend the workflow and wait for an external approval.
|
||||
*
|
||||
* Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage
|
||||
* URLs before calling this function.
|
||||
*
|
||||
* @example
|
||||
* const urls = await step("urls", () => getResumeUrls());
|
||||
* await step("notify", () => sendEmail(urls.approvalPage));
|
||||
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
||||
*/
|
||||
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
||||
|
||||
/**
|
||||
* Process items in parallel with optional concurrency control.
|
||||
*
|
||||
* Each item is processed by calling `fn(item)`, which should be a task().
|
||||
* Items are dispatched in batches of `concurrency` (default: all at once).
|
||||
*
|
||||
* @example
|
||||
* const process = task(async (item: string) => { ... });
|
||||
* const results = await parallel(items, process, { concurrency: 5 });
|
||||
*/
|
||||
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
||||
|
||||
@@ -7,7 +7,7 @@ description: MUST use when using the CLI.
|
||||
|
||||
The Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.
|
||||
|
||||
Current version: 1.642.0
|
||||
Current version: 1.651.1
|
||||
|
||||
## Global Options
|
||||
|
||||
@@ -65,6 +65,15 @@ Launch a dev server that will spawn a webserver with HMR
|
||||
**Options:**
|
||||
- `--includes <pattern...:string>` - Filter paths givena glob pattern or path
|
||||
|
||||
### docs
|
||||
|
||||
Search Windmill documentation. Requires Enterprise Edition.
|
||||
|
||||
**Arguments:** `<query:string>`
|
||||
|
||||
**Options:**
|
||||
- `--json` - Output results as JSON.
|
||||
|
||||
### flow
|
||||
|
||||
flow related commands
|
||||
@@ -113,7 +122,7 @@ folder related commands
|
||||
- `--json` - Output as JSON (for piping to jq)
|
||||
- `folder new <name:string>` - create a new folder locally
|
||||
- `--summary <summary:string>` - folder summary
|
||||
- `folder push <name:string>` - push a local folder to the remote by name. This overrides any remote versions.
|
||||
- `folder push <name:string>` - push a local folder to the remote by name. This overrides any remote versions.
|
||||
- `folder add-missing` - create default folder.meta.yaml for all subdirectories of f/ that are missing one
|
||||
- `-y, --yes` - skip confirmation prompt
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -42,6 +42,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
```typescript
|
||||
@@ -127,6 +129,36 @@ const result: S3Object = await wmill.writeS3File(
|
||||
|
||||
Import: import * as wmill from 'windmill-client'
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Initialize the Windmill client with authentication token and base URL
|
||||
* @param token - Authentication token (defaults to WM_TOKEN env variable)
|
||||
@@ -221,13 +253,6 @@ async getResult(jobId: string): Promise<any>
|
||||
*/
|
||||
async getResultMaybe(jobId: string): Promise<any>
|
||||
|
||||
/**
|
||||
* Wrap a function to execute as a Windmill task within a flow context
|
||||
* @param f - Function to wrap as a task
|
||||
* @returns Async wrapper function that executes as a Windmill job
|
||||
*/
|
||||
task<P, T>(f: (_: P) => T): (_: P) => Promise<T>
|
||||
|
||||
/**
|
||||
* @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
|
||||
*/
|
||||
@@ -499,6 +524,8 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* @param {string} [options.approver] - Optional user ID or name of the approver for the request.
|
||||
* @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
|
||||
* @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
|
||||
* @param {string} [options.resumeButtonText] - Optional text for the resume button.
|
||||
* @param {string} [options.cancelButtonText] - Optional text for the cancel button.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
|
||||
*
|
||||
@@ -514,12 +541,14 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* approver: "approver123",
|
||||
* defaultArgsJson: { key1: "value1", key2: 42 },
|
||||
* dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
|
||||
* resumeButtonText: "Resume",
|
||||
* cancelButtonText: "Cancel",
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* **Note:** This function requires execution within a Windmill flow or flow preview.
|
||||
*/
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, }: SlackApprovalOptions): Promise<void>
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
|
||||
|
||||
/**
|
||||
* Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
|
||||
@@ -563,32 +592,62 @@ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver
|
||||
*/
|
||||
parseS3Object(s3Object: S3Object): S3ObjectRecord
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
setWorkflowCtx(ctx: WorkflowCtx | null): void
|
||||
|
||||
async sleep(seconds: number): Promise<void>
|
||||
|
||||
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* Create a task that dispatches to a separate Windmill script.
|
||||
*
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
* const extract = taskScript("f/data/extract");
|
||||
* // inside workflow: await extract({ url: "https://..." })
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Create a task that dispatches to a separate Windmill flow.
|
||||
*
|
||||
* @example
|
||||
* const pipeline = taskFlow("f/etl/pipeline");
|
||||
* // inside workflow: await pipeline({ input: data })
|
||||
*/
|
||||
taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Mark an async function as a workflow-as-code entry point.
|
||||
*
|
||||
* The function must be **deterministic**: given the same inputs it must call
|
||||
* tasks in the same order on every replay. Branching on task results is fine
|
||||
* (results are replayed from checkpoint), but branching on external state
|
||||
* (current time, random values, external API calls) must use `step()` to
|
||||
* checkpoint the value so replays see the same result.
|
||||
*/
|
||||
workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
||||
|
||||
/**
|
||||
* Suspend the workflow and wait for an external approval.
|
||||
*
|
||||
* Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage
|
||||
* URLs before calling this function.
|
||||
*
|
||||
* @example
|
||||
* const urls = await step("urls", () => getResumeUrls());
|
||||
* await step("notify", () => sendEmail(urls.approvalPage));
|
||||
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
||||
*/
|
||||
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
||||
|
||||
/**
|
||||
* Process items in parallel with optional concurrency control.
|
||||
*
|
||||
* Each item is processed by calling `fn(item)`, which should be a task().
|
||||
* Items are dispatched in batches of `concurrency` (default: all at once).
|
||||
*
|
||||
* @example
|
||||
* const process = task(async (item: string) => { ... });
|
||||
* const results = await parallel(items, process, { concurrency: 5 });
|
||||
*/
|
||||
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
||||
|
||||
@@ -42,6 +42,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
**No imports allowed.** Use the globally available `fetch` function:
|
||||
@@ -125,6 +127,36 @@ const result: S3Object = await wmill.writeS3File(
|
||||
|
||||
Import: import * as wmill from 'windmill-client'
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Initialize the Windmill client with authentication token and base URL
|
||||
* @param token - Authentication token (defaults to WM_TOKEN env variable)
|
||||
@@ -219,13 +251,6 @@ async getResult(jobId: string): Promise<any>
|
||||
*/
|
||||
async getResultMaybe(jobId: string): Promise<any>
|
||||
|
||||
/**
|
||||
* Wrap a function to execute as a Windmill task within a flow context
|
||||
* @param f - Function to wrap as a task
|
||||
* @returns Async wrapper function that executes as a Windmill job
|
||||
*/
|
||||
task<P, T>(f: (_: P) => T): (_: P) => Promise<T>
|
||||
|
||||
/**
|
||||
* @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
|
||||
*/
|
||||
@@ -497,6 +522,8 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* @param {string} [options.approver] - Optional user ID or name of the approver for the request.
|
||||
* @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
|
||||
* @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
|
||||
* @param {string} [options.resumeButtonText] - Optional text for the resume button.
|
||||
* @param {string} [options.cancelButtonText] - Optional text for the cancel button.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
|
||||
*
|
||||
@@ -512,12 +539,14 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* approver: "approver123",
|
||||
* defaultArgsJson: { key1: "value1", key2: 42 },
|
||||
* dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
|
||||
* resumeButtonText: "Resume",
|
||||
* cancelButtonText: "Cancel",
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* **Note:** This function requires execution within a Windmill flow or flow preview.
|
||||
*/
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, }: SlackApprovalOptions): Promise<void>
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
|
||||
|
||||
/**
|
||||
* Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
|
||||
@@ -561,32 +590,62 @@ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver
|
||||
*/
|
||||
parseS3Object(s3Object: S3Object): S3ObjectRecord
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
setWorkflowCtx(ctx: WorkflowCtx | null): void
|
||||
|
||||
async sleep(seconds: number): Promise<void>
|
||||
|
||||
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* Create a task that dispatches to a separate Windmill script.
|
||||
*
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
* const extract = taskScript("f/data/extract");
|
||||
* // inside workflow: await extract({ url: "https://..." })
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Create a task that dispatches to a separate Windmill flow.
|
||||
*
|
||||
* @example
|
||||
* const pipeline = taskFlow("f/etl/pipeline");
|
||||
* // inside workflow: await pipeline({ input: data })
|
||||
*/
|
||||
taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Mark an async function as a workflow-as-code entry point.
|
||||
*
|
||||
* The function must be **deterministic**: given the same inputs it must call
|
||||
* tasks in the same order on every replay. Branching on task results is fine
|
||||
* (results are replayed from checkpoint), but branching on external state
|
||||
* (current time, random values, external API calls) must use `step()` to
|
||||
* checkpoint the value so replays see the same result.
|
||||
*/
|
||||
workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
||||
|
||||
/**
|
||||
* Suspend the workflow and wait for an external approval.
|
||||
*
|
||||
* Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage
|
||||
* URLs before calling this function.
|
||||
*
|
||||
* @example
|
||||
* const urls = await step("urls", () => getResumeUrls());
|
||||
* await step("notify", () => sendEmail(urls.approvalPage));
|
||||
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
||||
*/
|
||||
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
||||
|
||||
/**
|
||||
* Process items in parallel with optional concurrency control.
|
||||
*
|
||||
* Each item is processed by calling `fn(item)`, which should be a task().
|
||||
* Items are dispatched in batches of `concurrency` (default: all at once).
|
||||
*
|
||||
* @example
|
||||
* const process = task(async (item: string) => { ... });
|
||||
* const results = await parallel(items, process, { concurrency: 5 });
|
||||
*/
|
||||
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
||||
|
||||
@@ -42,6 +42,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
```typescript
|
||||
@@ -131,6 +133,36 @@ const result: S3Object = await wmill.writeS3File(
|
||||
|
||||
Import: import * as wmill from 'windmill-client'
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Initialize the Windmill client with authentication token and base URL
|
||||
* @param token - Authentication token (defaults to WM_TOKEN env variable)
|
||||
@@ -225,13 +257,6 @@ async getResult(jobId: string): Promise<any>
|
||||
*/
|
||||
async getResultMaybe(jobId: string): Promise<any>
|
||||
|
||||
/**
|
||||
* Wrap a function to execute as a Windmill task within a flow context
|
||||
* @param f - Function to wrap as a task
|
||||
* @returns Async wrapper function that executes as a Windmill job
|
||||
*/
|
||||
task<P, T>(f: (_: P) => T): (_: P) => Promise<T>
|
||||
|
||||
/**
|
||||
* @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
|
||||
*/
|
||||
@@ -503,6 +528,8 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* @param {string} [options.approver] - Optional user ID or name of the approver for the request.
|
||||
* @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
|
||||
* @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
|
||||
* @param {string} [options.resumeButtonText] - Optional text for the resume button.
|
||||
* @param {string} [options.cancelButtonText] - Optional text for the cancel button.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
|
||||
*
|
||||
@@ -518,12 +545,14 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* approver: "approver123",
|
||||
* defaultArgsJson: { key1: "value1", key2: 42 },
|
||||
* dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
|
||||
* resumeButtonText: "Resume",
|
||||
* cancelButtonText: "Cancel",
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* **Note:** This function requires execution within a Windmill flow or flow preview.
|
||||
*/
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, }: SlackApprovalOptions): Promise<void>
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
|
||||
|
||||
/**
|
||||
* Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
|
||||
@@ -567,32 +596,62 @@ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver
|
||||
*/
|
||||
parseS3Object(s3Object: S3Object): S3ObjectRecord
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
setWorkflowCtx(ctx: WorkflowCtx | null): void
|
||||
|
||||
async sleep(seconds: number): Promise<void>
|
||||
|
||||
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* Create a task that dispatches to a separate Windmill script.
|
||||
*
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
* const extract = taskScript("f/data/extract");
|
||||
* // inside workflow: await extract({ url: "https://..." })
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Create a task that dispatches to a separate Windmill flow.
|
||||
*
|
||||
* @example
|
||||
* const pipeline = taskFlow("f/etl/pipeline");
|
||||
* // inside workflow: await pipeline({ input: data })
|
||||
*/
|
||||
taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Mark an async function as a workflow-as-code entry point.
|
||||
*
|
||||
* The function must be **deterministic**: given the same inputs it must call
|
||||
* tasks in the same order on every replay. Branching on task results is fine
|
||||
* (results are replayed from checkpoint), but branching on external state
|
||||
* (current time, random values, external API calls) must use `step()` to
|
||||
* checkpoint the value so replays see the same result.
|
||||
*/
|
||||
workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
||||
|
||||
/**
|
||||
* Suspend the workflow and wait for an external approval.
|
||||
*
|
||||
* Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage
|
||||
* URLs before calling this function.
|
||||
*
|
||||
* @example
|
||||
* const urls = await step("urls", () => getResumeUrls());
|
||||
* await step("notify", () => sendEmail(urls.approvalPage));
|
||||
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
||||
*/
|
||||
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
||||
|
||||
/**
|
||||
* Process items in parallel with optional concurrency control.
|
||||
*
|
||||
* Each item is processed by calling `fn(item)`, which should be a task().
|
||||
* Items are dispatched in batches of `concurrency` (default: all at once).
|
||||
*
|
||||
* @example
|
||||
* const process = task(async (item: string) => { ... });
|
||||
* const results = await parallel(items, process, { concurrency: 5 });
|
||||
*/
|
||||
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
||||
|
||||
@@ -42,6 +42,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
**No imports allowed.** Use the globally available `fetch` function:
|
||||
@@ -92,6 +94,36 @@ export async function preprocessor(event: Event) {
|
||||
|
||||
Import: import * as wmill from 'windmill-client'
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
|
||||
/**
|
||||
* Initialize the Windmill client with authentication token and base URL
|
||||
* @param token - Authentication token (defaults to WM_TOKEN env variable)
|
||||
@@ -186,13 +218,6 @@ async getResult(jobId: string): Promise<any>
|
||||
*/
|
||||
async getResultMaybe(jobId: string): Promise<any>
|
||||
|
||||
/**
|
||||
* Wrap a function to execute as a Windmill task within a flow context
|
||||
* @param f - Function to wrap as a task
|
||||
* @returns Async wrapper function that executes as a Windmill job
|
||||
*/
|
||||
task<P, T>(f: (_: P) => T): (_: P) => Promise<T>
|
||||
|
||||
/**
|
||||
* @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
|
||||
*/
|
||||
@@ -464,6 +489,8 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* @param {string} [options.approver] - Optional user ID or name of the approver for the request.
|
||||
* @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
|
||||
* @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
|
||||
* @param {string} [options.resumeButtonText] - Optional text for the resume button.
|
||||
* @param {string} [options.cancelButtonText] - Optional text for the cancel button.
|
||||
*
|
||||
* @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
|
||||
*
|
||||
@@ -479,12 +506,14 @@ async usernameToEmail(username: string): Promise<string>
|
||||
* approver: "approver123",
|
||||
* defaultArgsJson: { key1: "value1", key2: 42 },
|
||||
* dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
|
||||
* resumeButtonText: "Resume",
|
||||
* cancelButtonText: "Cancel",
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* **Note:** This function requires execution within a Windmill flow or flow preview.
|
||||
*/
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, }: SlackApprovalOptions): Promise<void>
|
||||
async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
|
||||
|
||||
/**
|
||||
* Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
|
||||
@@ -528,32 +557,62 @@ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver
|
||||
*/
|
||||
parseS3Object(s3Object: S3Object): S3ObjectRecord
|
||||
|
||||
/**
|
||||
* Create a SQL template function for PostgreSQL/datatable queries
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}::int
|
||||
* `.fetch()
|
||||
*/
|
||||
datatable(name: string = "main"): DatatableSqlTemplateFunction
|
||||
setWorkflowCtx(ctx: WorkflowCtx | null): void
|
||||
|
||||
async sleep(seconds: number): Promise<void>
|
||||
|
||||
async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
||||
|
||||
/**
|
||||
* Create a SQL template function for DuckDB/ducklake queries
|
||||
* @param name - DuckDB database name (default: "main")
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* Create a task that dispatches to a separate Windmill script.
|
||||
*
|
||||
* @example
|
||||
* let sql = wmill.ducklake()
|
||||
* let name = 'Robin'
|
||||
* let age = 21
|
||||
* await sql`
|
||||
* SELECT * FROM friends
|
||||
* WHERE name = ${name} AND age = ${age}
|
||||
* `.fetch()
|
||||
* const extract = taskScript("f/data/extract");
|
||||
* // inside workflow: await extract({ url: "https://..." })
|
||||
*/
|
||||
ducklake(name: string = "main"): SqlTemplateFunction
|
||||
taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Create a task that dispatches to a separate Windmill flow.
|
||||
*
|
||||
* @example
|
||||
* const pipeline = taskFlow("f/etl/pipeline");
|
||||
* // inside workflow: await pipeline({ input: data })
|
||||
*/
|
||||
taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
||||
|
||||
/**
|
||||
* Mark an async function as a workflow-as-code entry point.
|
||||
*
|
||||
* The function must be **deterministic**: given the same inputs it must call
|
||||
* tasks in the same order on every replay. Branching on task results is fine
|
||||
* (results are replayed from checkpoint), but branching on external state
|
||||
* (current time, random values, external API calls) must use `step()` to
|
||||
* checkpoint the value so replays see the same result.
|
||||
*/
|
||||
workflow<T>(fn: (...args: any[]) => Promise<T>): void
|
||||
|
||||
/**
|
||||
* Suspend the workflow and wait for an external approval.
|
||||
*
|
||||
* Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage
|
||||
* URLs before calling this function.
|
||||
*
|
||||
* @example
|
||||
* const urls = await step("urls", () => getResumeUrls());
|
||||
* await step("notify", () => sendEmail(urls.approvalPage));
|
||||
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
||||
*/
|
||||
waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
||||
|
||||
/**
|
||||
* Process items in parallel with optional concurrency control.
|
||||
*
|
||||
* Each item is processed by calling `fn(item)`, which should be a task().
|
||||
* Items are dispatched in batches of `concurrency` (default: all at once).
|
||||
*
|
||||
* @example
|
||||
* const process = task(async (item: string) => { ... });
|
||||
* const results = await parallel(items, process, { concurrency: 5 });
|
||||
*/
|
||||
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
||||
|
||||
@@ -421,6 +421,16 @@ def load_s3_file_reader(s3object: S3Object | str, s3_resource_path: str | None)
|
||||
# '''
|
||||
def write_s3_file(s3object: S3Object | str | None, file_content: BufferedReader | bytes, s3_resource_path: str | None, content_type: str | None = None, content_disposition: str | None = None) -> S3Object
|
||||
|
||||
# Permanently delete a file from the workspace S3 bucket.
|
||||
#
|
||||
# '''python
|
||||
# from wmill import S3Object
|
||||
#
|
||||
# s3_obj = S3Object(s3="/path/to/my_file.txt")
|
||||
# client.delete_s3_object(s3_obj)
|
||||
# '''
|
||||
def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = None) -> None
|
||||
|
||||
# Sign S3 objects for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
@@ -639,18 +649,6 @@ def boto3_connection_settings(s3_resource_path: str = '') -> Boto3ConnectionSett
|
||||
# State path string
|
||||
def get_state_path() -> str
|
||||
|
||||
# Decorator to mark a function as a workflow task.
|
||||
#
|
||||
# When executed inside a Windmill job, the decorated function runs as a
|
||||
# separate workflow step. Outside Windmill, it executes normally.
|
||||
#
|
||||
# Args:
|
||||
# tag: Optional worker tag for execution
|
||||
#
|
||||
# Returns:
|
||||
# Decorated function
|
||||
def task(*args, **kwargs)
|
||||
|
||||
# Parse resource syntax from string.
|
||||
def parse_resource_syntax(s: str) -> Optional[str]
|
||||
|
||||
@@ -714,3 +712,93 @@ def infer_sql_type(value) -> str
|
||||
|
||||
def parse_sql_client_name(name: str) -> tuple[str, Optional[str]]
|
||||
|
||||
# Decorator that marks a function as a workflow task.
|
||||
#
|
||||
# Works in both WAC v1 (sync, HTTP-based dispatch) and WAC v2
|
||||
# (async, checkpoint/replay) modes:
|
||||
#
|
||||
# - **v2 (inside @workflow)**: dispatches as a checkpoint step.
|
||||
# - **v1 (WM_JOB_ID set, no @workflow)**: dispatches via HTTP API.
|
||||
# - **Standalone**: executes the function body directly.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# @task
|
||||
# async def extract_data(url: str): ...
|
||||
#
|
||||
# @task(path="f/external_script", timeout=600, tag="gpu")
|
||||
# async def run_external(x: int): ...
|
||||
def task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Create a task that dispatches to a separate Windmill script.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# extract = task_script("f/data/extract", timeout=600)
|
||||
#
|
||||
# @workflow
|
||||
# async def main():
|
||||
# data = await extract(url="https://...")
|
||||
def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Create a task that dispatches to a separate Windmill flow.
|
||||
#
|
||||
# Usage::
|
||||
#
|
||||
# pipeline = task_flow("f/etl/pipeline", priority=10)
|
||||
#
|
||||
# @workflow
|
||||
# async def main():
|
||||
# result = await pipeline(input=data)
|
||||
def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
|
||||
|
||||
# Decorator marking an async function as a workflow-as-code entry point.
|
||||
#
|
||||
# The function must be **deterministic**: given the same inputs it must call
|
||||
# tasks in the same order on every replay. Branching on task results is fine
|
||||
# (results are replayed from checkpoint), but branching on external state
|
||||
# (current time, random values, external API calls) must use ``step()`` to
|
||||
# checkpoint the value so replays see the same result.
|
||||
def workflow(func)
|
||||
|
||||
# Execute ``fn`` inline and checkpoint the result.
|
||||
#
|
||||
# On replay the cached value is returned without re-executing ``fn``.
|
||||
# Use for lightweight deterministic operations (timestamps, random IDs,
|
||||
# config reads) that should not incur the overhead of a child job.
|
||||
async def step(name: str, fn)
|
||||
|
||||
# Server-side sleep — suspend the workflow for the given duration without holding a worker.
|
||||
#
|
||||
# Inside a @workflow, the parent job suspends and auto-resumes after ``seconds``.
|
||||
# Outside a workflow, falls back to ``asyncio.sleep``.
|
||||
async def sleep(seconds: int)
|
||||
|
||||
# Suspend the workflow and wait for an external approval.
|
||||
#
|
||||
# Use ``get_resume_urls()`` (wrapped in ``step()``) to obtain
|
||||
# resume/cancel/approval URLs before calling this function.
|
||||
#
|
||||
# Returns a dict with ``value`` (form data), ``approver``, and ``approved``.
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# urls = await step("urls", lambda: get_resume_urls())
|
||||
# await step("notify", lambda: send_email(urls["approvalPage"]))
|
||||
# result = await wait_for_approval(timeout=3600)
|
||||
async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> dict
|
||||
|
||||
# Process items in parallel with optional concurrency control.
|
||||
#
|
||||
# Each item is processed by calling ``fn(item)``, which should be a @task.
|
||||
# Items are dispatched in batches of ``concurrency`` (default: all at once).
|
||||
#
|
||||
# Example::
|
||||
#
|
||||
# @task
|
||||
# async def process(item: str):
|
||||
# ...
|
||||
#
|
||||
# results = await parallel(items, process, concurrency=5)
|
||||
async def parallel(items, fn, concurrency: Optional[int] = None)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Create a folder ending with `.flow` and add a YAML file with the flow definition.
|
||||
For rawscript modules, use `!inline path/to/script.ts` for the content key.
|
||||
After writing:
|
||||
- `wmill flow generate-locks --yes` - Generate lock files
|
||||
- `wmill flow generate-locks <path_to_flow_folder> --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow.flow --yes`)
|
||||
- `wmill sync push` - Deploy to Windmill
|
||||
|
||||
## OpenFlow Schema
|
||||
|
||||
@@ -29,6 +29,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -29,6 +29,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
**No imports allowed.** Use the globally available `fetch` function:
|
||||
|
||||
@@ -29,6 +29,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -29,6 +29,8 @@ export async function main(stripe: RT.Stripe) {
|
||||
|
||||
Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
|
||||
|
||||
Before using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.
|
||||
|
||||
## Imports
|
||||
|
||||
**No imports allowed.** Use the globally available `fetch` function:
|
||||
|
||||
Reference in New Issue
Block a user