windmill-cli 1.693.1 → 1.693.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/main.js +455 -3
- package/package.json +1 -1
package/esm/main.js
CHANGED
|
@@ -16710,7 +16710,7 @@ var init_OpenAPI = __esm(() => {
|
|
|
16710
16710
|
PASSWORD: undefined,
|
|
16711
16711
|
TOKEN: getEnv3("WM_TOKEN"),
|
|
16712
16712
|
USERNAME: undefined,
|
|
16713
|
-
VERSION: "1.693.
|
|
16713
|
+
VERSION: "1.693.3",
|
|
16714
16714
|
WITH_CREDENTIALS: true,
|
|
16715
16715
|
interceptors: {
|
|
16716
16716
|
request: new Interceptors,
|
|
@@ -17362,6 +17362,7 @@ __export(exports_services_gen, {
|
|
|
17362
17362
|
getQueuePosition: () => getQueuePosition,
|
|
17363
17363
|
getQueueMetrics: () => getQueueMetrics,
|
|
17364
17364
|
getQueueCount: () => getQueueCount,
|
|
17365
|
+
getPublicSettings: () => getPublicSettings,
|
|
17365
17366
|
getPublicSecretOfLatestVersionOfApp: () => getPublicSecretOfLatestVersionOfApp,
|
|
17366
17367
|
getPublicSecretOfApp: () => getPublicSecretOfApp,
|
|
17367
17368
|
getPublicResource: () => getPublicResource,
|
|
@@ -18675,6 +18676,14 @@ var backendVersion = () => {
|
|
|
18675
18676
|
workspace: data3.workspace
|
|
18676
18677
|
}
|
|
18677
18678
|
});
|
|
18679
|
+
}, getPublicSettings = (data3) => {
|
|
18680
|
+
return request(OpenAPI, {
|
|
18681
|
+
method: "GET",
|
|
18682
|
+
url: "/w/{workspace}/workspaces/get_public_settings",
|
|
18683
|
+
path: {
|
|
18684
|
+
workspace: data3.workspace
|
|
18685
|
+
}
|
|
18686
|
+
});
|
|
18678
18687
|
}, getSettings = (data3) => {
|
|
18679
18688
|
return request(OpenAPI, {
|
|
18680
18689
|
method: "GET",
|
|
@@ -24594,7 +24603,8 @@ var backendVersion = () => {
|
|
|
24594
24603
|
workspace: data3.workspace
|
|
24595
24604
|
},
|
|
24596
24605
|
query: {
|
|
24597
|
-
file_key: data3.fileKey
|
|
24606
|
+
file_key: data3.fileKey,
|
|
24607
|
+
marker_file: data3.markerFile
|
|
24598
24608
|
}
|
|
24599
24609
|
});
|
|
24600
24610
|
}, loadParquetPreview = (data3) => {
|
|
@@ -78252,6 +78262,7 @@ You are a helpful assistant that can help with Windmill scripts, flows, apps, an
|
|
|
78252
78262
|
## Script Writing Guide
|
|
78253
78263
|
|
|
78254
78264
|
You MUST use the \`write-script-<language>\` skill to write or modify scripts in the language specified by the user. Use bun by default.
|
|
78265
|
+
For Workflow-as-Code scripts, use the \`write-workflow-as-code\` skill.
|
|
78255
78266
|
|
|
78256
78267
|
## Flow Writing Guide
|
|
78257
78268
|
|
|
@@ -78331,6 +78342,7 @@ var SKILLS = [
|
|
|
78331
78342
|
{ name: "triggers", description: "MUST use when configuring triggers." },
|
|
78332
78343
|
{ name: "schedules", description: "MUST use when configuring schedules." },
|
|
78333
78344
|
{ name: "resources", description: "MUST use when managing resources." },
|
|
78345
|
+
{ name: "write-workflow-as-code", description: "MUST use when writing or modifying Windmill Workflow-as-Code scripts using workflow, task, step, sleep, approvals, taskScript, taskFlow, task_script, or task_flow." },
|
|
78334
78346
|
{ name: "cli-commands", description: "MUST use when using the CLI, including debugging job failures and inspecting run history via `wmill job`." },
|
|
78335
78347
|
{ name: "preview", description: "MUST use when opening the Windmill dev page / visual preview of a flow, script, or app. Triggers on words like preview, open, navigate to, visualize, see the flow/app/script, and after writing a flow/script/app for visual verification." }
|
|
78336
78348
|
];
|
|
@@ -84173,6 +84185,446 @@ wmill resource-type get postgresql
|
|
|
84173
84185
|
# Push resources (tell the user to run this, do NOT run it yourself)
|
|
84174
84186
|
wmill sync push
|
|
84175
84187
|
\`\`\`
|
|
84188
|
+
`,
|
|
84189
|
+
"write-workflow-as-code": `---
|
|
84190
|
+
name: write-workflow-as-code
|
|
84191
|
+
description: MUST use when writing or modifying Windmill Workflow-as-Code scripts using workflow, task, step, sleep, approvals, taskScript, taskFlow, task_script, or task_flow.
|
|
84192
|
+
---
|
|
84193
|
+
|
|
84194
|
+
## CLI Commands
|
|
84195
|
+
|
|
84196
|
+
Place scripts in a folder.
|
|
84197
|
+
|
|
84198
|
+
After writing, tell the user which command fits what they want to do:
|
|
84199
|
+
|
|
84200
|
+
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
|
84201
|
+
- \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
|
|
84202
|
+
- \`wmill generate-metadata\` — generate \`.script.yaml\` and \`.lock\` files for the script you modified.
|
|
84203
|
+
- \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
|
|
84204
|
+
|
|
84205
|
+
### Preview vs run — choose by intent, not habit
|
|
84206
|
+
|
|
84207
|
+
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
|
84208
|
+
|
|
84209
|
+
Only use \`script run\` when:
|
|
84210
|
+
- The user explicitly says "run the deployed version" / "run what's on the server".
|
|
84211
|
+
- There is no local script being edited (you're just invoking an existing script).
|
|
84212
|
+
|
|
84213
|
+
Only use \`sync push\` when:
|
|
84214
|
+
- The user explicitly asks to deploy, publish, push, or ship.
|
|
84215
|
+
- The preview has already validated the change and the user wants it in the workspace.
|
|
84216
|
+
|
|
84217
|
+
### After writing — offer to test, don't wait passively
|
|
84218
|
+
|
|
84219
|
+
If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
|
|
84220
|
+
|
|
84221
|
+
If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
|
|
84222
|
+
|
|
84223
|
+
\`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill sync push\` and \`wmill generate-metadata\` modify workspace state or local files — only run these when the user explicitly asks; otherwise tell them which to run.
|
|
84224
|
+
|
|
84225
|
+
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
|
84226
|
+
|
|
84227
|
+
Use \`wmill resource-type list --schema\` to discover available resource types.
|
|
84228
|
+
|
|
84229
|
+
Workflow-as-Code files use the normal script CLI workflow. There are no separate WAC deploy commands.
|
|
84230
|
+
|
|
84231
|
+
# Windmill Workflow-as-Code Writing Guide
|
|
84232
|
+
|
|
84233
|
+
## Scope
|
|
84234
|
+
|
|
84235
|
+
Use this guide when writing or modifying Windmill Workflow-as-Code (WAC) scripts.
|
|
84236
|
+
WAC is authored as a Windmill script and deployed with the normal script workflow. It is not an OpenFlow YAML flow.
|
|
84237
|
+
|
|
84238
|
+
Supported WAC authoring targets:
|
|
84239
|
+
- TypeScript scripts that import from \`windmill-client\`
|
|
84240
|
+
- Python 3 scripts that import from \`wmill\`
|
|
84241
|
+
|
|
84242
|
+
## File Shape
|
|
84243
|
+
|
|
84244
|
+
TypeScript:
|
|
84245
|
+
|
|
84246
|
+
\`\`\`typescript
|
|
84247
|
+
import {
|
|
84248
|
+
task,
|
|
84249
|
+
taskScript,
|
|
84250
|
+
taskFlow,
|
|
84251
|
+
step,
|
|
84252
|
+
sleep,
|
|
84253
|
+
waitForApproval,
|
|
84254
|
+
getResumeUrls,
|
|
84255
|
+
parallel,
|
|
84256
|
+
workflow,
|
|
84257
|
+
} from "windmill-client";
|
|
84258
|
+
|
|
84259
|
+
const process = task(async (x: string): Promise<string> => {
|
|
84260
|
+
return \`processed: \${x}\`;
|
|
84261
|
+
});
|
|
84262
|
+
|
|
84263
|
+
export const main = workflow(async (x: string) => {
|
|
84264
|
+
const result = await process(x);
|
|
84265
|
+
return { result };
|
|
84266
|
+
});
|
|
84267
|
+
\`\`\`
|
|
84268
|
+
|
|
84269
|
+
Python:
|
|
84270
|
+
|
|
84271
|
+
\`\`\`python
|
|
84272
|
+
from wmill import task, task_script, task_flow, step, sleep, wait_for_approval, get_resume_urls, parallel, workflow
|
|
84273
|
+
|
|
84274
|
+
@task()
|
|
84275
|
+
async def process(x: str) -> str:
|
|
84276
|
+
return f"processed: {x}"
|
|
84277
|
+
|
|
84278
|
+
@workflow
|
|
84279
|
+
async def main(x: str):
|
|
84280
|
+
result = await process(x)
|
|
84281
|
+
return {"result": result}
|
|
84282
|
+
\`\`\`
|
|
84283
|
+
|
|
84284
|
+
Rules:
|
|
84285
|
+
- Do not call \`main\`.
|
|
84286
|
+
- TypeScript should export the workflow entrypoint, preferably \`export const main = workflow(async (...) => { ... })\`.
|
|
84287
|
+
- Python must use \`@workflow\` on an async top-level function, usually \`main\`.
|
|
84288
|
+
- Define task functions and \`taskScript\`/\`task_script\` or \`taskFlow\`/\`task_flow\` assignments at module top level with stable names.
|
|
84289
|
+
- Use the exact SDK names. Do not alias \`workflow\`, \`task\`, \`taskScript\`, \`taskFlow\`, \`step\`, \`sleep\`, \`waitForApproval\`, \`task_script\`, \`task_flow\`, or \`wait_for_approval\`; the WAC parser recognizes these names directly.
|
|
84290
|
+
|
|
84291
|
+
## Checkpoint And Replay Model
|
|
84292
|
+
|
|
84293
|
+
The parent workflow may rerun from the top after any suspension, retry, approval, or child task completion. Completed durable steps are replayed from the checkpoint.
|
|
84294
|
+
|
|
84295
|
+
Put every side effect or non-deterministic value behind a durable WAC boundary:
|
|
84296
|
+
- Use \`task()\` / \`@task()\` for substantial work that should run as its own child job.
|
|
84297
|
+
- Use \`taskScript()\` / \`task_script()\` for an existing script or a relative module file.
|
|
84298
|
+
- Use \`taskFlow()\` / \`task_flow()\` for an existing Windmill flow.
|
|
84299
|
+
- Use \`step(name, fn)\` for lightweight inline work whose result must be checkpointed.
|
|
84300
|
+
- Use \`sleep(seconds)\` for server-side sleeps that do not hold a worker.
|
|
84301
|
+
- Use \`waitForApproval()\` / \`wait_for_approval()\` for external approval suspension.
|
|
84302
|
+
|
|
84303
|
+
Never put API calls, database writes, notifications, random values, timestamps, or irreversible changes directly in the top-level workflow body. The workflow body can be rerun. Put those operations in a task or in \`step()\`.
|
|
84304
|
+
|
|
84305
|
+
Branching on task or step results is safe because those results are checkpointed. Branching on current time, random data, environment reads, or external state is unsafe unless the value is first captured with \`step()\`.
|
|
84306
|
+
|
|
84307
|
+
## Tasks
|
|
84308
|
+
|
|
84309
|
+
Use \`task()\` / \`@task()\` for inline functions that become workflow steps:
|
|
84310
|
+
|
|
84311
|
+
\`\`\`typescript
|
|
84312
|
+
const enrich = task(async (customerId: string) => {
|
|
84313
|
+
return await fetchCustomer(customerId);
|
|
84314
|
+
});
|
|
84315
|
+
\`\`\`
|
|
84316
|
+
|
|
84317
|
+
\`\`\`python
|
|
84318
|
+
@task(timeout=600, tag="etl")
|
|
84319
|
+
async def enrich(customer_id: str):
|
|
84320
|
+
return await fetch_customer(customer_id)
|
|
84321
|
+
\`\`\`
|
|
84322
|
+
|
|
84323
|
+
In TypeScript, prefer assigning each task to a named top-level const. In Python, prefer top-level async functions decorated with \`@task()\` or \`@task\`.
|
|
84324
|
+
|
|
84325
|
+
For existing scripts:
|
|
84326
|
+
|
|
84327
|
+
\`\`\`typescript
|
|
84328
|
+
const helper = taskScript("./helper.ts");
|
|
84329
|
+
const existing = taskScript("f/data/extract", { timeout: 600 });
|
|
84330
|
+
const value = await helper({ input: x });
|
|
84331
|
+
\`\`\`
|
|
84332
|
+
|
|
84333
|
+
\`\`\`python
|
|
84334
|
+
helper = task_script("./helper.py")
|
|
84335
|
+
existing = task_script("f/data/extract", timeout=600)
|
|
84336
|
+
value = await helper(input=x)
|
|
84337
|
+
\`\`\`
|
|
84338
|
+
|
|
84339
|
+
For existing flows:
|
|
84340
|
+
|
|
84341
|
+
\`\`\`typescript
|
|
84342
|
+
const pipeline = taskFlow("f/etl/pipeline");
|
|
84343
|
+
const output = await pipeline({ input: data });
|
|
84344
|
+
\`\`\`
|
|
84345
|
+
|
|
84346
|
+
\`\`\`python
|
|
84347
|
+
pipeline = task_flow("f/etl/pipeline")
|
|
84348
|
+
output = await pipeline(input=data)
|
|
84349
|
+
\`\`\`
|
|
84350
|
+
|
|
84351
|
+
## Inline Steps
|
|
84352
|
+
|
|
84353
|
+
Use \`step()\` for lightweight inline values that must not change during replay:
|
|
84354
|
+
|
|
84355
|
+
\`\`\`typescript
|
|
84356
|
+
const urls = await step("get_urls", () => getResumeUrls());
|
|
84357
|
+
const startedAt = await step("started_at", () => new Date().toISOString());
|
|
84358
|
+
\`\`\`
|
|
84359
|
+
|
|
84360
|
+
\`\`\`python
|
|
84361
|
+
urls = await step("get_urls", lambda: get_resume_urls())
|
|
84362
|
+
\`\`\`
|
|
84363
|
+
|
|
84364
|
+
Use stable, descriptive step names. Do not generate step names dynamically.
|
|
84365
|
+
|
|
84366
|
+
## Parallelism
|
|
84367
|
+
|
|
84368
|
+
To run independent work in parallel, start task promises/coroutines before awaiting them together:
|
|
84369
|
+
|
|
84370
|
+
\`\`\`typescript
|
|
84371
|
+
const [a, b] = await Promise.all([process("a"), process("b")]);
|
|
84372
|
+
const many = await parallel(items, process, { concurrency: 5 });
|
|
84373
|
+
\`\`\`
|
|
84374
|
+
|
|
84375
|
+
\`\`\`python
|
|
84376
|
+
import asyncio
|
|
84377
|
+
|
|
84378
|
+
a, b = await asyncio.gather(process("a"), process("b"))
|
|
84379
|
+
many = await parallel(items, process, concurrency=5)
|
|
84380
|
+
\`\`\`
|
|
84381
|
+
|
|
84382
|
+
Only parallelize independent steps. Do not read the result of a task before it is awaited.
|
|
84383
|
+
|
|
84384
|
+
## Approvals
|
|
84385
|
+
|
|
84386
|
+
Generate resume URLs inside \`step()\` before sending them:
|
|
84387
|
+
|
|
84388
|
+
\`\`\`typescript
|
|
84389
|
+
const urls = await step("get_urls", () => getResumeUrls());
|
|
84390
|
+
await step("notify", () => sendApprovalEmail(urls.approvalPage));
|
|
84391
|
+
const approval = await waitForApproval({ timeout: 3600 });
|
|
84392
|
+
\`\`\`
|
|
84393
|
+
|
|
84394
|
+
\`\`\`python
|
|
84395
|
+
urls = await step("get_urls", lambda: get_resume_urls())
|
|
84396
|
+
await step("notify", lambda: send_approval_email(urls["approvalPage"]))
|
|
84397
|
+
approval = await wait_for_approval(timeout=3600)
|
|
84398
|
+
\`\`\`
|
|
84399
|
+
|
|
84400
|
+
\`selfApproval: false\` and \`self_approval=False\` are Enterprise-only approval behavior. Do not use them unless the user asks for that behavior.
|
|
84401
|
+
|
|
84402
|
+
## Error Handling
|
|
84403
|
+
|
|
84404
|
+
Let task errors fail the workflow unless the user asks for recovery logic.
|
|
84405
|
+
|
|
84406
|
+
Python: \`except Exception\` is safe around WAC calls because internal suspension inherits from \`BaseException\`. Avoid bare \`except:\` in workflow code. If the user asks for recovery logic around failed child work, catch \`TaskError\` from \`wmill\` for task failures.
|
|
84407
|
+
|
|
84408
|
+
TypeScript: avoid broad \`try/catch\` around WAC SDK calls. The SDK uses an internal suspension error during initial dispatch; catching it can break workflow suspension. If a broad catch is unavoidable, rethrow internal suspension errors before handling business errors.
|
|
84409
|
+
|
|
84410
|
+
|
|
84411
|
+
## TypeScript Workflow-as-Code API (windmill-client)
|
|
84412
|
+
|
|
84413
|
+
Import: \`import { workflow, task, taskScript, taskFlow, step, sleep, waitForApproval, getResumeUrls, parallel } from "windmill-client"\`
|
|
84414
|
+
|
|
84415
|
+
\`\`\`typescript
|
|
84416
|
+
export interface TaskOptions {
|
|
84417
|
+
timeout?: number;
|
|
84418
|
+
tag?: string;
|
|
84419
|
+
cache_ttl?: number;
|
|
84420
|
+
priority?: number;
|
|
84421
|
+
concurrency_limit?: number;
|
|
84422
|
+
concurrency_key?: string;
|
|
84423
|
+
concurrency_time_window_s?: number;
|
|
84424
|
+
}
|
|
84425
|
+
|
|
84426
|
+
/**
|
|
84427
|
+
* Get URLs needed for resuming a flow after this step
|
|
84428
|
+
* @param approver approver name
|
|
84429
|
+
* @param flowLevel if true, generate resume URLs for the parent flow instead of the specific step.
|
|
84430
|
+
* This allows pre-approvals that can be consumed by any later suspend step in the same flow.
|
|
84431
|
+
* @returns approval page UI URL, resume and cancel API URLs for resuming the flow
|
|
84432
|
+
*/
|
|
84433
|
+
export async function getResumeUrls(approver?: string, flowLevel?: boolean): Promise<{ approvalPage: string; resume: string; cancel: string; }>
|
|
84434
|
+
|
|
84435
|
+
/**
|
|
84436
|
+
* Wrap an async function as a workflow task.
|
|
84437
|
+
*
|
|
84438
|
+
* @example
|
|
84439
|
+
* const extract_data = task(async (url: string) => { ... });
|
|
84440
|
+
* const run_external = task("f/external_script", async (x: number) => { ... });
|
|
84441
|
+
*
|
|
84442
|
+
* Inside a \`workflow()\`, calling a task dispatches it as a step.
|
|
84443
|
+
* Outside a workflow, the function body executes directly.
|
|
84444
|
+
*/
|
|
84445
|
+
export function task<T extends (...args: any[]) => Promise<any>>(fnOrPath: T | string, maybeFnOrOptions?: T | TaskOptions, maybeOptions?: TaskOptions,): T
|
|
84446
|
+
|
|
84447
|
+
/**
|
|
84448
|
+
* Create a task that dispatches to a separate Windmill script.
|
|
84449
|
+
*
|
|
84450
|
+
* @example
|
|
84451
|
+
* const extract = taskScript("f/data/extract");
|
|
84452
|
+
* // inside workflow: await extract({ url: "https://..." })
|
|
84453
|
+
*/
|
|
84454
|
+
export function taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
|
84455
|
+
|
|
84456
|
+
/**
|
|
84457
|
+
* Create a task that dispatches to a separate Windmill flow.
|
|
84458
|
+
*
|
|
84459
|
+
* @example
|
|
84460
|
+
* const pipeline = taskFlow("f/etl/pipeline");
|
|
84461
|
+
* // inside workflow: await pipeline({ input: data })
|
|
84462
|
+
*/
|
|
84463
|
+
export function taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
|
|
84464
|
+
|
|
84465
|
+
/**
|
|
84466
|
+
* Mark an async function as a workflow-as-code entry point.
|
|
84467
|
+
*
|
|
84468
|
+
* The function must be **deterministic**: given the same inputs it must call
|
|
84469
|
+
* tasks in the same order on every replay. Branching on task results is fine
|
|
84470
|
+
* (results are replayed from checkpoint), but branching on external state
|
|
84471
|
+
* (current time, random values, external API calls) must use \`step()\` to
|
|
84472
|
+
* checkpoint the value so replays see the same result.
|
|
84473
|
+
*/
|
|
84474
|
+
export function workflow<T>(fn: (...args: any[]) => Promise<T>)
|
|
84475
|
+
|
|
84476
|
+
export async function step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
|
|
84477
|
+
|
|
84478
|
+
export async function sleep(seconds: number): Promise<void>
|
|
84479
|
+
|
|
84480
|
+
/**
|
|
84481
|
+
* Suspend the workflow and wait for an external approval.
|
|
84482
|
+
*
|
|
84483
|
+
* Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
|
|
84484
|
+
* URLs before calling this function.
|
|
84485
|
+
*
|
|
84486
|
+
* @example
|
|
84487
|
+
* const urls = await step("urls", () => getResumeUrls());
|
|
84488
|
+
* await step("notify", () => sendEmail(urls.approvalPage));
|
|
84489
|
+
* const { value, approver } = await waitForApproval({ timeout: 3600 });
|
|
84490
|
+
*/
|
|
84491
|
+
export function waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
|
|
84492
|
+
|
|
84493
|
+
/**
|
|
84494
|
+
* Process items in parallel with optional concurrency control.
|
|
84495
|
+
*
|
|
84496
|
+
* Each item is processed by calling \`fn(item)\`, which should be a task().
|
|
84497
|
+
* Items are dispatched in batches of \`concurrency\` (default: all at once).
|
|
84498
|
+
*
|
|
84499
|
+
* @example
|
|
84500
|
+
* const process = task(async (item: string) => { ... });
|
|
84501
|
+
* const results = await parallel(items, process, { concurrency: 5 });
|
|
84502
|
+
*/
|
|
84503
|
+
export async function parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
|
|
84504
|
+
\`\`\`
|
|
84505
|
+
|
|
84506
|
+
|
|
84507
|
+
## Python Workflow-as-Code API (wmill)
|
|
84508
|
+
|
|
84509
|
+
Import: \`from wmill import workflow, task, task_script, task_flow, step, sleep, wait_for_approval, get_resume_urls, parallel, TaskError\`
|
|
84510
|
+
|
|
84511
|
+
\`\`\`python
|
|
84512
|
+
# Raised when a WAC task step failed.
|
|
84513
|
+
#
|
|
84514
|
+
# Attributes:
|
|
84515
|
+
# step_key: The checkpoint key of the failed step.
|
|
84516
|
+
# child_job_id: The UUID of the failed child job.
|
|
84517
|
+
# result: The error result from the child job.
|
|
84518
|
+
class TaskError(Exception):
|
|
84519
|
+
def __init__(self, message: str, *, step_key: str = '', child_job_id: str = '', result = None)
|
|
84520
|
+
|
|
84521
|
+
# Get URLs needed for resuming a flow after suspension.
|
|
84522
|
+
#
|
|
84523
|
+
# Args:
|
|
84524
|
+
# approver: Optional approver name
|
|
84525
|
+
# flow_level: If True, generate resume URLs for the parent flow instead of the
|
|
84526
|
+
# specific step. This allows pre-approvals that can be consumed by any later
|
|
84527
|
+
# suspend step in the same flow.
|
|
84528
|
+
#
|
|
84529
|
+
# Returns:
|
|
84530
|
+
# Dictionary with approvalPage, resume, and cancel URLs
|
|
84531
|
+
def get_resume_urls(approver: str = None, flow_level: bool = None) -> dict
|
|
84532
|
+
|
|
84533
|
+
# Decorator that marks a function as a workflow task.
|
|
84534
|
+
#
|
|
84535
|
+
# Works in both WAC v1 (sync, HTTP-based dispatch) and WAC v2
|
|
84536
|
+
# (async, checkpoint/replay) modes:
|
|
84537
|
+
#
|
|
84538
|
+
# - **v2 (inside @workflow)**: dispatches as a checkpoint step.
|
|
84539
|
+
# - **v1 (WM_JOB_ID set, no @workflow)**: dispatches via HTTP API.
|
|
84540
|
+
# - **Standalone**: executes the function body directly.
|
|
84541
|
+
#
|
|
84542
|
+
# Usage::
|
|
84543
|
+
#
|
|
84544
|
+
# @task
|
|
84545
|
+
# async def extract_data(url: str): ...
|
|
84546
|
+
#
|
|
84547
|
+
# @task(path="f/external_script", timeout=600, tag="gpu")
|
|
84548
|
+
# async def run_external(x: int): ...
|
|
84549
|
+
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)
|
|
84550
|
+
|
|
84551
|
+
# Create a task that dispatches to a separate Windmill script.
|
|
84552
|
+
#
|
|
84553
|
+
# Usage::
|
|
84554
|
+
#
|
|
84555
|
+
# extract = task_script("f/data/extract", timeout=600)
|
|
84556
|
+
#
|
|
84557
|
+
# @workflow
|
|
84558
|
+
# async def main():
|
|
84559
|
+
# data = await extract(url="https://...")
|
|
84560
|
+
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)
|
|
84561
|
+
|
|
84562
|
+
# Create a task that dispatches to a separate Windmill flow.
|
|
84563
|
+
#
|
|
84564
|
+
# Usage::
|
|
84565
|
+
#
|
|
84566
|
+
# pipeline = task_flow("f/etl/pipeline", priority=10)
|
|
84567
|
+
#
|
|
84568
|
+
# @workflow
|
|
84569
|
+
# async def main():
|
|
84570
|
+
# result = await pipeline(input=data)
|
|
84571
|
+
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)
|
|
84572
|
+
|
|
84573
|
+
# Decorator marking an async function as a workflow-as-code entry point.
|
|
84574
|
+
#
|
|
84575
|
+
# The function must be **deterministic**: given the same inputs it must call
|
|
84576
|
+
# tasks in the same order on every replay. Branching on task results is fine
|
|
84577
|
+
# (results are replayed from checkpoint), but branching on external state
|
|
84578
|
+
# (current time, random values, external API calls) must use \`\`step()\`\` to
|
|
84579
|
+
# checkpoint the value so replays see the same result.
|
|
84580
|
+
def workflow(func)
|
|
84581
|
+
|
|
84582
|
+
# Execute \`\`fn\`\` inline and checkpoint the result.
|
|
84583
|
+
#
|
|
84584
|
+
# On replay the cached value is returned without re-executing \`\`fn\`\`.
|
|
84585
|
+
# Use for lightweight deterministic operations (timestamps, random IDs,
|
|
84586
|
+
# config reads) that should not incur the overhead of a child job.
|
|
84587
|
+
async def step(name: str, fn)
|
|
84588
|
+
|
|
84589
|
+
# Server-side sleep — suspend the workflow for the given duration without holding a worker.
|
|
84590
|
+
#
|
|
84591
|
+
# Inside a @workflow, the parent job suspends and auto-resumes after \`\`seconds\`\`.
|
|
84592
|
+
# Outside a workflow, falls back to \`\`asyncio.sleep\`\`.
|
|
84593
|
+
async def sleep(seconds: int)
|
|
84594
|
+
|
|
84595
|
+
# Suspend the workflow and wait for an external approval.
|
|
84596
|
+
#
|
|
84597
|
+
# Use \`\`get_resume_urls()\`\` (wrapped in \`\`step()\`\`) to obtain
|
|
84598
|
+
# resume/cancel/approval URLs before calling this function.
|
|
84599
|
+
#
|
|
84600
|
+
# Returns a dict with \`\`value\`\` (form data), \`\`approver\`\`, and \`\`approved\`\`.
|
|
84601
|
+
#
|
|
84602
|
+
# Args:
|
|
84603
|
+
# timeout: Approval timeout in seconds (default 1800).
|
|
84604
|
+
# form: Optional form schema for the approval page.
|
|
84605
|
+
# self_approval: Whether the user who triggered the flow can approve it (default True).
|
|
84606
|
+
#
|
|
84607
|
+
# Example::
|
|
84608
|
+
#
|
|
84609
|
+
# urls = await step("urls", lambda: get_resume_urls())
|
|
84610
|
+
# await step("notify", lambda: send_email(urls["approvalPage"]))
|
|
84611
|
+
# result = await wait_for_approval(timeout=3600)
|
|
84612
|
+
async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True) -> dict
|
|
84613
|
+
|
|
84614
|
+
# Process items in parallel with optional concurrency control.
|
|
84615
|
+
#
|
|
84616
|
+
# Each item is processed by calling \`\`fn(item)\`\`, which should be a @task.
|
|
84617
|
+
# Items are dispatched in batches of \`\`concurrency\`\` (default: all at once).
|
|
84618
|
+
#
|
|
84619
|
+
# Example::
|
|
84620
|
+
#
|
|
84621
|
+
# @task
|
|
84622
|
+
# async def process(item: str):
|
|
84623
|
+
# ...
|
|
84624
|
+
#
|
|
84625
|
+
# results = await parallel(items, process, concurrency=5)
|
|
84626
|
+
async def parallel(items, fn, *, concurrency: Optional[int] = None)
|
|
84627
|
+
\`\`\`
|
|
84176
84628
|
`,
|
|
84177
84629
|
"cli-commands": `---
|
|
84178
84630
|
name: cli-commands
|
|
@@ -87882,7 +88334,7 @@ var config_default = command35;
|
|
|
87882
88334
|
|
|
87883
88335
|
// src/main.ts
|
|
87884
88336
|
await init_context();
|
|
87885
|
-
var VERSION = "1.693.
|
|
88337
|
+
var VERSION = "1.693.3";
|
|
87886
88338
|
async function checkVersionSafe(cmd) {
|
|
87887
88339
|
const mainCommand = cmd.getMainCommand();
|
|
87888
88340
|
const upgradeCommand = mainCommand.getCommand("upgrade");
|